]> ocean-lang.org Git - ocean/commitdiff
oceani: add array type.
authorNeilBrown <neil@brown.name>
Wed, 1 May 2019 09:01:48 +0000 (19:01 +1000)
committerNeilBrown <neil@brown.name>
Wed, 1 May 2019 09:01:48 +0000 (19:01 +1000)
I can now declare arrays and access or assign
members there-of.

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

index 9ab456a629badad65780a72cc1d10e366cd29ced..27c0c32493ecba0ee96916ae13135e2f69558790 100644 (file)
@@ -1758,6 +1758,7 @@ link to find the primary instance.
                }
                cast(var, $0)->var = v;
        } }$
+       ## variable grammar
 
        $*type
        Type -> IDENTIFIER ${
@@ -1769,6 +1770,7 @@ link to find the primary instance.
                        $0 = Tnone;
                }
        }$
+       ## type grammar
 
 ###### print exec cases
        case Xvar:
@@ -3199,6 +3201,217 @@ 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;
+               {
+               char tail[3];
+               mpq_t num;
+               if (number_parse(num, tail, $2.txt) == 0)
+                       tok_err(config2context(config), "error: unrecognised number", &$2);
+               else if (tail[0])
+                       tok_err(config2context(config), "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(config2context(config), "error: array size must be an integer",
+                                       &$2);
+                       } else if (mpz_cmp_ui(mpq_numref(num), 1UL << 30) >= 0)
+                               tok_err(config2context(config), "error: array size is too large",
+                                       &$2);
+               }
+               }
+       }$
+
+       | [ IDENTIFIER ] Type ${ {
+               struct variable *v = var_ref(config2context(config), $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;
+       } }$
+
+###### 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
@@ -3416,3 +3629,24 @@ Fibonacci, and performs a binary search for a number.
                        print "Yay, I found", target
                case GiveUp:
                        print "Closest I found was", mid
+
+               size::=55
+               list:[size]number
+               list[0] = 1234
+               for i:=1; then i = i + 1; while i < size:
+                       n := list[i-1] * list[i-1]
+                       list[i] = (n / 100) % 10000
+
+               print "Before sort:"
+               for i:=0; then i = i + 1; while i < size:
+                       print "list[",i,"]=",list[i]
+
+               for i := 1; then i=i+1; while i < size:
+                       for j:=i-1; then j=j-1; while j >= 0:
+                               if list[j] > list[j+1]:
+                                       t:= list[j]
+                                       list[j] = list[j+1]
+                                       list[j+1] = t
+               print "After sort:"
+               for i:=0; then i = i + 1; while i < size:
+                       print "list[",i,"]=",list[i]