From 241e92c09f8d0a9a42c74768a960d938db245ca9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 11 May 2019 11:30:30 +1000 Subject: [PATCH] oceani: move "complex types" earlier. 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 --- csrc/oceani.mdc | 462 ++++++++++++++++++++++++------------------------ 1 file changed, 231 insertions(+), 231 deletions(-) diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 02968bb..b47383a 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -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 -- 2.43.0