]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: differentiate static-sized arrays from others.
[ocean] / csrc / oceani.mdc
index d690b70fb5c795ee481483db747f794f28850381..0de2988dbc689dd0b1970c16e48bdd20b1403c84 100644 (file)
@@ -287,14 +287,6 @@ consistent across all the branches.  When the variable is not used
 outside the if, the variables in the different branches are distinct
 and can be of different types.
 
-Determining the types of all variables early is important for
-processing command line arguments.  These can be assigned to any of
-several types of variable, but we must first know the correct type so
-any required conversion can happen.  If a variable is associated with
-a command line argument but no type can be interpreted (e.g. the
-variable is only ever used in a `print` statement), then the type is
-set to 'string'.
-
 Undeclared names may only appear in "use" statements and "case" expressions.
 These names are given a type of "label" and a unique value.
 This allows them to fill the role of a name in an enumerated type, which
@@ -407,11 +399,11 @@ various entities.
 ### Types
 
 Values come in a wide range of types, with more likely to be added.
-Each type needs to be able to parse and print its own values (for
-convenience at least) as well as to compare two values, at least for
-equality and possibly for order.  For now, values might need to be
-duplicated and freed, though eventually such manipulations will be
-better integrated into the language.
+Each type needs to be able to print its own values (for convenience at
+least) as well as to compare two values, at least for equality and
+possibly for order.  For now, values might need to be duplicated and
+freed, though eventually such manipulations will be better integrated
+into the language.
 
 Rather than requiring every numeric type to support all numeric
 operations (add, multiple, etc), we allow types to be able to present
@@ -437,7 +429,7 @@ Named type are stored in a simple linked list.  Objects of each type are
                struct type *next;
                int size, align;
                void (*init)(struct type *type, struct value *val);
-               int (*parse)(struct type *type, char *str, struct value *val);
+               void (*prepare_type)(struct type *type, int parse_time);
                void (*print)(struct type *type, struct value *val);
                void (*print_type)(struct type *type, FILE *f);
                int (*cmp_order)(struct type *t1, struct type *t2,
@@ -541,20 +533,13 @@ Named type are stored in a simple linked list.  Objects of each type are
                        printf("*Unknown*");            // NOTEST
        }
 
-       static int parse_value(struct type *type, char *arg, 
-                              struct value *val)
-       {
-               if (type && type->parse)
-                       return type->parse(type, arg, val);
-               return 0;                               // NOTEST
-       }
-
        static struct value *val_alloc(struct type *t, struct value *init)
        {
                struct value *ret;
 
-               if (!t->size)
-                       val_init(t, NULL);
+               if (t->prepare_type)
+                       t->prepare_type(t, 0);
+
                ret = calloc(1, t->size);
                if (init)
                        memcpy(ret, init, t->size);
@@ -574,7 +559,6 @@ Named type are stored in a simple linked list.  Objects of each type are
        static int value_cmp(struct type *tl, struct type *tr,
                             struct value *left, struct value *right);
        static void print_value(struct type *type, struct value *v);
-       static int parse_value(struct type *type, char *arg, struct value *val);
 
 ###### free context types
 
@@ -627,9 +611,6 @@ A separate function encoding these cases will simplify some code later.
                return require == have;
        }
 
-When assigning command line arguments to variables, we need to be able
-to parse each type from a string.
-
 ###### includes
        #include <gmp.h>
        #include "parse_string.h"
@@ -747,57 +728,10 @@ to parse each type from a string.
                }
        }
 
-       static int _parse_value(struct type *type, char *arg, struct value *val)
-       {
-               struct text tx;
-               int neg = 0;
-               char tail[3] = "";
-
-               switch(type->vtype) {
-               case Vlabel:                            // NOTEST
-               case Vnone:                             // NOTEST
-                       return 0;                       // NOTEST
-               case Vstr:
-                       val->str.len = strlen(arg);
-                       val->str.txt = malloc(val->str.len);
-                       memcpy(val->str.txt, arg, val->str.len);
-                       break;
-               case Vnum:
-                       if (*arg == '-') {
-                               neg = 1;
-                               arg++;
-                       }
-                       tx.txt = arg; tx.len = strlen(tx.txt);
-                       if (number_parse(val->num, tail, tx) == 0)
-                               mpq_init(val->num);
-                       else if (neg)
-                               mpq_neg(val->num, val->num);
-                       if (tail[0]) {
-                               printf("Unsupported suffix: %s\n", arg);
-                               return 0;
-                       }
-                       break;
-               case Vbool:
-                       if (strcasecmp(arg, "true") == 0 ||
-                           strcmp(arg, "1") == 0)
-                               val->bool = 1;
-                       else if (strcasecmp(arg, "false") == 0 ||
-                                strcmp(arg, "0") == 0)
-                               val->bool = 0;
-                       else {
-                               printf("Bad bool: %s\n", arg);
-                               return 0;
-                       }
-                       break;
-               }
-               return 1;
-       }
-
        static void _free_value(struct type *type, struct value *v);
 
        static struct type base_prototype = {
                .init = _val_init,
-               .parse = _parse_value,
                .print = _print_value,
                .cmp_order = _value_cmp,
                .cmp_eq = _value_cmp,
@@ -1505,8 +1439,10 @@ in `rval`.
        {
                struct lrval ret = _interp_exec(e);
 
-               if (typeret)
+               if (ret.lval)
                        *typeret = ret.type;
+               else
+                       free_value(ret.type, &ret.rval);
                return ret.lval;
        }
 
@@ -1553,10 +1489,6 @@ different phases of parse, analyse, print, interpret.
 
 Thus far we have arrays and structs.
 
-Some complex types need do not exist in a name table, so they are kept
-on a linked list in the context (`anon_typelist`).  This allows them to
-be freed when parsing is complete.
-
 #### Arrays
 
 Arrays can be declared by giving a size and a type, as `[size]type' so
@@ -1571,39 +1503,66 @@ ever be referenced by the name it is declared with.  It is likely that
 a "`copy`" primitive will eventually be define which can be used to
 make a copy of an array with controllable recursive depth.
 
+For now we have two sorts of array, those with fixed size either because
+it is given as a literal number or because it is a struct member (which
+cannot have a runtime-changing size), and those with a size that is
+determined at runtime - local variables with a const size.  The former
+have their size calculated at parse time, the latter at run time.
+
+For the latter type, the `size` field of the type is the size of a
+pointer, and the array is reallocated every time it comes into scope.
+
+We differentiate struct fields with a const size from local variables
+with a const size by whether they are prepared at parse time or not.
+
 ###### type union fields
 
        struct {
-               int size;
+               short size;
+               short static_size;
                struct variable *vsize;
                struct type *member;
        } array;
 
 ###### value union fields
-       void *array;
+       void *array;  // used if not static_size
 
 ###### value functions
 
-       static void array_init(struct type *type, struct value *val)
+       static void array_prepare_type(struct type *type, int parse_time)
        {
-               int i;
+               mpz_t q;
+               if (!type->array.vsize || type->array.static_size)
+                       return;
 
-               if (type->array.vsize) {
-                       mpz_t q;
-                       mpz_init(q);
-                       mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
-                                  mpq_denref(type->array.vsize->val->num));
-                       type->array.size = mpz_get_si(q);
-                       mpz_clear(q);
+               mpz_init(q);
+               mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
+                          mpq_denref(type->array.vsize->val->num));
+               type->array.size = mpz_get_si(q);
+               mpz_clear(q);
+
+               if (parse_time) {
+                       type->array.static_size = 1;
+                       type->size = type->array.size * type->array.member->size;
+                       type->align = type->array.member->align;
                }
-               type->size = type->array.size * type->array.member->size;
-               type->align = type->array.member->align;
+       }
+
+       static void array_init(struct type *type, struct value *val)
+       {
+               int i;
+               void *ptr = val->ptr;
 
                if (!val)
-                       return;         
+                       return;
+               if (!type->array.static_size) {
+                       val->array = calloc(type->array.size, 
+                                           type->array.member->size);
+                       ptr = val->array;
+               }
                for (i = 0; i < type->array.size; i++) {
                        struct value *v;
-                       v = (void*)val->ptr + i * type->array.member->size;
+                       v = (void*)ptr + i * type->array.member->size;
                        val_init(type->array.member, v);
                }
        }
@@ -1611,12 +1570,17 @@ make a copy of an array with controllable recursive depth.
        static void array_free(struct type *type, struct value *val)
        {
                int i;
+               void *ptr = val->ptr;
 
+               if (!type->array.static_size)
+                       ptr = val->array;
                for (i = 0; i < type->array.size; i++) {
                        struct value *v;
-                       v = (void*)val->ptr + i * type->array.member->size;
+                       v = (void*)ptr + i * type->array.member->size;
                        free_value(type->array.member, v);
                }
+               if (!type->array.static_size)
+                       free(ptr);
        }
 
        static int array_compat(struct type *require, struct type *have)
@@ -1645,27 +1609,34 @@ make a copy of an array with controllable recursive depth.
 
        static struct type array_prototype = {
                .init = array_init,
+               .prepare_type = array_prepare_type,
                .print_type = array_print_type,
                .compat = array_compat,
                .free = array_free,
+               .size = sizeof(void*),
+               .align = sizeof(void*),
        };
 
+###### declare terminals
+       $TERM [ ]
+
 ###### type grammar
 
-       | [ NUMBER ] Type ${
-               $0 = calloc(1, sizeof(struct type));
-               *($0) = array_prototype;
-               $0->array.member = $<4;
-               $0->array.vsize = NULL;
-               {
+       | [ NUMBER ] Type ${ {
                char tail[3];
                mpq_t num;
+               struct text noname = { "", 0 };
+               struct type *t;
+
+               $0 = t = add_type(c, noname, &array_prototype);
+               t->array.member = $<4;
+               t->array.vsize = NULL;
                if (number_parse(num, tail, $2.txt) == 0)
                        tok_err(c, "error: unrecognised number", &$2);
                else if (tail[0])
                        tok_err(c, "error: unsupported number suffix", &$2);
                else {
-                       $0->array.size = mpz_get_ui(mpq_numref(num));
+                       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",
                                        &$2);
@@ -1674,41 +1645,26 @@ make a copy of an array with controllable recursive depth.
                                        &$2);
                        mpq_clear(num);
                }
-               $0->next = c->anon_typelist;
-               c->anon_typelist = $0;
-               }
-       }$
+               t->array.static_size = 1;
+               t->size = t->array.size * t->array.member->size;
+               t->align = t->array.member->align;
+       } }$
 
        | [ IDENTIFIER ] Type ${ {
                struct variable *v = var_ref(c, $2.txt);
+               struct text noname = { "", 0 };
 
                if (!v)
                        tok_err(c, "error: name undeclared", &$2);
                else if (!v->constant)
                        tok_err(c, "error: array size must be a constant", &$2);
 
-               $0 = calloc(1, sizeof(struct type));
-               *($0) = array_prototype;
+               $0 = add_type(c, noname, &array_prototype);
                $0->array.member = $<4;
                $0->array.size = 0;
                $0->array.vsize = v;
-               $0->next = c->anon_typelist;
-               c->anon_typelist = $0;
        } }$
 
-###### parse context
-
-       struct type *anon_typelist;
-
-###### free context types
-
-       while (context.anon_typelist) {
-               struct type *t = context.anon_typelist;
-
-               context.anon_typelist = t->next;
-               free(t);
-       }
-
 ###### Binode types
        Index,
 
@@ -1753,6 +1709,7 @@ make a copy of an array with controllable recursive depth.
        case Index: {
                mpz_t q;
                long i;
+               void *ptr;
 
                lleft = linterp_exec(b->left, &ltype);
                right = interp_exec(b->right, &rtype);
@@ -1761,9 +1718,13 @@ make a copy of an array with controllable recursive depth.
                i = mpz_get_si(q);
                mpz_clear(q);
 
+               if (ltype->array.static_size)
+                       ptr = lleft;
+               else
+                       ptr = *(void**)lleft;
                rvtype = ltype->array.member;
                if (i >= 0 && i < ltype->array.size)
-                       lrv = (void*)lleft + i * rvtype->size;
+                       lrv = ptr + i * rvtype->size;
                else
                        val_init(ltype->array.member, &rv);
                ltype = NULL;
@@ -1835,7 +1796,12 @@ function will be needed.
                for (i = 0; i < type->structure.nfields; i++) {
                        struct value *v;
                        v = (void*) val->ptr + type->structure.fields[i].offset;
-                       val_init(type->structure.fields[i].type, v);
+                       if (type->structure.fields[i].init)
+                               dup_value(type->structure.fields[i].type, 
+                                         type->structure.fields[i].init,
+                                         v);
+                       else
+                               val_init(type->structure.fields[i].type, v);
                }
        }
 
@@ -1886,6 +1852,9 @@ function will be needed.
                free(e);
                break;
 
+###### declare terminals
+       $TERM struct .
+
 ###### variable grammar
 
        | Variable . IDENTIFIER ${ {
@@ -2047,7 +2016,8 @@ function will be needed.
                        $0 = calloc(1, sizeof(struct fieldlist));
                        $0->f.name = $1.txt;
                        $0->f.type = $<3;
-                       $0->f.init = val_alloc($0->f.type, NULL);
+                       if ($0->f.type->prepare_type)
+                               $0->f.type->prepare_type($0->f.type, 1);
                }$
 
 ###### forward decls
@@ -2132,6 +2102,8 @@ an executable.
 
 ###### Grammar
 
+       $TERM True False
+
        $*val
        Value ->  True ${
                        $0 = new_val(Tbool, $1);
@@ -2253,6 +2225,8 @@ link to find the primary instance.
 
 ###### Grammar
 
+       $TERM : ::
+
        $*var
        VariableDecl -> IDENTIFIER : ${ {
                struct variable *v = var_decl(c, $1.txt);
@@ -2984,9 +2958,22 @@ should only insert brackets were needed for precedence.
                right = interp_exec(b->right, &rvtype);
                rtype = Tstr;
                rvtype = Tnum;
-               char *str = strndup(right.str.txt, right.str.len);
-               parse_value(rvtype, str, &rv);
-               free(str);
+
+               struct text tx = right.str;
+               char tail[3];
+               int neg = 0;
+               if (tx.txt[0] == '-') {
+                       neg = 1;
+                       tx.txt++;
+                       tx.len--;
+               }
+               if (number_parse(rv.num, tail, tx) == 0)
+                       mpq_init(rv.num);
+               else if (neg)
+                       mpq_neg(rv.num, rv.num);
+               if (tail[0])
+                       printf("Unsupported suffix: %.*s\n", tx.len, tx.txt);
+
                break;
 
 ###### value functions
@@ -3057,11 +3044,10 @@ is in-place.
 ###### Binode types
        Block,
 
-###### expr precedence
-       $TERM pass
-
 ###### Grammar
 
+       $TERM { } ;
+
        $*binode
        Block -> { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
                | { SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
@@ -3131,6 +3117,7 @@ is in-place.
                        $0->right = $<1;
                        }$
 
+       $TERM pass
        SimpleStatement -> pass ${ $0 = NULL; }$
                | ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$
                ## SimpleStatement Grammar
@@ -3306,6 +3293,9 @@ it is declared, and error will be raised as the name is created as
        Assign,
        Declare,
 
+###### declare terminals
+       $TERM =
+
 ###### SimpleStatement Grammar
        | Variable = Expression ${
                        $0 = new(binode);
@@ -3421,14 +3411,13 @@ it is declared, and error will be raised as the name is created as
                struct variable *v = cast(var, b->left)->var;
                if (v->merged)
                        v = v->merged;
+               free_value(v->type, v->val);
+               free(v->val);
                if (b->right) {
                        right = interp_exec(b->right, &rtype);
-                       free_value(v->type, v->val);
-                       free(v->val);
                        v->val = val_alloc(v->type, &right);
                        rtype = Tnone;
                } else {
-                       free_value(v->type, v->val);
                        v->val = val_alloc(v->type, NULL);
                }
                break;
@@ -3976,6 +3965,8 @@ various declarations in the parse context.
        $void
        Ocean -> OptNL DeclarationList
 
+       ## declare terminals
+
        OptNL ->
                | OptNL NEWLINE
        Newlines -> NEWLINE
@@ -4019,6 +4010,8 @@ searching through for the Nth constant for decreasing N.
 
 ###### top level grammar
 
+       $TERM const
+
        DeclareConstant -> const { IN OptNL ConstList OUT OptNL } Newlines
                | const { SimpleConstList } Newlines
                | const IN OptNL ConstList OUT Newlines
@@ -4125,6 +4118,8 @@ analysis is a bit more interesting at this level.
                        c->prog = $<1;
        } }$
 
+       $TERM program
+
        $*binode
        Program -> program OpenScope Varlist ColonBlock Newlines ${
                $0 = new(binode);
@@ -4234,8 +4229,9 @@ analysis is a bit more interesting at this level.
                                v->var->val = vl;
                        }
                        free_value(v->var->type, vl);
-                       if (!parse_value(v->var->type, argv[0], vl))
-                               exit(1);
+                       vl->str.len = strlen(argv[0]);
+                       vl->str.txt = malloc(vl->str.len);
+                       memcpy(vl->str.txt, argv[0], vl->str.len);
                        argv++;
                }
                v = interp_exec(p->right, &vtype);