prepare_types(&context);
if (!context.parse_error && !analyse_funcs(&context)) {
fprintf(stderr, "oceani: type error in program - not running.\n");
- context.parse_error = 1;
+ context.parse_error += 1;
}
if (doprint) {
static void type_err(struct parse_context *c,
char *fmt, struct exec *loc,
struct type *t1, int rules, struct type *t2);
+ static void tok_err(struct parse_context *c, char *fmt, struct token *t);
###### core functions
}
}
fputs("\n", stderr);
- c->parse_error = 1;
+ c->parse_error += 1;
}
static void tok_err(struct parse_context *c, char *fmt, struct token *t)
{
fprintf(stderr, "%s:%d:%d: %s: %.*s\n", c->file_name, t->line, t->col, fmt,
t->txt.len, t->txt.txt);
- c->parse_error = 1;
+ c->parse_error += 1;
}
## Entities: declared and predeclared.
expected to return, and returns the type that it does return, either of
which can be `NULL` signifying "unknown". A `prop_err` flag set is
passed by reference. It has `Efail` set when an error is found, and
-`Eretry` when the type for some element is set via propagation. If it
-remains unchanged at `0`, then no more propagation is needed.
+`Eretry` when the type for some element is set via propagation. If
+any expression cannot be evaluated immediately, `Enoconst` is set.
+If the expression can be copied, `Emaycopy` is set.
+
+If it remains unchanged at `0`, then no more propagation is needed.
###### ast
enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2};
- enum prop_err {Efail = 1<<0, Eretry = 1<<1};
+ enum prop_err {Efail = 1<<0, Eretry = 1<<1, Enoconst = 1<<2,
+ Emaycopy = 1<<3};
###### format cases
case 'r':
static struct type *propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr,
struct type *type, int rules)
{
+ int pre_err = c->parse_error;
struct type *ret = __propagate_types(prog, c, perr, type, rules);
- if (c->parse_error)
+ if (c->parse_error > pre_err)
*perr |= Efail;
return ret;
}
struct type {
struct text name;
struct type *next;
+ struct token first_use;
int size, align;
int anon;
void (*init)(struct type *type, struct value *val);
- void (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
+ int (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
void (*print)(struct type *type, struct value *val, FILE *f);
void (*print_type)(struct type *type, FILE *f);
int (*cmp_order)(struct type *t1, struct type *t2,
struct type *n;
n = calloc(1, sizeof(*n));
- *n = *proto;
+ if (proto)
+ *n = *proto;
+ else
+ n->size = -1;
n->name = s;
n->anon = anon;
n->next = c->typelist;
static void prepare_types(struct parse_context *c)
{
struct type *t;
-
- for (t = c->typelist; t; t = t->next)
- if (t->prepare_type)
- t->prepare_type(c, t, 1);
+ int retry = 1;
+ enum { none, some, cannot } progress = none;
+
+ while (retry) {
+ retry = 0;
+
+ for (t = c->typelist; t; t = t->next) {
+ if (t->size < 0)
+ tok_err(c, "error: type used but not declared",
+ &t->first_use);
+ if (t->size == 0 && t->prepare_type) {
+ if (t->prepare_type(c, t, 1))
+ progress = some;
+ else if (progress == cannot)
+ tok_err(c, "error: type has recursive definition",
+ &t->first_use);
+ else
+ retry = 1;
+ }
+ }
+ switch (progress) {
+ case cannot:
+ retry = 0; break;
+ case none:
+ progress = cannot; break;
+ case some:
+ progress = none; break;
+ }
+ }
}
###### forward decls
$*type
Type -> IDENTIFIER ${
- $0 = find_type(c, $1.txt);
+ $0 = find_type(c, $ID.txt);
if (!$0) {
- tok_err(c,
- "error: undefined type", &$1);
-
- $0 = Tnone;
+ $0 = add_type(c, $ID.txt, NULL);
+ $0->first_use = $ID;
}
}$
## type grammar
{
if (!v->global) {
if (!c->local || !v->type)
- return NULL;
+ return NULL; // UNTESTED
if (v->frame_pos + v->type->size > c->local_size) {
printf("INVALID frame_pos\n"); // NOTEST
exit(2); // NOTEST
struct variable *v = var_ref(c, $1.txt);
$0 = new_pos(var, $1);
if (v == NULL) {
- /* This might be a label - allocate a var just in case */
+ /* This might be a global const or a label
+ * Allocate a var with impossible type Tnone,
+ * which will be adjusted when we find out what it is,
+ * or will trigger an error.
+ */
v = var_decl(c, $1.txt);
if (v) {
v->type = Tnone;
v->where_set = prog;
*perr |= Eretry;
}
- return type;
- }
- if (!type_compat(type, v->type, rules)) {
+ } else if (!type_compat(type, v->type, rules)) {
type_err(c, "error: expected %1%r but variable '%v' is %2", prog,
type, rules, v->type);
type_err(c, "info: this is where '%v' was set to %1", v->where_set,
v->type, rules, NULL);
}
+ if (!v->global || v->frame_pos < 0)
+ *perr |= Enoconst;
if (!type)
return v->type;
return type;
###### value functions
- static void array_prepare_type(struct parse_context *c, struct type *type,
+ static int array_prepare_type(struct parse_context *c, struct type *type,
int parse_time)
{
struct value *vsize;
mpz_t q;
if (type->array.static_size)
- return;
+ return 1; // UNTESTED
if (type->array.unspec && parse_time)
- return;
+ return 1; // UNTESTED
+ if (parse_time && type->array.vsize && !type->array.vsize->global)
+ return 1; // UNTESTED
if (type->array.vsize) {
vsize = var_value(c, type->array.vsize);
if (!vsize)
- return;
+ return 1; // UNTESTED
mpz_init(q);
mpz_tdiv_q(q, mpq_numref(vsize->num), mpq_denref(vsize->num));
type->array.size = mpz_get_si(q);
mpz_clear(q);
}
+ if (!parse_time)
+ return 1;
+ if (type->array.member->size <= 0)
+ return 0;
- if (parse_time && type->array.member->size) {
- type->array.static_size = 1;
- type->size = type->array.size * type->array.member->size;
- type->align = type->array.member->align;
- }
+ type->array.static_size = 1;
+ type->size = type->array.size * type->array.member->size;
+ type->align = type->array.member->align;
+
+ return 1;
}
static void array_init(struct type *type, struct value *val)
free_fieldlist(t->structure.field_list);
}
- static void structure_prepare_type(struct parse_context *c,
- struct type *t, int parse_time)
+ static int structure_prepare_type(struct parse_context *c,
+ struct type *t, int parse_time)
{
int cnt = 0;
struct fieldlist *f;
if (!parse_time || t->structure.fields)
- return;
+ return 1;
for (f = t->structure.field_list; f; f=f->prev) {
enum prop_err perr;
cnt += 1;
+ if (f->f.type->size <= 0)
+ return 0;
if (f->f.type->prepare_type)
- f->f.type->prepare_type(c, f->f.type, 1);
+ f->f.type->prepare_type(c, f->f.type, parse_time);
+
if (f->init == NULL)
continue;
do {
propagate_types(f->init, c, &perr, f->f.type, 0);
} while (perr & Eretry);
if (perr & Efail)
- c->parse_error = 1; // NOTEST
+ c->parse_error += 1; // NOTEST
}
t->structure.nfields = cnt;
f = f->prev;
}
+ return 1;
}
static struct type structure_prototype = {
###### top level grammar
DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ {
- struct type *t =
- add_type(c, $2.txt, &structure_prototype);
+ struct type *t;
+ t = find_type(c, $ID.txt);
+ if (!t)
+ t = add_type(c, $ID.txt, &structure_prototype);
+ else if (t->size >= 0) {
+ tok_err(c, "error: type already declared", &$ID);
+ tok_err(c, "info: this is location of declartion", &t->first_use);
+ /* Create a new one - duplicate */
+ t = add_type(c, $ID.txt, &structure_prototype);
+ } else {
+ struct type tmp = *t;
+ *t = structure_prototype;
+ t->name = tmp.name;
+ t->next = tmp.next;
+ }
t->structure.field_list = $<FB;
+ t->first_use = $ID;
} }$
$*fieldlist
prog, NULL, 0, NULL);
return NULL;
}
+ *perr |= Enoconst;
v->var->type->check_args(c, perr, v->var->type, args);
+ if (v->var->type->function.inline_result)
+ *perr |= Emaycopy;
return v->var->type->function.return_type;
}
propagate_types(b->left, c, perr, t,
(b->op == Assign ? Rnoconstant : 0));
}
- if (t && t->dup == NULL && t->name.txt[0] != ' ') // HACK
+ if (t && t->dup == NULL && !(*perr & Emaycopy))
type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
return Tnone;
v->global = 1;
} else {
v = var_ref(c, $1.txt);
- tok_err(c, "error: name already declared", &$1);
- type_err(c, "info: this is where '%v' was first declared",
- v->where_decl, NULL, 0, NULL);
+ if (v->type == Tnone) {
+ v->where_decl = var;
+ v->where_set = var;
+ v->type = $<CT;
+ v->constant = 1;
+ v->global = 1;
+ } else {
+ tok_err(c, "error: name already declared", &$1);
+ type_err(c, "info: this is where '%v' was first declared",
+ v->where_decl, NULL, 0, NULL);
+ }
}
var->var = v;
static void resolve_consts(struct parse_context *c)
{
struct binode *b;
+ int retry = 1;
+ enum { none, some, cannot } progress = none;
+
c->constlist = reorder_bilist(c->constlist);
- for (b = cast(binode, c->constlist); b;
- b = cast(binode, b->right)) {
- enum prop_err perr;
- struct binode *vb = cast(binode, b->left);
- struct var *v = cast(var, vb->left);
- do {
- perr = 0;
- propagate_types(vb->right, c, &perr,
- v->var->type, 0);
- } while (perr & Eretry);
- if (perr & Efail)
- c->parse_error = 1;
- else {
- struct value res = interp_exec(
- c, vb->right, &v->var->type);
- global_alloc(c, v->var->type, v->var, &res);
+ while (retry) {
+ retry = 0;
+ for (b = cast(binode, c->constlist); b;
+ b = cast(binode, b->right)) {
+ enum prop_err perr;
+ struct binode *vb = cast(binode, b->left);
+ struct var *v = cast(var, vb->left);
+ if (v->var->frame_pos >= 0)
+ continue;
+ do {
+ perr = 0;
+ propagate_types(vb->right, c, &perr,
+ v->var->type, 0);
+ } while (perr & Eretry);
+ if (perr & Efail)
+ c->parse_error += 1;
+ else if (!(perr & Enoconst)) {
+ progress = some;
+ struct value res = interp_exec(
+ c, vb->right, &v->var->type);
+ global_alloc(c, v->var->type, v->var, &res);
+ } else {
+ if (progress == cannot)
+ type_err(c, "error: const %v cannot be resolved.",
+ v, NULL, 0, NULL);
+ else
+ retry = 1;
+ }
+ }
+ switch (progress) {
+ case cannot:
+ retry = 0; break;
+ case none:
+ progress = cannot; break;
+ case some:
+ progress = none; break;
}
}
}
* is a list for 'struct var'
*/
struct type *t = add_anon_type(c, &structure_prototype,
- " function result");
+ "function result");
int cnt = 0;
struct binode *b;
propagate_types(b->left, c, &perr, Tnone, 0); // NOTEST
}
if (perr & Efail)
- c->parse_error = 1;
+ c->parse_error += 1;
}
return !c->parse_error;
progp = var_value(c, mainv);
if (!progp || !progp->function) {
fprintf(stderr, "oceani: no main function found.\n");
- c->parse_error = 1;
+ c->parse_error += 1;
return;
}
if (!analyse_main(mainv->type, c)) {
fprintf(stderr, "oceani: main has wrong type.\n");
- c->parse_error = 1;
+ c->parse_error += 1;
return;
}
al = mainv->type->function.params;