]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: use new slice syntax for argv argument.
[ocean] / csrc / oceani.mdc
index c80c99262004c6b39f82ca924e7e513fb3fddfaf..a3574ea24e91167880aa12d2cff4bcefc1a1e412 100644 (file)
@@ -598,7 +598,7 @@ the value can only be assigned once, when the variable is declared.
 
 ###### ast
 
-       enum val_rules {Rboolok = 1<<0,};
+       enum val_rules {Rboolok = 1<<0, Rrefok = 1<<1,};
        enum prop_err {Efail = 1<<0, Eretry = 1<<1, Eruntime = 1<<2,
                       Emaycopy = 1<<3, Erval = 1<<4, Econst = 1<<5};
 
@@ -2468,15 +2468,11 @@ with a const size by whether they are prepared at parse time or not.
                /* Both are arrays, so we can look at details */
                if (!type_compat(require->array.member, have->array.member, 0))
                        return 0;
-               if (have->array.unspec && require->array.unspec) {
-                       if (have->array.vsize && require->array.vsize &&
-                           have->array.vsize != require->array.vsize)  // UNTESTED
-                               /* sizes might not be the same */
-                               return 0;       // UNTESTED
-                       return 1;
-               }
+               if (have->array.unspec && require->array.unspec &&
+                   have->array.size != require->array.size)
+                       return 0;       // UNTESTED
                if (have->array.unspec || require->array.unspec)
-                       return 1;       // UNTESTED
+                       return 1;
                if (require->array.vsize == NULL && have->array.vsize == NULL)
                        return require->array.size == have->array.size;
 
@@ -2554,29 +2550,18 @@ with a const size by whether they are prepared at parse time or not.
                $0->array.vsize = v;
        } }$
 
-###### Grammar
-       $*type
-       OptType -> Type ${ $0 = $<1; }$
-               | ${ $0 = NULL; }$
-
 ###### formal type grammar
 
-       | [ IDENTIFIER :: OptType ] Type ${ {
-               struct variable *v = var_decl(c, $ID.txt);
-
-               v->type = $<OT;
-               v->constant = 1;
-               if (!v->type)
-                       v->type = Tnum;
-               $0 = add_anon_type(c, &array_prototype, "array[var]");
-               $0->array.member = $<6;
+       | [ ] Type ${ {
+               $0 = add_anon_type(c, &array_prototype, "array[]");
+               $0->array.member = $<Type;
                $0->array.size = 0;
                $0->array.unspec = 1;
-               $0->array.vsize = v;
+               $0->array.vsize = NULL;
        } }$
 
 ###### Binode types
-       Index,
+       Index, Length,
 
 ###### term grammar
 
@@ -2588,6 +2573,13 @@ with a const size by whether they are prepared at parse time or not.
                $0 = b;
        } }$
 
+       | Term [ ] ${ {
+               struct binode *b = new(binode);
+               b->op = Length;
+               b->left = $<Term;
+               $0 = b;
+       } }$
+
 ###### print binode cases
        case Index:
                print_exec(b->left, -1, bracket);
@@ -2596,6 +2588,11 @@ with a const size by whether they are prepared at parse time or not.
                printf("]");
                break;
 
+       case Length:
+               print_exec(b->left, -1, bracket);
+               printf("[]");
+               break;
+
 ###### propagate binode cases
        case Index:
                /* left must be an array, right must be a number,
@@ -2615,6 +2612,20 @@ with a const size by whether they are prepared at parse time or not.
                }
                break;
 
+       case Length:
+               /* left must be an array, result is a number
+                */
+               t = propagate_types(b->left, c, perr, NULL, 0);
+               if (!t || t->compat != array_compat) {
+                       type_err(c, "error: %1 cannot provide length", prog, t, 0, NULL);
+                       return NULL;
+               }
+               if (!type_compat(type, Tnum, rules))
+                       type_err(c, "error: have %1 but need %2", prog,
+                                        Tnum, rules, type);
+               return Tnum;
+               break;
+
 ###### interp binode cases
        case Index: {
                mpz_t q;
@@ -2640,6 +2651,13 @@ with a const size by whether they are prepared at parse time or not.
                ltype = NULL;
                break;
        }
+       case Length: {
+               lleft = linterp_exec(c, b->left, &ltype);
+               mpq_set_ui(rv.num, ltype->array.size, 1);
+               ltype = NULL;
+               rvtype = Tnum;
+               break;
+       }
 
 #### Structs
 
@@ -2917,24 +2935,31 @@ function will be needed.
        }
 
 ###### top level grammar
-       DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ {
-               struct type *t;
-               t = find_type(c, $ID.txt);
-               if (!t)
-                       t = add_type(c, $ID.txt, &structure_prototype);
-               else if (t->size >= 0) {
+       $*type
+       StructName -> IDENTIFIER ${ {
+               struct type *t = find_type(c, $ID.txt);
+
+               if (t && t->size >= 0) {
                        tok_err(c, "error: type already declared", &$ID);
                        tok_err(c, "info: this is location of declartion", &t->first_use);
-                       /* Create a new one - duplicate */
-                       t = add_type(c, $ID.txt, &structure_prototype);
-               } else {
-                       struct type tmp = *t;
-                       *t = structure_prototype;
-                       t->name = tmp.name;
-                       t->next = tmp.next;
+                       t = NULL;
                }
-               t->structure.field_list = $<FB;
+               if (!t)
+                       t = add_type(c, $ID.txt, NULL);
                t->first_use = $ID;
+               $0 = t;
+       } }$
+       $void
+       DeclareStruct -> struct StructName FieldBlock Newlines ${ {
+               struct type *t = $<SN;
+               struct type tmp = *t;
+
+               *t = structure_prototype;
+               t->name = tmp.name;
+               t->next = tmp.next;
+               t->first_use = tmp.first_use;
+
+               t->structure.field_list = $<FB;
        } }$
 
        $*fieldlist
@@ -3121,6 +3146,9 @@ anything in the heap or on the stack.  A reference can be assigned
        static int reference_compat(struct type *require, struct type *have,
                                    enum val_rules rules)
        {
+               if (rules & Rrefok)
+                       if (require->reference.referent == have)
+                               return 1;
                if (have->compat != require->compat)
                        return 0;
                if (have->reference.referent != require->reference.referent)
@@ -3148,7 +3176,6 @@ anything in the heap or on the stack.  A reference can be assigned
                return Tnone;
        }
 
-
        static struct type reference_prototype = {
                .print_type = reference_print_type,
                .cmp_eq = reference_cmp,
@@ -3318,7 +3345,7 @@ anything in the heap or on the stack.  A reference can be assigned
 ###### Expressions: dereference
 
 ###### Binode types
-       Deref,
+       Deref, AddressOf,
 
 ###### term grammar
 
@@ -3334,6 +3361,9 @@ anything in the heap or on the stack.  A reference can be assigned
                print_exec(b->left, -1, bracket);
                printf("@");
                break;
+       case AddressOf:
+               print_exec(b->left, -1, bracket);
+               break;
 
 ###### propagate binode cases
        case Deref:
@@ -3347,13 +3377,30 @@ anything in the heap or on the stack.  A reference can be assigned
                        return t->reference.referent;
                break;
 
+       case AddressOf:
+               /* left must be lval, we create reference to it */
+               if (!type || type->free != reference_free)
+                       t = propagate_types(b->left, c, perr, type, 0); // UNTESTED
+               else
+                       t = propagate_types(b->left, c, perr,
+                                           type->reference.referent, 0);
+               if (t)
+                       t = find_anon_type(c, &reference_prototype, "@%.*s",
+                                       t->name.len, t->name.txt);
+               return t;
+
 ###### interp binode cases
-       case Deref: {
+       case Deref:
                left = interp_exec(c, b->left, &ltype);
                lrv = left.ref;
                rvtype = ltype->reference.referent;
                break;
-       }
+
+       case AddressOf:
+               rv.ref = linterp_exec(c, b->left, &rvtype);
+               rvtype = find_anon_type(c, &reference_prototype, "@%.*s",
+                                       rvtype->name.len, rvtype->name.txt);
+               break;
 
 
 #### Functions
@@ -3453,6 +3500,14 @@ further detailed when Expression Lists are introduced.
                return 0;
        }
 
+       static struct exec *take_addr(struct exec *e)
+       {
+               struct binode *rv = new(binode);
+               rv->op = AddressOf;
+               rv->left = e;
+               return rv;
+       }
+
        static void function_check_args(struct parse_context *c, enum prop_err *perr,
                                        struct type *require, struct exec *args)
        {
@@ -3464,13 +3519,22 @@ further detailed when Expression Lists are introduced.
 
                while (param) {
                        struct var *pv = cast(var, param->left);
+                       struct type *t = pv->var->type, *t2;
                        if (!arg) {
                                type_err(c, "error: insufficient arguments to function.",
                                         args, NULL, 0, NULL);
                                break;
                        }
                        *perr = 0;
-                       propagate_types(arg->left, c, perr, pv->var->type, 0);
+                       t2 = propagate_types(arg->left, c, perr, t, Rrefok);
+                       if (t->free == reference_free &&
+                           t->reference.referent == t2 &&
+                           !(*perr & Erval)) {
+                               arg->left = take_addr(arg->left);
+                       } else if (!(*perr & Efail) && !type_compat(t2, t, 0)) {
+                               type_err(c, "error: cannot pass rval when reference expected",
+                                        arg->left, NULL, 0, NULL);
+                       }
                        param = cast(binode, param->right);
                        arg = cast(binode, arg->right);
                }
@@ -4714,8 +4778,8 @@ it is declared, it is assumed to be a global constant which are allowed to
 be declared at any time.
 
 ###### Binode types
-       Assign,
-       Declare,
+       Assign, AssignRef,
+       Declare, DeclareRef,
 
 ###### declare terminals
        $TERM =
@@ -4751,6 +4815,7 @@ be declared at any time.
 ###### print binode cases
 
        case Assign:
+       case AssignRef:
                do_indent(indent, "");
                print_exec(b->left, -1, bracket);
                printf(" = ");
@@ -4760,6 +4825,7 @@ be declared at any time.
                break;
 
        case Declare:
+       case DeclareRef:
                {
                struct variable *v = cast(var, b->left)->var;
                do_indent(indent, "");
@@ -4789,8 +4855,10 @@ be declared at any time.
 ###### propagate binode cases
 
        case Assign:
+       case AssignRef:
        case Declare:
-               /* Both must match and not be labels,
+       case DeclareRef:
+               /* Both must match, or left may be ref and right an lval
                 * Type must support 'dup',
                 * For Assign, left must not be constant.
                 * result is Tnone
@@ -4801,11 +4869,23 @@ be declared at any time.
                        return Tnone;
 
                if (t) {
-                       if (propagate_types(b->right, c, perr_local, t, 0) != t &&
-                           *perr_local & Efail)
-                               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);
+                       struct type *t2 = propagate_types(b->right, c, perr_local,
+                                                         t, Rrefok);
+                       if (!t2 || t2 == t || (*perr_local & Efail))
+                               ; // No more effort needed
+                       else if (t->free == reference_free &&
+                                t->reference.referent == t2 &&
+                                !(*perr_local & Erval)) {
+                               if (b->op == Assign)
+                                       b->op = AssignRef;
+                               if (b->op == Declare)
+                                       b->op = DeclareRef;
+                       }
+                       else if (t->free == reference_free &&
+                                t->reference.referent == t2 &&
+                                (*perr_local & Erval))
+                               type_err(c, "error: Cannot assign an rval to a reference.",
+                                        b, NULL, 0, NULL);
                } else {
                        t = propagate_types(b->right, c, perr_local, NULL, 0);
                        if (t)
@@ -4814,7 +4894,7 @@ be declared at any time.
                if (*perr & Erval)
                        type_err(c, "error: cannot assign to an rval", b,
                                 NULL, 0, NULL);
-               else if (b->op == Assign && (*perr & Econst)) {
+               else if ((b->op == Assign || b->op == AssignRef) && (*perr & Econst)) {
                        type_err(c, "error: Cannot assign to a constant: %v",
                                 b->left, NULL, 0, NULL);
                        if (b->left->type == Xvar) {
@@ -4826,6 +4906,9 @@ be declared at any time.
                }
                if (t && t->dup == NULL && !(*perr_local & Emaycopy))
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
+               if (b->left->type == Xvar && (*perr_local & Efail))
+                       type_err(c, "info: variable '%v' was set as %1 here.",
+                                cast(var, b->left)->var->where_set, t, rules, NULL);
                return Tnone;
 
                break;
@@ -4833,13 +4916,21 @@ be declared at any time.
 ###### interp binode cases
 
        case Assign:
+       case AssignRef:
                lleft = linterp_exec(c, b->left, &ltype);
-               if (lleft)
+               if (!lleft)
+                       // FIXME lleft==NULL probably means illegal array ref
+                       // should that cause a runtime error
+                       ;
+               else if (b->op == AssignRef)
+                       lleft->ref = linterp_exec(c, b->right, &rtype);
+               else
                        dinterp_exec(c, b->right, lleft, ltype, 1);
                ltype = Tnone;
                break;
 
        case Declare:
+       case DeclareRef:
        {
                struct variable *v = cast(var, b->left)->var;
                struct value *val;
@@ -4847,10 +4938,12 @@ be declared at any time.
                val = var_value(c, v);
                if (v->type->prepare_type)
                        v->type->prepare_type(c, v->type, 0);
-               if (b->right)
-                       dinterp_exec(c, b->right, val, v->type, 0);
-               else
+               if (!b->right)
                        val_init(v->type, val);
+               else if (b->op == DeclareRef)
+                       val->ref = linterp_exec(c, b->right, &rtype);
+               else
+                       dinterp_exec(c, b->right, val, v->type, 0);
                break;
        }
 
@@ -5842,15 +5935,12 @@ is a bit more interesting at this level.
                        struct value *vl = var_value(c, v->var);
                        struct value arg;
                        struct type *t;
-                       mpq_t argcq;
                        int i;
 
                        switch (anum++) {
                        case 0: /* argv */
                                t = v->var->type;
-                               mpq_init(argcq);
-                               mpq_set_ui(argcq, argc, 1);
-                               memcpy(var_value(c, t->array.vsize), &argcq, sizeof(argcq));
+                               t->array.size = argc;
                                t->prepare_type(c, t, 0);
                                array_init(v->var->type, vl);
                                for (i = 0; i < argc; i++) {
@@ -5904,7 +5994,7 @@ things which will likely grow as the languages grows.
                name:string
                alive:Boolean
 
-       func main(argv:[argc::]string)
+       func main(argv:[]string)
                print "Hello World, what lovely oceans you have!"
                print "Are there", five, "?"
                print pi, pie, "but", cake