X-Git-Url: https://ocean-lang.org/code/?a=blobdiff_plain;f=csrc%2Foceani.mdc;h=0334af198c9656e7f261beb6e773c838aeda2a8a;hb=b880d8942e1539875d8209e18bf3d21011220ff8;hp=fabfe188c07ebd5bc9abdca9dd492aad34041de2;hpb=6a7ef05f3986dd8127b8c3bfaeeceb514a8beaa4;p=ocean diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index fabfe18..0334af1 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -261,9 +261,10 @@ structures can be used. free(s); s = t; } - if (!context.parse_error) { - ## free global vars - } + // FIXME parser should pop scope even on error + while (context.scope_depth > 0) + scope_pop(&context); + ## free global vars ## free context types ## free context storage exit(context.parse_error ? 1 : 0); @@ -691,7 +692,7 @@ A separate function encoding these cases will simplify some code later. } } - static void _dup_value(struct type *type, + static void _dup_value(struct type *type, struct value *vold, struct value *vnew) { switch (type->vtype) { @@ -1031,7 +1032,7 @@ list of in_scope names. The storage of the value of a variable will be described later. For now we just need to know that when a variable goes out of scope, it might -need to be freed. For this we need to be able to find it, so assume that +need to be freed. For this we need to be able to find it, so assume that `var_value()` will provide that. ###### variable fields @@ -1575,7 +1576,7 @@ propagation is needed. ###### ast - enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 2<<1}; + enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2}; ###### format cases case 'r': @@ -1875,9 +1876,10 @@ with a const size by whether they are prepared at parse time or not. t->array.vsize = NULL; if (number_parse(num, tail, $2.txt) == 0) tok_err(c, "error: unrecognised number", &$2); - else if (tail[0]) + else if (tail[0]) { tok_err(c, "error: unsupported number suffix", &$2); - else { + mpq_clear(num); + } else { t->array.size = mpz_get_ui(mpq_numref(num)); if (mpz_cmp_ui(mpq_denref(num), 1) != 0) { tok_err(c, "error: array size must be an integer", @@ -2061,7 +2063,7 @@ function will be needed. struct value *v; v = (void*) val->ptr + type->structure.fields[i].offset; if (type->structure.fields[i].init) - dup_value(type->structure.fields[i].type, + dup_value(type->structure.fields[i].type, type->structure.fields[i].init, v); else @@ -2335,10 +2337,9 @@ function will be needed. #### Functions A function is a chunk of code which can be passed parameters and can -return results (though results are not yet implemented). Each function -has a type which includes the set of parameters and the return value. -As yet these types cannot be declared separately from the function -itself. +return results. Each function has a type which includes the set of +parameters and the return value. As yet these types cannot be declared +separately from the function itself. The parameters can be specified either in parentheses as a ';' separated list, such as @@ -2359,6 +2360,22 @@ be a ';' separated list) do code block +In the first case a return type can follow the paentheses after a colon, +in the second it is given on a line starting with the word `return`. + +##### Example: functions that return + + func add(a:number; b:number): number + code block + + func catenate + a: string + b: string + return string + do + code block + + For constructing these lists we use a `List` binode, which will be further detailed when Expression Lists are introduced. @@ -2366,6 +2383,7 @@ further detailed when Expression Lists are introduced. struct { struct binode *params; + struct type *return_type; int local_size; } function; @@ -2433,7 +2451,12 @@ further detailed when Expression Lists are introduced. if (b->right) fprintf(f, "; "); } - fprintf(f, ")\n"); + fprintf(f, ")"); + if (type->function.return_type != Tnone) { + fprintf(f, ":"); + type_print(type->function.return_type, f); + } + fprintf(f, "\n"); } static void function_free_type(struct type *t) @@ -2480,7 +2503,6 @@ further detailed when Expression Lists are introduced. } } }$ - $*binode Args -> ArgsLine NEWLINE ${ $0 = $right); struct var *v = cast(var, b->left); @@ -3541,7 +3563,7 @@ arguments, form with the 'List' nodes. return NULL; } v->var->type->check_args(c, ok, v->var->type, args); - return Tnone; + return v->var->type->function.return_type; } ###### interp binode cases @@ -3569,7 +3591,7 @@ arguments, form with the 'List' nodes. arg = cast(binode, arg->right); } c->local = local; c->local_size = t->function.local_size; - right = interp_exec(c, fbody->function, &rtype); + rv = interp_exec(c, fbody->function, &rvtype); c->local = oldlocal; c->local_size = old_size; free(local); break; @@ -3746,9 +3768,14 @@ is in-place. for (e = b; e; e = cast(binode, e->right)) { t = propagate_types(e->left, c, ok, NULL, rules); - if ((rules & Rboolok) && t == Tbool) + if ((rules & Rboolok) && (t == Tbool || t == Tnone)) t = NULL; - if (t && t != Tnone && t != Tbool) { + if (t == Tnone && e->right) + /* Only the final statement *must* return a value + * when not Rboolok + */ + t = NULL; + if (t) { if (!type) type = t; else if (t != type) @@ -3890,6 +3917,7 @@ it is declared, and error will be raised as the name is created as type_err(c, "Variable declared with no type or value: %v", $1, NULL, 0, NULL); + free_var($1); } else { $0 = new(binode); $0->op = Declare; @@ -3999,16 +4027,16 @@ it is declared, and error will be raised as the name is created as ### The `use` statement -The `use` statement is the last "simple" statement. It is needed when -the condition in a conditional statement is a block. `use` works much -like `return` in C, but only completes the `condition`, not the whole -function. +The `use` statement is the last "simple" statement. It is needed when a +statement block can return a value. This includes the body of a +function which has a return type, and the "condition" code blocks in +`if`, `while`, and `switch` statements. ###### Binode types Use, ###### expr precedence - $TERM use + $TERM use ###### SimpleStatement Grammar | use Expression ${ @@ -4650,11 +4678,12 @@ searching through for the Nth constant for decreasing N. v->where_set = var; var->var = v; v->constant = 1; + v->global = 1; } else { - v = var_ref(c, $1.txt); + struct variable *vorig = var_ref(c, $1.txt); tok_err(c, "error: name already declared", &$1); type_err(c, "info: this is where '%v' was first declared", - v->where_decl, NULL, 0, NULL); + vorig->where_decl, NULL, 0, NULL); } do { ok = 1; @@ -4708,18 +4737,17 @@ The code in an Ocean program is all stored in function declarations. One of the functions must be named `main` and it must accept an array of strings as a parameter - the command line arguments. - -As this is the top level, several things are handled a bit -differently. -The function is not interpreted by `interp_exec` as that isn't -passed the argument list which the program requires. Similarly type -analysis is a bit more interesting at this level. +As this is the top level, several things are handled a bit differently. +The function is not interpreted by `interp_exec` as that isn't passed +the argument list which the program requires. Similarly type analysis +is a bit more interesting at this level. ###### ast functions static struct variable *declare_function(struct parse_context *c, struct variable *name, struct binode *args, + struct type *ret, struct exec *code) { struct text funcname = {" func", 5}; @@ -4727,24 +4755,41 @@ analysis is a bit more interesting at this level. struct value fn = {.function = code}; name->type = add_type(c, funcname, &function_prototype); name->type->function.params = reorder_bilist(args); + name->type->function.return_type = ret; global_alloc(c, name->type, name, &fn); var_block_close(c, CloseSequential, code); - } else + } else { + free_binode(args); + free_type(ret); + free_exec(code); var_block_close(c, CloseSequential, NULL); + } return name; } +###### declare terminals + $TERM return + ###### top level grammar $*variable DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${ - $0 = declare_function(c, $function, c, &ok, Tnone, 0); + propagate_types(val->function, c, &ok, + v->type->function.return_type, 0); } while (ok == 2); if (ok) /* Make sure everything is still consistent */ - propagate_types(val->function, c, &ok, Tnone, 0); + propagate_types(val->function, c, &ok, + v->type->function.return_type, 0); if (!ok) all_ok = 0; v->type->function.local_size = scope_finalize(c); @@ -4877,7 +4924,6 @@ analysis is a bit more interesting at this level. array_init(v->var->type, vl); for (i = 0; i < argc; i++) { struct value *vl2 = vl->array + i * v->var->type->array.member->size; - arg.str.txt = argv[i]; arg.str.len = strlen(argv[i]);