X-Git-Url: https://ocean-lang.org/code/?p=ocean;a=blobdiff_plain;f=csrc%2Foceani.mdc;h=a62534814a880fd01aa9c78cdfce316edbb81a37;hp=dca205570c9af2c1ae704e0a58c04f01bdd96782;hb=69ba500597a59e484af0fa351bdd4d0b5fe53df4;hpb=63e4b945b7fcf3c2ccbf7fee64bc08ae9f0aecf0 diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index dca2055..a625348 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -367,14 +367,14 @@ context so indicate that parsing failed. static void fput_loc(struct exec *loc, FILE *f); static void type_err(struct parse_context *c, char *fmt, struct exec *loc, - struct type *t1, int rules, struct type *t2); + struct type *t1, enum val_rules rules, struct type *t2); static void tok_err(struct parse_context *c, char *fmt, struct token *t); ###### core functions static void type_err(struct parse_context *c, char *fmt, struct exec *loc, - struct type *t1, int rules, struct type *t2) + struct type *t1, enum val_rules rules, struct type *t2) { fprintf(stderr, "%s:", c->file_name); fput_loc(loc, stderr); @@ -592,21 +592,24 @@ passed by reference. It has `Efail` set when an error is found, and any expression cannot be evaluated a compile time, `Eruntime` is set. If the expression can be copied, `Emaycopy` is set. -If it remains unchanged at `0`, then no more propagation is needed. +If `Erval` is set, then the value cannot be assigned to because it is +a temporary result. If `Erval` is clear but `Econst` is set, then +the value can only be assigned once, when the variable is declared. ###### ast - enum val_rules {Rboolok = 1<<1, Rnoconstant = 1<<2}; + enum val_rules {Rboolok = 1<<0,}; enum prop_err {Efail = 1<<0, Eretry = 1<<1, Eruntime = 1<<2, - Emaycopy = 1<<3}; + Emaycopy = 1<<3, Erval = 1<<4, Econst = 1<<5}; ###### forward decls static struct type *propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr, - struct type *type, int rules); + struct type *type, enum val_rules rules); ###### core functions static struct type *__propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr, - struct type *type, int rules) + enum prop_err *perr_local, + struct type *type, enum val_rules rules) { struct type *t; @@ -628,11 +631,13 @@ If it remains unchanged at `0`, then no more propagation is needed. } static struct type *propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr, - struct type *type, int rules) + struct type *type, enum val_rules rules) { int pre_err = c->parse_error; - struct type *ret = __propagate_types(prog, c, perr, type, rules); + enum prop_err perr_local = 0; + struct type *ret = __propagate_types(prog, c, perr, &perr_local, type, rules); + *perr |= perr_local & (Efail | Eretry); if (c->parse_error > pre_err) *perr |= Efail; return ret; @@ -986,7 +991,7 @@ which might be reported in error messages. ###### forward decls static void free_value(struct type *type, struct value *v); - static int type_compat(struct type *require, struct type *have, int rules); + static int type_compat(struct type *require, struct type *have, enum val_rules rules); static void type_print(struct type *type, FILE *f); static void val_init(struct type *type, struct value *v); static void dup_value(struct type *type, @@ -1051,11 +1056,12 @@ A separate function encoding these cases will simplify some code later. ###### type functions - int (*compat)(struct type *this, struct type *other); + int (*compat)(struct type *this, struct type *other, enum val_rules rules); ###### ast functions - static int type_compat(struct type *require, struct type *have, int rules) + static int type_compat(struct type *require, struct type *have, + enum val_rules rules) { if ((rules & Rboolok) && have == Tbool) return 1; // NOTEST @@ -1063,7 +1069,7 @@ A separate function encoding these cases will simplify some code later. return 1; if (require->compat) - return require->compat(require, have); + return require->compat(require, have, rules); return require == have; } @@ -1313,6 +1319,7 @@ executable. if (!type_compat(type, val->vtype, rules)) type_err(c, "error: expected %1 found %2", prog, type, rules, val->vtype); + *perr |= Erval; return val->vtype; } @@ -1435,6 +1442,7 @@ match "case". if (!type_compat(type, Tlabel, rules)) type_err(c, "error: expected %1 found %2", prog, type, rules, Tlabel); + *perr |= Erval; return Tlabel; } ###### interp exec cases @@ -2266,13 +2274,6 @@ correctly. return Tnone; // NOTEST } v = v->merged; - if (v->constant && (rules & Rnoconstant)) { - type_err(c, "error: Cannot assign to a constant: %v", - prog, NULL, 0, NULL); - type_err(c, "info: name was defined as a constant here", - v->where_decl, NULL, 0, NULL); - return v->type; - } if (v->type == Tnone && v->where_decl == prog) type_err(c, "error: variable used but not declared: %v", prog, NULL, 0, NULL); @@ -2290,6 +2291,8 @@ correctly. } if (!v->global || v->frame_pos < 0) *perr |= Eruntime; + if (v->constant) + *perr |= Econst; if (!type) return v->type; return type; @@ -2459,7 +2462,8 @@ with a const size by whether they are prepared at parse time or not. free(ptr); } - static int array_compat(struct type *require, struct type *have) + static int array_compat(struct type *require, struct type *have, + enum val_rules rules) { if (have->compat != require->compat) return 0; @@ -2599,8 +2603,8 @@ with a const size by whether they are prepared at parse time or not. /* left must be an array, right must be a number, * result is the member type of the array */ - propagate_types(b->right, c, perr, Tnum, 0); - t = propagate_types(b->left, c, perr, NULL, rules & Rnoconstant); + propagate_types(b->right, c, perr_local, Tnum, 0); + t = propagate_types(b->left, c, perr, NULL, 0); if (!t || t->compat != array_compat) { type_err(c, "error: %1 cannot be indexed", prog, t, 0, NULL); return NULL; @@ -3116,7 +3120,8 @@ anything in the heap or on the stack. A reference can be assigned /* Nothing to do here */ } - static int reference_compat(struct type *require, struct type *have) + static int reference_compat(struct type *require, struct type *have, + enum val_rules rules) { if (have->compat != require->compat) return 0; @@ -3257,6 +3262,7 @@ anything in the heap or on the stack. A reference can be assigned r->reftype = type; *perr |= Eretry; } + *perr |= Erval; return type; case RefNil: if (type && type->free != reference_free) @@ -3266,9 +3272,10 @@ anything in the heap or on the stack. A reference can be assigned r->reftype = type; *perr |= Eretry; } + *perr |= Erval; return type; case RefFree: - t = propagate_types(r->right, c, perr, NULL, 0); + t = propagate_types(r->right, c, perr_local, NULL, 0); if (t && t->free != reference_free) type_err(c, "error: @free can only be assigned a reference, not %1", prog, t, 0, NULL); @@ -3335,6 +3342,7 @@ anything in the heap or on the stack. A reference can be assigned /* left must be a reference, and we return what it refers to */ /* FIXME how can I pass the expected type down? */ t = propagate_types(b->left, c, perr, NULL, 0); + *perr &= ~Erval; if (!t || t->free != reference_free) type_err(c, "error: Cannot dereference %1", b, t, 0, NULL); else @@ -3440,7 +3448,8 @@ further detailed when Expression Lists are introduced. val->function = NULL; } - static int function_compat(struct type *require, struct type *have) + static int function_compat(struct type *require, struct type *have, + enum val_rules rules) { // FIXME can I do anything here yet? return 0; @@ -3666,9 +3675,10 @@ it in the "SimpleStatement Grammar" which will be described later. return NULL; } *perr |= Eruntime; - v->var->type->check_args(c, perr, v->var->type, args); + v->var->type->check_args(c, perr_local, v->var->type, args); if (v->var->type->function.inline_result) *perr |= Emaycopy; + *perr |= Erval; return v->var->type->function.return_type; } @@ -3781,7 +3791,7 @@ there. struct binode *b2 = cast(binode, b->right); struct type *t2; - propagate_types(b->left, c, perr, Tbool, 0); + propagate_types(b->left, c, perr_local, Tbool, 0); t = propagate_types(b2->left, c, perr, type, 0); t2 = propagate_types(b2->right, c, perr, type ?: t, 0); return t ?: t2; @@ -3955,6 +3965,7 @@ evaluate the second expression if not necessary. if (type && type != Tbool) type_err(c, "error: %1 operation found where %2 expected", prog, Tbool, 0, type); + *perr |= Erval; return Tbool; ###### interp binode cases @@ -4076,6 +4087,7 @@ expression operator, and the `CMPop` non-terminal will match one of them. if (!type_compat(type, Tbool, 0)) type_err(c, "error: Comparison returns %1 but %2 expected", prog, Tbool, rules, type); + *perr |= Erval; return Tbool; ###### interp binode cases @@ -4253,6 +4265,7 @@ parentheses around an expression converts it into a Term, if (!type_compat(type, Tnum, 0)) type_err(c, "error: Arithmetic returns %1 but %2 expected", prog, Tnum, rules, type); + *perr |= Erval; return Tnum; case Concat: @@ -4262,6 +4275,7 @@ parentheses around an expression converts it into a Term, if (!type_compat(type, Tstr, 0)) type_err(c, "error: Concat returns %1 but %2 expected", prog, Tstr, rules, type); + *perr |= Erval; return Tstr; case StringConv: @@ -4271,6 +4285,7 @@ parentheses around an expression converts it into a Term, type_err(c, // UNTESTED "error: Can only convert string to number, not %1", prog, type, 0, NULL); + *perr |= Erval; return Tnum; case Test: @@ -4279,6 +4294,7 @@ parentheses around an expression converts it into a Term, if (!t || !t->test) type_err(c, "error: '?' requires a testable value, not %1", prog, t, 0, NULL); + *perr |= Erval; return Tbool; case Choose: @@ -4290,10 +4306,11 @@ parentheses around an expression converts it into a Term, if (t && t->test == NULL) type_err(c, "error: \"??\" requires a testable value, not %1", prog, t, 0, NULL); + *perr |= Erval; return t; case Bracket: - return propagate_types(b->right, c, perr, type, 0); + return propagate_types(b->right, c, perr, type, rules); ###### interp binode cases @@ -4663,7 +4680,7 @@ printed. else b = cast(binode, b->right); while (b) { - propagate_types(b->left, c, perr, NULL, 0); + propagate_types(b->left, c, perr_local, NULL, 0); b = cast(binode, b->right); } break; @@ -4780,23 +4797,35 @@ be declared at any time. * For Assign, left must not be constant. * result is Tnone */ - t = propagate_types(b->left, c, perr, NULL, - (b->op == Assign ? Rnoconstant : 0)); + *perr &= ~(Erval | Econst); + t = propagate_types(b->left, c, perr, NULL, 0); if (!b->right) return Tnone; if (t) { - if (propagate_types(b->right, c, perr, t, 0) != t) + if (propagate_types(b->right, c, perr_local, t, 0) != t) if (b->left->type == Xvar) type_err(c, "info: variable '%v' was set as %1 here.", cast(var, b->left)->var->where_set, t, rules, NULL); } else { - t = propagate_types(b->right, c, perr, NULL, 0); + t = propagate_types(b->right, c, perr_local, NULL, 0); if (t) - propagate_types(b->left, c, perr, t, - (b->op == Assign ? Rnoconstant : 0)); + propagate_types(b->left, c, perr, t, 0); + } + if (*perr & Erval) + type_err(c, "error: cannot assign to an rval", b, + NULL, 0, NULL); + else if (b->op == Assign && (*perr & Econst)) { + type_err(c, "error: Cannot assign to a constant: %v", + b->left, NULL, 0, NULL); + if (b->left->type == Xvar) { + struct var *var = cast(var, b->left); + struct variable *v = var->var; + type_err(c, "info: name was defined as a constant here", + v->where_decl, NULL, 0, NULL); + } } - if (t && t->dup == NULL && !(*perr & Emaycopy)) + if (t && t->dup == NULL && !(*perr_local & Emaycopy)) type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL); return Tnone; @@ -5246,7 +5275,7 @@ casepart` to track a list of case parts. ###### propagate binode cases case Loop: - t = propagate_types(b->right, c, perr, Tnone, 0); + t = propagate_types(b->right, c, perr_local, Tnone, 0); if (!type_compat(Tnone, t, 0)) *perr |= Efail; // UNTESTED return propagate_types(b->left, c, perr, type, rules); @@ -5632,8 +5661,8 @@ is a bit more interesting at this level. struct value fn = {.function = code}; struct type *t; var_block_close(c, CloseFunction, code); - t = add_anon_type(c, &function_prototype, - "func %.*s", name->name->name.len, + t = add_anon_type(c, &function_prototype, + "func %.*s", name->name->name.len, name->name->name.txt); name->type = t; t->function.params = reorder_bilist(args); @@ -5745,7 +5774,7 @@ is a bit more interesting at this level. all_ok = 0; if (!v->type->function.inline_result && !v->type->function.return_type->dup) { - type_err(c, "error: function cannot return value of type %1", + type_err(c, "error: function cannot return value of type %1", v->where_decl, v->type->function.return_type, 0, NULL); }