From: NeilBrown Date: Thu, 2 Dec 2021 02:43:27 +0000 (+1100) Subject: oceani - delay processing of global constants X-Git-Url: https://ocean-lang.org/code/?p=ocean;a=commitdiff_plain;h=923ca343c74104bfa366b6d3adc09b14e11cadfa oceani - delay processing of global constants 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 --- diff --git a/csrc/oceani-tests.mdc b/csrc/oceani-tests.mdc index 58fde75..d65b6f9 100644 --- a/csrc/oceani-tests.mdc +++ b/csrc/oceani-tests.mdc @@ -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 diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 34c17b2..5bf754e 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -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 = $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= $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.