]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: don't add extra indent for Declare and Assign
[ocean] / csrc / oceani.mdc
index 9720d222fac37ffced3f0494c446e3af2203eb19..2398fb3bb87b4f8c04c1ddb49f67baa64ce64071 100644 (file)
@@ -367,6 +367,7 @@ context so indicate that parsing failed.
        static void type_err(struct parse_context *c,
                             char *fmt, struct exec *loc,
                             struct type *t1, int rules, struct type *t2);
+       static void tok_err(struct parse_context *c, char *fmt, struct token *t);
 
 ###### core functions
 
@@ -477,12 +478,12 @@ from the `exec_types` enum.
                if (loc->type == Xbinode)
                        return __fput_loc(cast(binode,loc)->left, f) ||
                               __fput_loc(cast(binode,loc)->right, f);  // NOTEST
-               return 0;
+               return 0;       // NOTEST
        }
        static void fput_loc(struct exec *loc, FILE *f)
        {
                if (!__fput_loc(loc, f))
-                       fprintf(f, "??:??: ");
+                       fprintf(f, "??:??: ");  // NOTEST
        }
 
 Each different type of `exec` node needs a number of functions defined,
@@ -588,13 +589,15 @@ which can be `NULL` signifying "unknown".  A `prop_err` flag set is
 passed by reference.  It has `Efail` set when an error is found, and
 `Eretry` when the type for some element is set via propagation.  If
 any expression cannot be evaluated immediately, `Enoconst` is set.
+If the expression can be copied, `Emaycopy` is set.
 
 If it remains unchanged at `0`, then no more propagation is needed.
 
 ###### ast
 
        enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2};
-       enum prop_err {Efail = 1<<0, Eretry = 1<<1, Enoconst = 1<<2};
+       enum prop_err {Efail = 1<<0, Eretry = 1<<1, Enoconst = 1<<2,
+                      Emaycopy = 1<<3};
 
 ###### format cases
        case 'r':
@@ -789,10 +792,11 @@ which might be reported in error messages.
        struct type {
                struct text name;
                struct type *next;
+               struct token first_use;
                int size, align;
                int anon;
                void (*init)(struct type *type, struct value *val);
-               void (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
+               int (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
                void (*print)(struct type *type, struct value *val, FILE *f);
                void (*print_type)(struct type *type, FILE *f);
                int (*cmp_order)(struct type *t1, struct type *t2,
@@ -800,6 +804,7 @@ which might be reported in error messages.
                int (*cmp_eq)(struct type *t1, struct type *t2,
                              struct value *v1, struct value *v2);
                void (*dup)(struct type *type, struct value *vold, struct value *vnew);
+               int (*test)(struct type *type, struct value *val);
                void (*free)(struct type *type, struct value *val);
                void (*free_type)(struct type *t);
                long long (*to_int)(struct value *v);
@@ -836,7 +841,10 @@ which might be reported in error messages.
                struct type *n;
 
                n = calloc(1, sizeof(*n));
-               *n = *proto;
+               if (proto)
+                       *n = *proto;
+               else
+                       n->size = -1;
                n->name = s;
                n->anon = anon;
                n->next = c->typelist;
@@ -859,7 +867,7 @@ which might be reported in error messages.
                va_start(ap, name);
                vasprintf(&t.txt, name, ap);
                va_end(ap);
-               t.len = strlen(name);
+               t.len = strlen(t.txt);
                return _add_type(c, t, proto, 1);
        }
 
@@ -886,8 +894,10 @@ which might be reported in error messages.
                        fprintf(f, "%.*s", type->name.len, type->name.txt);
                else if (type->print_type)
                        type->print_type(type, f);
+               else if (type->name.len && type->anon)
+                       fprintf(f, "\"%.*s\"", type->name.len, type->name.txt);
                else
-                       fputs("*invalid*type*", f);
+                       fputs("*invalid*type*", f);     // NOTEST
        }
 
        static void val_init(struct type *type, struct value *val)
@@ -924,10 +934,35 @@ which might be reported in error messages.
        static void prepare_types(struct parse_context *c)
        {
                struct type *t;
+               int retry = 1;
+               enum { none, some, cannot } progress = none;
 
-               for (t = c->typelist; t; t = t->next)
-                       if (t->prepare_type)
-                               t->prepare_type(c, t, 1);
+               while (retry) {
+                       retry = 0;
+
+                       for (t = c->typelist; t; t = t->next) {
+                               if (t->size < 0)
+                                       tok_err(c, "error: type used but not declared",
+                                                &t->first_use);
+                               if (t->size == 0 && t->prepare_type) {
+                                       if (t->prepare_type(c, t, 1))
+                                               progress = some;
+                                       else if (progress == cannot)
+                                               tok_err(c, "error: type has recursive definition",
+                                                       &t->first_use);
+                                       else
+                                               retry = 1;
+                               }
+                       }
+                       switch (progress) {
+                       case cannot:
+                               retry = 0; break;
+                       case none:
+                               progress = cannot; break;
+                       case some:
+                               progress = none; break;
+                       }
+               }
        }
 
 ###### forward decls
@@ -966,12 +1001,10 @@ symbol for those.
 
        $*type
        Type -> IDENTIFIER ${
-               $0 = find_type(c, $1.txt);
+               $0 = find_type(c, $ID.txt);
                if (!$0) {
-                       tok_err(c,
-                               "error: undefined type", &$1);
-
-                       $0 = Tnone;
+                       $0 = add_type(c, $ID.txt, NULL);
+                       $0->first_use = $ID;
                }
        }$
        ## type grammar
@@ -1138,6 +1171,11 @@ A separate function encoding these cases will simplify some code later.
 
        static void _free_value(struct type *type, struct value *v);
 
+       static int bool_test(struct type *type, struct value *v)
+       {
+               return v->bool;
+       }
+
        static struct type base_prototype = {
                .init = _val_init,
                .print = _print_value,
@@ -1168,6 +1206,7 @@ A separate function encoding these cases will simplify some code later.
 ###### context initialization
 
        Tbool  = add_base_type(&context, "Boolean", Vbool, sizeof(char));
+       Tbool->test = bool_test;
        Tstr   = add_base_type(&context, "string", Vstr, sizeof(struct text));
        Tnum   = add_base_type(&context, "number", Vnum, sizeof(mpq_t));
        Tnone  = add_base_type(&context, "none", Vnone, 0);
@@ -2112,7 +2151,7 @@ correctly.
                        } else
                                fputs("???", stderr);   // NOTEST
                } else
-                       fputs("NOTVAR", stderr);
+                       fputs("NOTVAR", stderr);        // NOTEST
                break;
 
 ###### propagate exec cases
@@ -2251,33 +2290,37 @@ with a const size by whether they are prepared at parse time or not.
 
 ###### value functions
 
-       static void array_prepare_type(struct parse_context *c, struct type *type,
+       static int array_prepare_type(struct parse_context *c, struct type *type,
                                       int parse_time)
        {
                struct value *vsize;
                mpz_t q;
                if (type->array.static_size)
-                       return;
+                       return 1;       // UNTESTED
                if (type->array.unspec && parse_time)
-                       return;
+                       return 1;       // UNTESTED
                if (parse_time && type->array.vsize && !type->array.vsize->global)
-                       return;
+                       return 1;       // UNTESTED
 
                if (type->array.vsize) {
                        vsize = var_value(c, type->array.vsize);
                        if (!vsize)
-                               return; // UNTESTED
+                               return 1;       // UNTESTED
                        mpz_init(q);
                        mpz_tdiv_q(q, mpq_numref(vsize->num), mpq_denref(vsize->num));
                        type->array.size = mpz_get_si(q);
                        mpz_clear(q);
                }
+               if (!parse_time)
+                       return 1;
+               if (type->array.member->size <= 0)
+                       return 0;       // UNTESTED
 
-               if (parse_time && type->array.member->size) {
-                       type->array.static_size = 1;
-                       type->size = type->array.size * type->array.member->size;
-                       type->align = type->array.member->align;
-               }
+               type->array.static_size = 1;
+               type->size = type->array.size * type->array.member->size;
+               type->align = type->array.member->align;
+
+               return 1;
        }
 
        static void array_init(struct type *type, struct value *val)
@@ -2606,21 +2649,24 @@ function will be needed.
                free_fieldlist(t->structure.field_list);
        }
 
-       static void structure_prepare_type(struct parse_context *c,
-                                          struct type *t, int parse_time)
+       static int structure_prepare_type(struct parse_context *c,
+                                         struct type *t, int parse_time)
        {
                int cnt = 0;
                struct fieldlist *f;
 
                if (!parse_time || t->structure.fields)
-                       return;
+                       return 1;
 
                for (f = t->structure.field_list; f; f=f->prev) {
                        enum prop_err perr;
                        cnt += 1;
 
+                       if (f->f.type->size <= 0)
+                               return 0;
                        if (f->f.type->prepare_type)
-                               f->f.type->prepare_type(c, f->f.type, 1);
+                               f->f.type->prepare_type(c, f->f.type, parse_time);
+
                        if (f->init == NULL)
                                continue;
                        do {
@@ -2653,6 +2699,7 @@ function will be needed.
 
                        f = f->prev;
                }
+               return 1;
        }
 
        static struct type structure_prototype = {
@@ -2755,9 +2802,23 @@ function will be needed.
 
 ###### top level grammar
        DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ {
-               struct type *t =
-                       add_type(c, $2.txt, &structure_prototype);
+               struct type *t;
+               t = find_type(c, $ID.txt);
+               if (!t)
+                       t = add_type(c, $ID.txt, &structure_prototype);
+               else if (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->structure.field_list = $<FB;
+               t->first_use = $ID;
        } }$
 
        $*fieldlist
@@ -3037,6 +3098,7 @@ further detailed when Expression Lists are introduced.
                e->var = v;
                if (v) {
                        v->where_decl = e;
+                       v->where_set = e;
                        $0 = v;
                } else {
                        v = var_ref(c, $1.txt);
@@ -3065,7 +3127,7 @@ further detailed when Expression Lists are introduced.
        | Varlist ; ${ $0 = $<1; }$
 
        Varlist -> Varlist ; ArgDecl ${
-               $0 = new(binode);
+               $0 = new_pos(binode, $2);
                $0->op = List;
                $0->left = $<Vl;
                $0->right = $<AD;
@@ -3079,9 +3141,11 @@ further detailed when Expression Lists are introduced.
 
        $*var
        ArgDecl -> IDENTIFIER : FormalType ${ {
-               struct variable *v = var_decl(c, $1.txt);
-               $0 = new(var);
+               struct variable *v = var_decl(c, $ID.txt);
+               $0 = new_pos(var, $ID);
                $0->var = v;
+               v->where_decl = $0;
+               v->where_set = $0;
                v->type = $<FT;
        } }$
 
@@ -3159,6 +3223,8 @@ it in the "SimpleStatement Grammar" which will be described later.
                }
                *perr |= Enoconst;
                v->var->type->check_args(c, perr, v->var->type, args);
+               if (v->var->type->function.inline_result)
+                       *perr |= Emaycopy;
                return v->var->type->function.return_type;
        }
 
@@ -3596,10 +3662,17 @@ expression operator, and the `CMPop` non-terminal will match one of them.
 ### Expressions: Arithmetic etc.
 
 The remaining expressions with the highest precedence are arithmetic,
-string concatenation, and string conversion.  String concatenation
+string concatenation, string conversion, and testing.  String concatenation
 (`++`) has the same precedence as multiplication and division, but lower
 than the uniary.
 
+Testing comes in two forms.  A single question mark (`?`) is a uniary
+operator which converts come types into Boolean.  The general meaning is
+"is this a value value" and there will be more uses as the language
+develops.  A double questionmark (`??`) is a binary operator (Choose),
+with same precedence as multiplication, which returns the LHS if it
+tests successfully, else returns the RHS.
+
 String conversion is a temporary feature until I get a better type
 system.  `$` is a prefix operator which expects a string and returns
 a number.
@@ -3615,15 +3688,15 @@ parentheses around an expression converts it into a Term,
 ###### Binode types
        Plus, Minus,
        Times, Divide, Rem,
-       Concat,
-       Absolute, Negate,
+       Concat, Choose,
+       Absolute, Negate, Test,
        StringConv,
        Bracket,
 
 ###### declare terminals
        $LEFT + - Eop
-       $LEFT * / % ++ Top
-       $LEFT Uop $
+       $LEFT * / % ++ ?? Top
+       $LEFT Uop $ ?
        $TERM ( )
 
 ###### expression grammar
@@ -3668,11 +3741,13 @@ parentheses around an expression converts it into a Term,
        Uop ->   + ${ $0.op = Absolute; }$
        |        - ${ $0.op = Negate; }$
        |        $ ${ $0.op = StringConv; }$
+       |        ? ${ $0.op = Test; }$
 
        Top ->   * ${ $0.op = Times; }$
        |        / ${ $0.op = Divide; }$
        |        % ${ $0.op = Rem; }$
        |        ++ ${ $0.op = Concat; }$
+       |        ?? ${ $0.op = Choose; }$
 
 ###### print binode cases
        case Plus:
@@ -3681,6 +3756,7 @@ parentheses around an expression converts it into a Term,
        case Divide:
        case Concat:
        case Rem:
+       case Choose:
                if (bracket) printf("(");
                print_exec(b->left, indent, bracket);
                switch(b->op) {
@@ -3690,6 +3766,7 @@ parentheses around an expression converts it into a Term,
                case Divide: fputs(" / ", stdout); break;
                case Rem:    fputs(" % ", stdout); break;
                case Concat: fputs(" ++ ", stdout); break;
+               case Choose: fputs(" ?? ", stdout); break;
                default: abort();       // NOTEST
                }                       // NOTEST
                print_exec(b->right, indent, bracket);
@@ -3698,11 +3775,13 @@ parentheses around an expression converts it into a Term,
        case Absolute:
        case Negate:
        case StringConv:
+       case Test:
                if (bracket) printf("(");
                switch (b->op) {
                case Absolute:   fputs("+", stdout); break;
                case Negate:     fputs("-", stdout); break;
                case StringConv: fputs("$", stdout); break;
+               case Test:       fputs("?", stdout); break;
                default: abort();       // NOTEST
                }                       // NOTEST
                print_exec(b->right, indent, bracket);
@@ -3750,6 +3829,25 @@ parentheses around an expression converts it into a Term,
                                prog, type, 0, NULL);
                return Tnum;
 
+       case Test:
+               /* LHS must support ->test, result is Tbool */
+               t = propagate_types(b->right, c, perr, NULL, 0);
+               if (!t || !t->test)
+                       type_err(c, "error: '?' requires a testable value, not %1",
+                                prog, t, 0, NULL);
+               return Tbool;
+
+       case Choose:
+               /* LHS and RHS must match and are returned. Must support
+                * ->test
+                */
+               t = propagate_types(b->left, c, perr, type, rules);
+               t = propagate_types(b->right, c, perr, t, rules);
+               if (t && t->test == NULL)
+                       type_err(c, "error: \"??\" requires a testable value, not %1",
+                                prog, t, 0, NULL);
+               return t;
+
        case Bracket:
                return propagate_types(b->right, c, perr, type, 0);
 
@@ -3828,6 +3926,20 @@ parentheses around an expression converts it into a Term,
                        printf("Unsupported suffix: %.*s\n", tx.len, tx.txt);   // UNTESTED
 
                break;
+       case Test:
+               right = interp_exec(c, b->right, &rtype);
+               rvtype = Tbool;
+               rv.bool = !!rtype->test(rtype, &right);
+               break;
+       case Choose:
+               left = interp_exec(c, b->left, &ltype);
+               if (ltype->test(ltype, &left)) {
+                       rv = left;
+                       rvtype = ltype;
+                       ltype = NULL;
+               } else
+                       rv = interp_exec(c, b->right, &rvtype);
+               break;
 
 ###### value functions
 
@@ -4067,19 +4179,19 @@ printed.
 ###### SimpleStatement Grammar
 
        | print ExpressionList ${
-               $0 = b = new(binode);
+               $0 = b = new_pos(binode, $1);
                b->op = Print;
                b->right = NULL;
                b->left = reorder_bilist($<EL);
        }$
        | print ExpressionList , ${ {
-               $0 = b = new(binode);
+               $0 = b = new_pos(binode, $1);
                b->op = Print;
                b->right = reorder_bilist($<EL);
                b->left = NULL;
        } }$
        | print ${
-               $0 = b = new(binode);
+               $0 = b = new_pos(binode, $1);
                b->op = Print;
                b->left = NULL;
                b->right = NULL;
@@ -4181,9 +4293,9 @@ it is declared, and error will be raised as the name is created as
 
        case Assign:
                do_indent(indent, "");
-               print_exec(b->left, indent, bracket);
+               print_exec(b->left, -1, bracket);
                printf(" = ");
-               print_exec(b->right, indent, bracket);
+               print_exec(b->right, -1, bracket);
                if (indent >= 0)
                        printf("\n");
                break;
@@ -4192,7 +4304,7 @@ it is declared, and error will be raised as the name is created as
                {
                struct variable *v = cast(var, b->left)->var;
                do_indent(indent, "");
-               print_exec(b->left, indent, bracket);
+               print_exec(b->left, -1, bracket);
                if (cast(var, b->left)->var->constant) {
                        printf("::");
                        if (v->explicit_type) {
@@ -4208,7 +4320,7 @@ it is declared, and error will be raised as the name is created as
                }
                if (b->right) {
                        printf("= ");
-                       print_exec(b->right, indent, bracket);
+                       print_exec(b->right, -1, bracket);
                }
                if (indent >= 0)
                        printf("\n");
@@ -4240,7 +4352,7 @@ it is declared, and error will be raised as the name is created as
                                propagate_types(b->left, c, perr, t,
                                                (b->op == Assign ? Rnoconstant : 0));
                }
-               if (t && t->dup == NULL && t->name.txt[0] != ' ') // HACK
+               if (t && t->dup == NULL && !(*perr & Emaycopy))
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
                return Tnone;
 
@@ -5049,7 +5161,7 @@ is a bit more interesting at this level.
                 * is a list for 'struct var'
                 */
                struct type *t = add_anon_type(c, &structure_prototype,
-                                              " function result");
+                                              "function result");
                int cnt = 0;
                struct binode *b;