]> ocean-lang.org Git - ocean/commitdiff
oceani: move "complex types" earlier.
authorNeilBrown <neil@brown.name>
Sat, 11 May 2019 01:30:30 +0000 (11:30 +1000)
committerNeilBrown <neil@brown.name>
Sat, 11 May 2019 01:30:30 +0000 (11:30 +1000)
I think this fits better before "language elements",
as part of "data structures".  Nearly everything it needs
is defined by there.

Signed-off-by: NeilBrown <neil@brown.name>
csrc/oceani.mdc

index 02968bb473926333f3341ed78663d24d2b9144dd..b47383ac97b2243e0f18fd078371832c2d1caaf7 100644 (file)
@@ -1525,6 +1525,237 @@ Each `exec` can return a value, which may be `Tnone` but must be non-NULL;
                return ret;
        }
 
+### Complex types
+
+Now that we have the shape of the interpreter in place we can add some
+complex types and connected them in to the data structures and the
+different phases of parse, analyse, print, interpret.
+
+For now, just arrays.
+
+#### Arrays
+
+Arrays can be declared by giving a size and a type, as `[size]type' so
+`freq:[26]number` declares `freq` to be an array of 26 numbers.  The
+size can be an arbitrary expression which is evaluated when the name
+comes into scope.
+
+Arrays cannot be assigned.  When pointers are introduced we will also
+introduce array slices which can refer to part or all of an array -
+the assignment syntax will create a slice.  For now, an array can only
+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 depth.
+
+###### type union fields
+
+       struct {
+               int size;
+               struct variable *vsize;
+               struct type *member;
+       } array;
+
+###### value union fields
+       struct {
+               struct value *elmnts;
+       } array;
+
+###### value functions
+
+       static struct value array_prepare(struct type *type)
+       {
+               struct value ret;
+
+               ret.type = type;
+               ret.array.elmnts = NULL;
+               return ret;
+       }
+
+       static struct value array_init(struct type *type)
+       {
+               struct value ret;
+               int i;
+
+               ret.type = type;
+               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);
+               }
+               ret.array.elmnts = calloc(type->array.size,
+                                         sizeof(ret.array.elmnts[0]));
+               for (i = 0; ret.array.elmnts && i < type->array.size; i++)
+                       ret.array.elmnts[i] = val_init(type->array.member);
+               return ret;
+       }
+
+       static void array_free(struct value val)
+       {
+               int i;
+
+               if (val.array.elmnts)
+                       for (i = 0; i < val.type->array.size; i++)
+                               free_value(val.array.elmnts[i]);
+               free(val.array.elmnts);
+       }
+
+       static int array_compat(struct type *require, struct type *have)
+       {
+               if (have->compat != require->compat)
+                       return 0;
+               /* Both are arrays, so we can look at details */
+               if (!type_compat(require->array.member, have->array.member, 0))
+                       return 0;
+               if (require->array.vsize == NULL && have->array.vsize == NULL)
+                       return require->array.size == have->array.size;
+
+               return require->array.vsize == have->array.vsize;
+       }
+
+       static void array_print_type(struct type *type, FILE *f)
+       {
+               fputs("[", f);
+               if (type->array.vsize) {
+                       struct binding *b = type->array.vsize->name;
+                       fprintf(f, "%.*s]", b->name.len, b->name.txt);
+               } else
+                       fprintf(f, "%d]", type->array.size);
+               type_print(type->array.member, f);
+       }
+
+       static struct type array_prototype = {
+               .prepare = array_prepare,
+               .init = array_init,
+               .print_type = array_print_type,
+               .compat = array_compat,
+               .free = array_free,
+       };
+
+###### type grammar
+
+       | [ NUMBER ] Type ${
+               $0 = calloc(1, sizeof(struct type));
+               *($0) = array_prototype;
+               $0->array.member = $<4;
+               $0->array.vsize = NULL;
+               {
+               struct parse_context *c = config2context(config);
+               char tail[3];
+               mpq_t num;
+               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));
+                       if (mpz_cmp_ui(mpq_denref(num), 1) != 0) {
+                               tok_err(c, "error: array size must be an integer",
+                                       &$2);
+                       } else if (mpz_cmp_ui(mpq_numref(num), 1UL << 30) >= 0)
+                               tok_err(c, "error: array size is too large",
+                                       &$2);
+                       mpq_clear(num);
+               }
+               $0->next= c->anon_typelist;
+               c->anon_typelist = $0;
+               }
+       }$
+
+       | [ IDENTIFIER ] Type ${ {
+               struct parse_context *c = config2context(config);
+               struct variable *v = var_ref(c, $2.txt);
+
+               if (!v)
+                       tok_err(config2context(config), "error: name undeclared", &$2);
+               else if (!v->constant)
+                       tok_err(config2context(config), "error: array size must be a constant", &$2);
+
+               $0 = calloc(1, sizeof(struct type));
+               *($0) = 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,
+
+###### variable grammar
+
+       | Variable [ Expression ] ${ {
+               struct binode *b = new(binode);
+               b->op = Index;
+               b->left = $<1;
+               b->right = $<3;
+               $0 = b;
+       } }$
+
+###### print binode cases
+       case Index:
+               print_exec(b->left, -1, 0);
+               printf("[");
+               print_exec(b->right, -1, 0);
+               printf("]");
+               break;
+
+###### propagate binode cases
+       case Index:
+               /* left must be an array, right must be a number,
+                * result is the member type of the array
+                */
+               propagate_types(b->right, c, ok, Tnum, 0);
+               t = propagate_types(b->left, c, ok, NULL, rules & Rnoconstant);
+               if (!t || t->compat != array_compat) {
+                       type_err(c, "error: %1 cannot be indexed", prog, t, 0, NULL);
+                       *ok = 0;
+                       return NULL;
+               } else {
+                       if (!type_compat(type, t->array.member, rules)) {
+                               type_err(c, "error: have %1 but need %2", prog,
+                                        t->array.member, rules, type);
+                               *ok = 0;
+                       }
+                       return t->array.member;
+               }
+               break;
+
+###### interp binode cases
+       case Index: {
+               mpz_t q;
+               long i;
+
+               lleft = linterp_exec(b->left);
+               right = interp_exec(b->right);
+               mpz_init(q);
+               mpz_tdiv_q(q, mpq_numref(right.num), mpq_denref(right.num));
+               i = mpz_get_si(q);
+               mpz_clear(q);
+
+               if (i >= 0 && i < lleft->type->array.size)
+                       lrv = &lleft->array.elmnts[i];
+               else
+                       rv = val_init(lleft->type->array.member);
+               break;
+       }
+
 ## Language elements
 
 Each language element needs to be parsed, printed, analysed,
@@ -3313,237 +3544,6 @@ defined.
                break;
        }
 
-## Complex types
-
-Now that we have the shape of the interpreter in place we can add some
-complex types and connected them in to the data structures and the
-different phases of parse, analyse, print, interpret.
-
-For now, just arrays.
-
-### Arrays
-
-Arrays can be declared by giving a size and a type, as `[size]type' so
-`freq:[26]number` declares `freq` to be an array of 26 numbers.  The
-size can be an arbitrary expression which is evaluated when the name
-comes into scope.
-
-Arrays cannot be assigned.  When pointers are introduced we will also
-introduce array slices which can refer to part or all of an array -
-the assignment syntax will create a slice.  For now, an array can only
-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 depth.
-
-###### type union fields
-
-       struct {
-               int size;
-               struct variable *vsize;
-               struct type *member;
-       } array;
-
-###### value union fields
-       struct {
-               struct value *elmnts;
-       } array;
-
-###### value functions
-
-       static struct value array_prepare(struct type *type)
-       {
-               struct value ret;
-
-               ret.type = type;
-               ret.array.elmnts = NULL;
-               return ret;
-       }
-
-       static struct value array_init(struct type *type)
-       {
-               struct value ret;
-               int i;
-
-               ret.type = type;
-               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);
-               }
-               ret.array.elmnts = calloc(type->array.size,
-                                         sizeof(ret.array.elmnts[0]));
-               for (i = 0; ret.array.elmnts && i < type->array.size; i++)
-                       ret.array.elmnts[i] = val_init(type->array.member);
-               return ret;
-       }
-
-       static void array_free(struct value val)
-       {
-               int i;
-
-               if (val.array.elmnts)
-                       for (i = 0; i < val.type->array.size; i++)
-                               free_value(val.array.elmnts[i]);
-               free(val.array.elmnts);
-       }
-
-       static int array_compat(struct type *require, struct type *have)
-       {
-               if (have->compat != require->compat)
-                       return 0;
-               /* Both are arrays, so we can look at details */
-               if (!type_compat(require->array.member, have->array.member, 0))
-                       return 0;
-               if (require->array.vsize == NULL && have->array.vsize == NULL)
-                       return require->array.size == have->array.size;
-
-               return require->array.vsize == have->array.vsize;
-       }
-
-       static void array_print_type(struct type *type, FILE *f)
-       {
-               fputs("[", f);
-               if (type->array.vsize) {
-                       struct binding *b = type->array.vsize->name;
-                       fprintf(f, "%.*s]", b->name.len, b->name.txt);
-               } else
-                       fprintf(f, "%d]", type->array.size);
-               type_print(type->array.member, f);
-       }
-
-       static struct type array_prototype = {
-               .prepare = array_prepare,
-               .init = array_init,
-               .print_type = array_print_type,
-               .compat = array_compat,
-               .free = array_free,
-       };
-
-###### type grammar
-
-       | [ NUMBER ] Type ${
-               $0 = calloc(1, sizeof(struct type));
-               *($0) = array_prototype;
-               $0->array.member = $<4;
-               $0->array.vsize = NULL;
-               {
-               struct parse_context *c = config2context(config);
-               char tail[3];
-               mpq_t num;
-               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));
-                       if (mpz_cmp_ui(mpq_denref(num), 1) != 0) {
-                               tok_err(c, "error: array size must be an integer",
-                                       &$2);
-                       } else if (mpz_cmp_ui(mpq_numref(num), 1UL << 30) >= 0)
-                               tok_err(c, "error: array size is too large",
-                                       &$2);
-                       mpq_clear(num);
-               }
-               $0->next= c->anon_typelist;
-               c->anon_typelist = $0;
-               }
-       }$
-
-       | [ IDENTIFIER ] Type ${ {
-               struct parse_context *c = config2context(config);
-               struct variable *v = var_ref(c, $2.txt);
-
-               if (!v)
-                       tok_err(config2context(config), "error: name undeclared", &$2);
-               else if (!v->constant)
-                       tok_err(config2context(config), "error: array size must be a constant", &$2);
-
-               $0 = calloc(1, sizeof(struct type));
-               *($0) = 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,
-
-###### variable grammar
-
-       | Variable [ Expression ] ${ {
-               struct binode *b = new(binode);
-               b->op = Index;
-               b->left = $<1;
-               b->right = $<3;
-               $0 = b;
-       } }$
-
-###### print binode cases
-       case Index:
-               print_exec(b->left, -1, 0);
-               printf("[");
-               print_exec(b->right, -1, 0);
-               printf("]");
-               break;
-
-###### propagate binode cases
-       case Index:
-               /* left must be an array, right must be a number,
-                * result is the member type of the array
-                */
-               propagate_types(b->right, c, ok, Tnum, 0);
-               t = propagate_types(b->left, c, ok, NULL, rules & Rnoconstant);
-               if (!t || t->compat != array_compat) {
-                       type_err(c, "error: %1 cannot be indexed", prog, t, 0, NULL);
-                       *ok = 0;
-                       return NULL;
-               } else {
-                       if (!type_compat(type, t->array.member, rules)) {
-                               type_err(c, "error: have %1 but need %2", prog,
-                                        t->array.member, rules, type);
-                               *ok = 0;
-                       }
-                       return t->array.member;
-               }
-               break;
-
-###### interp binode cases
-       case Index: {
-               mpz_t q;
-               long i;
-
-               lleft = linterp_exec(b->left);
-               right = interp_exec(b->right);
-               mpz_init(q);
-               mpz_tdiv_q(q, mpq_numref(right.num), mpq_denref(right.num));
-               i = mpz_get_si(q);
-               mpz_clear(q);
-
-               if (i >= 0 && i < lleft->type->array.size)
-                       lrv = &lleft->array.elmnts[i];
-               else
-                       rv = val_init(lleft->type->array.member);
-               break;
-       }
-
 ### Finally the whole program.
 
 Somewhat reminiscent of Pascal a (current) Ocean program starts with