]> ocean-lang.org Git - ocean/commitdiff
oceani - delay processing of global constants
authorNeilBrown <neil@brown.name>
Thu, 2 Dec 2021 02:43:27 +0000 (13:43 +1100)
committerNeilBrown <neil@brown.name>
Fri, 3 Dec 2021 08:14:40 +0000 (19:14 +1100)
Rather than setting up the value of a constant as it is parsed, collect
the declarations and process them all at the end.

This is a step towards allowing constants to refer to constants that are
declared later.

Signed-off-by: NeilBrown <neil@brown.name>
csrc/oceani-tests.mdc
csrc/oceani.mdc

index 58fde75620d45c479b8840abea87fc5db643eca7..d65b6f97d8593548f13648e3216f09f80a34a44b 100644 (file)
@@ -939,7 +939,6 @@ various places that `type_err()` are called.
                print bar, foo
 
 ###### output: type_err_const
-       .tmp.code:4:16: error: expected number found string
        .tmp.code:6:8: error: name already declared: bar
        .tmp.code:4:8: info: this is where 'bar' was first declared
        .tmp.code:8:8: error: variable 'foo' redeclared
@@ -948,6 +947,7 @@ various places that `type_err()` are called.
        .tmp.code:7:5: info: this is where 'main' was first declared
        .tmp.code:13:8: error: variable 'foo' redeclared
        .tmp.code:3:8: info: this is where 'foo' was first declared
+       .tmp.code:4:16: error: expected number found string
 
 ###### test: type_err_const1
        const
index 34c17b234efaefda84540c2560a045b1b6a5309a..5bf754e8fe52ced6af10691f0519f2c47f2c18fc 100644 (file)
@@ -242,6 +242,7 @@ structures can be used.
 
                parse_oceani(ss->code, &context.config, dotrace ? stderr : NULL);
 
+               resolve_consts(&context);
                prepare_types(&context);
                if (!context.parse_error && !analyse_funcs(&context)) {
                        fprintf(stderr, "oceani: type error in program - not running.\n");
@@ -266,6 +267,7 @@ structures can be used.
                while (context.scope_depth > 0)
                        scope_pop(&context);
                ## free global vars
+               ## free const decls
                ## free context types
                ## free context storage
                exit(context.parse_error ? 1 : 0);
@@ -1588,10 +1590,10 @@ need to be freed.  For this we need to be able to find it, so assume that
                while (v) {
                        struct variable *next = v->previous;
 
-                       if (v->global) {
+                       if (v->global && v->frame_pos >= 0) {
                                free_value(v->type, var_value(&context, v));
-                               if (v->depth == 0)
-                                       // This is a global constant
+                               if (v->depth == 0 && v->type->free == function_free)
+                                       // This is a function constant
                                        free_exec(v->where_decl);
                        }
                        free(v);
@@ -4857,13 +4859,15 @@ various declarations in the parse context.
 
 ### The `const` section
 
-As well as being defined in with the code that uses them, constants
-can be declared at the top level.  These have full-file scope, so they
-are always `InScope`.  The value of a top level constant can be given
-as an expression, and this is evaluated immediately rather than in the
-later interpretation stage.  Once we add functions to the language, we
-will need rules concern which, if any, can be used to define a top
-level constant.
+As well as being defined in with the code that uses them, constants can
+be declared at the top level.  These have full-file scope, so they are
+always `InScope`, even before(!) they have been declared.  The value of
+a top level constant can be given as an expression, and this is
+evaluated after parsing and before execution.
+
+A function call can be used to evaluate a constant, but it will not have
+access to any program state, once such statement becomes meaningful.
+e.g.  arguments and filesystem will not be visible.
 
 Constants are defined in a section that starts with the reserved word
 `const` and then has a block with a list of assignment statements.
@@ -4872,11 +4876,8 @@ make it clear that they are constants.  Type can also be given: if
 not, the type will be determined during analysis, as with other
 constants.
 
-As the types constants are inserted at the head of a list, printing
-them in the same order that they were read is not straight forward.
-We take a quadratic approach here and count the number of constants
-(variables of depth 0), then count down from there, each time
-searching through for the Nth constant for decreasing N.
+###### parse context
+       struct binode *constlist;
 
 ###### top level grammar
 
@@ -4903,69 +4904,88 @@ searching through for the Nth constant for decreasing N.
 
        $void
        Const -> IDENTIFIER :: CType = Expression ${ {
-               int ok;
                struct variable *v;
+               struct binode *bl, *bv;
+               struct var *var = new_pos(var, $ID);
 
-               v = var_decl(c, $1.txt);
+               v = var_decl(c, $ID.txt);
                if (v) {
-                       struct var *var = new_pos(var, $1);
                        v->where_decl = var;
                        v->where_set = var;
-                       var->var = v;
+                       v->type = $<CT;
                        v->constant = 1;
                        v->global = 1;
                } else {
-                       struct variable *vorig = var_ref(c, $1.txt);
+                       v = var_ref(c, $1.txt);
                        tok_err(c, "error: name already declared", &$1);
                        type_err(c, "info: this is where '%v' was first declared",
-                                vorig->where_decl, NULL, 0, NULL);
-               }
-               do {
-                       ok = 1;
-                       propagate_types($5, c, &ok, $3, 0);
-               } while (ok == 2);
-               if (!ok)
-                       c->parse_error = 1;
-               else if (v) {
-                       struct value res = interp_exec(c, $5, &v->type);
-                       global_alloc(c, v->type, v, &res);
+                                v->where_decl, NULL, 0, NULL);
                }
+               var->var = v;
+
+               bv = new(binode);
+               bv->op = Declare;
+               bv->left = var;
+               bv->right= $<Exp;
+
+               bl = new(binode);
+               bl->op = List;
+               bl->left = c->constlist;
+               bl->right = bv;
+               c->constlist = bl;
        } }$
 
-###### print const decls
+###### core functions
+       static void resolve_consts(struct parse_context *c)
        {
-               struct variable *v;
-               int target = -1;
-
-               while (target != 0) {
-                       int i = 0;
-                       for (v = context.in_scope; v; v=v->in_scope)
-                               if (v->depth == 0 && v->constant) {
-                                       i += 1;
-                                       if (i == target)
-                                               break;
-                               }
-
-                       if (target == -1) {
-                               if (i)
-                                       printf("const\n");
-                               target = i;
-                       } else {
-                               struct value *val = var_value(&context, v);
-                               printf("    %.*s :: ", v->name->name.len, v->name->name.txt);
-                               type_print(v->type, stdout);
-                               printf(" = ");
-                               if (v->type == Tstr)
-                                       printf("\"");
-                               print_value(v->type, val, stdout);
-                               if (v->type == Tstr)
-                                       printf("\"");
-                               printf("\n");
-                               target -= 1;
+               struct binode *b;
+               c->constlist = reorder_bilist(c->constlist);
+               for (b = cast(binode, c->constlist); b;
+                    b = cast(binode, b->right)) {
+                       int ok;
+                       struct binode *vb = cast(binode, b->left);
+                       struct var *v = cast(var, vb->left);
+                       do {
+                               ok = 1;
+                               propagate_types(vb->right, c, &ok,
+                                               v->var->type, 0);
+                       } while (ok == 2);
+                       if (!ok)
+                               c->parse_error = 1;
+                       else {
+                               struct value res = interp_exec(
+                                       c, vb->right, &v->var->type);
+                               global_alloc(c, v->var->type, v->var, &res);
                        }
                }
        }
 
+###### print const decls
+       {
+               struct binode *b;
+               int first = 1;
+
+               for (b = cast(binode, context.constlist); b;
+                    b = cast(binode, b->right)) {
+                       struct binode *vb = cast(binode, b->left);
+                       struct var *vr = cast(var, vb->left);
+                       struct variable *v = vr->var;
+
+                       if (first)
+                               printf("const\n");
+                       first = 0;
+
+                       printf("    %.*s :: ", v->name->name.len, v->name->name.txt);
+                       type_print(v->type, stdout);
+                       printf(" = ");
+                       print_exec(vb->right, -1, 0);
+                       printf("\n");
+               }
+       }
+
+###### free const decls
+       free_binode(context.constlist);
+
 ### Function declarations
 
 The code in an Ocean program is all stored in function declarations.