]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: detect and report tails on numbers and strings.
[ocean] / csrc / oceani.mdc
index c38fce52f095cc9279c937bc2b272a5d044e6da0..ebb69ade3d2a32f40e0e3666ed6416cf8d2cc4e9 100644 (file)
@@ -110,6 +110,7 @@ option.
        struct parse_context {
                struct token_config config;
                char *file_name;
+               int parse_error;
                ## parse context
        };
 
@@ -226,9 +227,13 @@ option.
                } else
                        prog = parse_oceani(s->code, &context.config,
                                    dotrace ? stderr : NULL);
+               if (!prog) {
+                       fprintf(stderr, "oceani: fatal parser error.\n");
+                       context.parse_error = 1;
+               }
                if (prog && doprint)
                        print_exec(*prog, 0, brackets);
-               if (prog && doexec) {
+               if (prog && doexec && !context.parse_error) {
                        if (!analyse_prog(*prog, &context)) {
                                fprintf(stderr, "oceani: type error in program - not running.\n");
                                exit(1);
@@ -246,7 +251,7 @@ option.
                        s = t;
                }
                ## free context
-               exit(0);
+               exit(context.parse_error ? 1 : 0);
        }
 
 ### Analysis
@@ -367,6 +372,13 @@ stored.
                        }
                }
                fputs("\n", stderr);
+               c->parse_error = 1;
+       }
+
+       static void tok_err(struct parse_context *c, char *fmt, struct token *t)
+       {
+               fprintf(stderr, "%s:%d:%d: %s\n", c->file_name, t->line, t->col, fmt);
+               c->parse_error = 1;
        }
 
 ## Data Structures
@@ -657,6 +669,7 @@ cannot nest, so a declaration while a name is in-scope is an error.
                struct variable *previous;
                struct value val;
                struct binding *name;
+               struct exec *where_decl;// where name was declared
                struct exec *where_set; // where type was set
                ## variable fields
        };
@@ -889,7 +902,7 @@ all pending-scope variables become conditionally scoped.
 
                switch (v ? v->scope : OutScope) {
                case InScope:
-                       /* Signal error ... once I build error signalling support */
+                       /* Caller will report the error */
                        return NULL;
                case CondScope:
                        for (;
@@ -1149,6 +1162,8 @@ also want to know what sort of bracketing to use.
 
        static void print_exec(struct exec *e, int indent, int bracket)
        {
+               if (!e)
+                       return;
                switch (e->type) {
                case Xbinode:
                        print_binode(cast(binode, e), indent, bracket); break;
@@ -1272,16 +1287,25 @@ an executable.
                        $0->val.vtype = Vnum;
                        if (number_parse($0->val.num, $0->val.tail, $1.txt) == 0)
                                mpq_init($0->val.num);
+                               if ($0->val.tail[0])
+                                       tok_err(config2context(config), "error: unsupported number suffix.",
+                                               &$1);
                        }$
                | STRING ${
                        $0 = new_pos(val, $1);
                        $0->val.vtype = Vstr;
                        string_parse(&$1, '\\', &$0->val.str, $0->val.tail);
+                       if ($0->val.tail[0])
+                               tok_err(config2context(config), "error: unsupported string suffix.",
+                                       &$1);
                        }$
                | MULTI_STRING ${
                        $0 = new_pos(val, $1);
                        $0->val.vtype = Vstr;
                        string_parse(&$1, '\\', &$0->val.str, $0->val.tail);
+                       if ($0->val.tail[0])
+                               tok_err(config2context(config), "error: unsupported string suffix.",
+                                       &$1);
                        }$
 
 ###### print exec cases
@@ -1370,12 +1394,32 @@ link to find the primary instance.
                struct variable *v = var_decl(config2context(config), $1.txt);
                $0 = new_pos(var, $1);
                $0->var = v;
+               if (v)
+                       v->where_decl = $0;
+               else {
+                       v = var_ref(config2context(config), $1.txt);
+                       $0->var = v;
+                       type_err(config2context(config), "error: variable '%v' redeclared",
+                                $0, Vnone, Vnone);
+                       type_err(config2context(config), "info: this is where '%v' was first declared",
+                                v->where_decl, Vnone, Vnone);
+               }
        } }$
            | IDENTIFIER ::= ${ {
                struct variable *v = var_decl(config2context(config), $1.txt);
-               v->constant = 1;
                $0 = new_pos(var, $1);
                $0->var = v;
+               if (v) {
+                       v->where_decl = $0;
+                       v->constant = 1;
+               } else {
+                       v = var_ref(config2context(config), $1.txt);
+                       $0->var = v;
+                       type_err(config2context(config), "error: variable '%v' redeclared",
+                                $0, Vnone, Vnone);
+                       type_err(config2context(config), "info: this is where '%v' was first declared",
+                                v->where_decl, Vnone, Vnone);
+               }
        } }$
 
        Variable -> IDENTIFIER ${ {
@@ -1438,9 +1482,9 @@ link to find the primary instance.
                        return type;
                }
                if (!vtype_compat(type, v->val.vtype, bool_permitted)) {
-                       type_err(c, "error: expected %1 but variable %v is %2", prog,
+                       type_err(c, "error: expected %1 but variable '%v' is %2", prog,
                                 type, v->val.vtype);
-                       type_err(c, "info: this is where %v was set to %1", v->where_set,
+                       type_err(c, "info: this is where '%v' was set to %1", v->where_set,
                                 v->val.vtype, Vnone);
                        *ok = 0;
                }
@@ -2187,7 +2231,7 @@ it is declared, and error will be raised as the name is created as
                if (t > Vunknown) {
                        if (propagate_types(b->right, c, ok, t, 0) != t)
                                if (b->left->type == Xvar)
-                                       type_err(c, "info: variable %v was set as %1 here.",
+                                       type_err(c, "info: variable '%v' was set as %1 here.",
                                                 cast(var, b->left)->var->where_set, t, Vnone);
                } else {
                        t = propagate_types(b->right, c, ok, Vnolabel, 0);
@@ -2751,7 +2795,11 @@ analysis is a bit more interesting at this level.
                $0->right = $<4;
                var_block_close(config2context(config), CloseSequential);
                if (config2context(config)->scope_stack) abort();
-       }$
+               }$
+               | ERROR ${
+                       tok_err(config2context(config),
+                               "error: unhandled parse error.", &$1);
+               }$
 
        Varlist -> Varlist ArgDecl ${
                        $0 = new(binode);
@@ -2796,6 +2844,8 @@ analysis is a bit more interesting at this level.
                struct binode *b = cast(binode, prog);
                int ok = 1;
 
+               if (!b)
+                       return 0;
                do {
                        ok = 1;
                        propagate_types(b->right, c, &ok, Vnone, 0);
@@ -2826,9 +2876,12 @@ analysis is a bit more interesting at this level.
        static void interp_prog(struct exec *prog, char **argv)
        {
                struct binode *p = cast(binode, prog);
-               struct binode *al = cast(binode, p->left);
+               struct binode *al;
                struct value v;
 
+               if (!prog)
+                       return;
+               al = cast(binode, p->left);
                while (al) {
                        struct var *v = cast(var, al->left);
                        struct value *vl = &v->var->val;