X-Git-Url: https://ocean-lang.org/code/?p=ocean;a=blobdiff_plain;f=csrc%2Foceani.mdc;h=a4110da2a970c1b60a6ad2e0f3be4f6243a2c1e0;hp=a421167632746e9525716f96e3729983ff8022a4;hb=2c2269f21afd52650025b7255c000d33929ed635;hpb=0897423423ea2704abdfd35dc58065d12d9f7386 diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index a421167..a4110da 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -1426,9 +1426,10 @@ stack. static void scope_finalize(struct parse_context *c, struct type *ft) { - int size = 0; + int size = ft->function.local_size; struct variable *next = ft->function.scope; struct variable *done = NULL; + while (next) { struct variable *v = next; struct type *t = v->type; @@ -1438,12 +1439,14 @@ stack. continue; if (!t) continue; + if (v->frame_pos >= 0) + continue; while (done && done->scope_end < v->scope_start) done = done->in_scope; if (done) pos = done->frame_pos + done->type->size; else - pos = 0; + pos = ft->function.local_size; if (pos & (t->align - 1)) pos = (pos + t->align) & ~(t->align-1); v->frame_pos = pos; @@ -1742,7 +1745,7 @@ in `rval`. { struct lrval ret = _interp_exec(c, e, dest, dtype); if (!ret.type) - return; // NOTEST + return; if (need_free) free_value(dtype, dest); if (ret.lval) @@ -2405,7 +2408,7 @@ function will be needed. while (target != 0) { int i = 0; for (t = context.typelist; t ; t=t->next) - if (t->print_type_decl && !t->check_args) { + if (t->print_type_decl && !t->check_args && t->name.txt[0] != ' ') { i += 1; if (i == target) break; @@ -2446,7 +2449,7 @@ be a ';' separated list) do code block -In the first case a return type can follow the paentheses after a colon, +In the first case a return type can follow the parentheses after a colon, in the second it is given on a line starting with the word `return`. ##### Example: functions that return @@ -2461,8 +2464,28 @@ in the second it is given on a line starting with the word `return`. do code block +Rather than returning a type, the function can specify a set of local +variables to return as a struct. The values of these variables when the +function exits will be provided to the caller. For this the return type +is replaced with a block of result declarations, either in parentheses +or bracketed by `return` and `do`. + +##### Example: functions returning multiple variables + + func to_cartesian(rho:number; theta:number):(x:number; y:number) + x = ..... + y = ..... + + func to_polar + x:number; y:number + return + rho:number + theta:number + do + rho = .... + theta = .... -For constructing these lists we use a `List` binode, which will be +For constructing the lists we use a `List` binode, which will be further detailed when Expression Lists are introduced. ###### type union fields @@ -2471,6 +2494,7 @@ further detailed when Expression Lists are introduced. struct binode *params; struct type *return_type; struct variable *scope; + int inline_result; // return value is at start of 'local' int local_size; } function; @@ -2541,7 +2565,20 @@ further detailed when Expression Lists are introduced. fprintf(f, ")"); if (type->function.return_type != Tnone) { fprintf(f, ":"); - type_print(type->function.return_type, f); + if (type->function.inline_result) { + int i; + struct type *t = type->function.return_type; + fprintf(f, " ("); + for (i = 0; i < t->structure.nfields; i++) { + struct field *fl = t->structure.fields + i; + if (i) + fprintf(f, "; "); + fprintf(f, "%.*s:", fl->name.len, fl->name.txt); + type_print(fl->type, f); + } + fprintf(f, ")"); + } else + type_print(type->function.return_type, f); } fprintf(f, "\n"); } @@ -2982,10 +3019,11 @@ there. ###### Binode types CondExpr, -###### Grammar +###### declare terminals $LEFT if $$ifelse - ## expr precedence + +###### Grammar $*exec Expression -> Expression if Expression else Expression $$ifelse ${ { @@ -3104,7 +3142,7 @@ evaluate the second expression if not necessary. OrElse, Not, -###### expr precedence +###### declare terminals $LEFT or $LEFT and $LEFT not @@ -3252,7 +3290,7 @@ expression operator, and the `CMPop` non-terminal will match one of them. Eql, NEql, -###### expr precedence +###### declare terminals $LEFT < > <= >= == != CMPop ###### expression grammar @@ -3369,7 +3407,7 @@ should only insert brackets were needed for precedence. StringConv, Bracket, -###### expr precedence +###### declare terminals $LEFT + - Eop $LEFT * / % ++ Top $LEFT Uop $ @@ -3687,7 +3725,12 @@ arguments, form with the 'List' nodes. arg = cast(binode, arg->right); } c->local = local; c->local_size = t->function.local_size; - rv = interp_exec(c, fbody->function, &rvtype); + if (t->function.inline_result && dtype) { + _interp_exec(c, fbody->function, NULL, NULL); + memcpy(dest, local, dtype->size); + rvtype = ret.type = NULL; + } else + rv = interp_exec(c, fbody->function, &rvtype); c->local = oldlocal; c->local_size = old_size; free(local); break; @@ -3746,6 +3789,12 @@ which does nothing and is represented as a `NULL` pointer in a `Block` list. Other stand-alone statements will follow once the infrastructure is in-place. +As many statements will use binodes, we declare a binode pointer 'b' in +the common header for all reductions to use. + +###### Parser: reduce + struct binode *b; + ###### Binode types Block, @@ -3823,6 +3872,7 @@ is in-place. }$ $TERM pass + $*exec SimpleStatement -> pass ${ $0 = NULL; }$ | ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$ ## SimpleStatement Grammar @@ -3906,28 +3956,28 @@ printed. ###### Binode types Print, -##### expr precedence +##### declare terminals $TERM print ###### SimpleStatement Grammar | print ExpressionList ${ - $0 = new(binode); - $0->op = Print; - $0->right = NULL; - $0->left = reorder_bilist($op = Print; + b->right = NULL; + b->left = reorder_bilist($op = Print; - $0->right = reorder_bilist($left = NULL; + $0 = b = new(binode); + b->op = Print; + b->right = reorder_bilist($left = NULL; } }$ | print ${ - $0 = new(binode); - $0->op = Print; - $0->left = NULL; - $0->right = NULL; + $0 = b = new(binode); + b->op = Print; + b->left = NULL; + b->right = NULL; }$ ###### print binode cases @@ -3996,16 +4046,16 @@ it is declared, and error will be raised as the name is created as ###### SimpleStatement Grammar | Variable = Expression ${ - $0 = new(binode); - $0->op = Assign; - $0->left = $<1; - $0->right = $<3; + $0 = b= new(binode); + b->op = Assign; + b->left = $<1; + b->right = $<3; }$ | VariableDecl = Expression ${ - $0 = new(binode); - $0->op = Declare; - $0->left = $<1; - $0->right =$<3; + $0 = b= new(binode); + b->op = Declare; + b->left = $<1; + b->right =$<3; }$ | VariableDecl ${ @@ -4015,10 +4065,10 @@ it is declared, and error will be raised as the name is created as $1, NULL, 0, NULL); free_var($1); } else { - $0 = new(binode); - $0->op = Declare; - $0->left = $<1; - $0->right = NULL; + $0 = b = new(binode); + b->op = Declare; + b->left = $<1; + b->right = NULL; } }$ @@ -4085,7 +4135,7 @@ it is declared, and error will be raised as the name is created as propagate_types(b->left, c, ok, t, (b->op == Assign ? Rnoconstant : 0)); } - if (t && t->dup == NULL) + if (t && t->dup == NULL && t->name.txt[0] != ' ') // HACK type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL); return Tnone; @@ -4125,16 +4175,16 @@ function which has a return type, and the "condition" code blocks in ###### Binode types Use, -###### expr precedence +###### declare terminals $TERM use ###### SimpleStatement Grammar | use Expression ${ - $0 = new_pos(binode, $1); - $0->op = Use; - $0->right = $<2; - if ($0->right->type == Xvar) { - struct var *v = cast(var, $0->right); + $0 = b = new_pos(binode, $1); + b->op = Use; + b->right = $<2; + if (b->right->type == Xvar) { + struct var *v = cast(var, b->right); if (v->var->type == Tnone) { /* Convert this to a label */ struct value *val; @@ -4288,7 +4338,7 @@ casepart` to track a list of case parts. ###### ComplexStatement Grammar | CondStatement ${ $0 = $<1; }$ -###### expr precedence +###### declare terminals $TERM for then while do $TERM else $TERM switch case @@ -4834,20 +4884,62 @@ is a bit more interesting at this level. ###### ast functions + static struct type *handle_results(struct parse_context *c, + struct binode *results) + { + /* Create a 'struct' type from the results list, which + * is a list for 'struct var' + */ + struct text result_type_name = { " function_result", 5 }; + struct type *t = add_type(c, result_type_name, &structure_prototype); + int cnt = 0; + struct binode *b; + + for (b = results; b; b = cast(binode, b->right)) + cnt += 1; + t->structure.nfields = cnt; + t->structure.fields = calloc(cnt, sizeof(struct field)); + cnt = 0; + for (b = results; b; b = cast(binode, b->right)) { + struct var *v = cast(var, b->left); + struct field *f = &t->structure.fields[cnt++]; + int a = v->var->type->align; + f->name = v->var->name->name; + f->type = v->var->type; + f->init = NULL; + f->offset = t->size; + v->var->frame_pos = f->offset; + t->size += ((f->type->size - 1) | (a-1)) + 1; + if (a > t->align) + t->align = a; + variable_unlink_exec(v->var); + } + free_binode(results); + return t; + } + static struct variable *declare_function(struct parse_context *c, struct variable *name, struct binode *args, struct type *ret, + struct binode *results, struct exec *code) { struct text funcname = {" func", 5}; if (name) { 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); + struct type *t; var_block_close(c, CloseFunction, code); + t = add_type(c, funcname, &function_prototype); + name->type = t; + t->function.params = reorder_bilist(args); + if (!ret) { + ret = handle_results(c, reorder_bilist(results)); + t->function.inline_result = 1; + t->function.local_size = ret->size; + } + t->function.return_type = ret; + global_alloc(c, t, name, &fn); name->type->function.scope = c->out_scope; } else { free_binode(args); @@ -4866,22 +4958,31 @@ is a bit more interesting at this level. $*variable DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${ - $0 = declare_function(c, $in_scope; v; v = v->in_scope) { struct value *val; + struct type *ret; int ok = 1; if (v->depth != 0 || !v->type || !v->type->check_args) continue; + ret = v->type->function.inline_result ? + Tnone : v->type->function.return_type; val = var_value(c, v); do { ok = 1; - propagate_types(val->function, c, &ok, - v->type->function.return_type, 0); + propagate_types(val->function, c, &ok, ret, 0); } while (ok == 2); if (ok) /* Make sure everything is still consistent */ - propagate_types(val->function, c, &ok, - v->type->function.return_type, 0); + propagate_types(val->function, c, &ok, ret, 0); if (!ok) all_ok = 0; - if (!v->type->function.return_type->dup) { + if (!v->type->function.inline_result && + !v->type->function.return_type->dup) { type_err(c, "error: function cannot return value of type %1", v->where_decl, v->type->function.return_type, 0, NULL); }