summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-03-25 23:38:15 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-03-25 23:38:15 -0400
commit1949636463f53675f04e1315ad84ecc87def57cb (patch)
tree421de652d28b966616a850feab09ab80aaaebb76
parent8e5951cefcffcd74674233637c07137c6f60ecc1 (diff)
improved struct member lookup
-rw-r--r--copy.c10
-rw-r--r--identifiers.c5
-rw-r--r--main.c1
-rw-r--r--parse.c12
-rw-r--r--types.c70
-rw-r--r--types.h8
6 files changed, 67 insertions, 39 deletions
diff --git a/copy.c b/copy.c
index 7bc26e2..88fb1ee 100644
--- a/copy.c
+++ b/copy.c
@@ -90,12 +90,12 @@ static void copy_val_full(Copier *c, Value *out, Value in, Type *t) {
static void copy_struct(Copier *c, StructDef *out, StructDef *in) {
*out = *in;
- out->scope = in->scope;
- idents_create(&out->scope.idents, c->allocr, &out->scope);
+ out->body = in->body;
+ idents_create(&out->body.idents, c->allocr, &out->body);
Block *prev = c->block;
- copy_block(c, &out->scope, &in->scope, 0);
- c->block = &out->scope;
+ copy_block(c, &out->body, &in->body, 0);
+ c->block = &out->body;
if (in->flags & STRUCT_DEF_RESOLVED) {
size_t nfields = arr_len(in->fields);
out->fields = NULL;
@@ -167,7 +167,7 @@ static void copy_type(Copier *c, Type *out, Type *in) {
break;
case TYPE_STRUCT: {
if (in->flags & TYPE_IS_RESOLVED) {
- /* we don't actually need to make a copy of the struct for inference */
+ /* we don't actually need to make a copy of the struct here */
} else {
/*
it's okay to copy the struct definition here, because before resolving,
diff --git a/identifiers.c b/identifiers.c
index b03a7be..a31600c 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -225,3 +225,8 @@ static Location ident_decl_location(File *file, Identifier i) {
Location l = {0};
return l;
}
+
+static bool ident_is_declared(Identifier i) {
+ return i && i->decl_kind != IDECL_NONE;
+}
+
diff --git a/main.c b/main.c
index 86916d1..30558f3 100644
--- a/main.c
+++ b/main.c
@@ -8,6 +8,7 @@
/*
TODO:
+make sure that struct["member"] still works
use
- use with a decl, e.g. use p : Point;
simplify eval macros with val_to_u/i64
diff --git a/parse.c b/parse.c
index 8c11bb5..a493f41 100644
--- a/parse.c
+++ b/parse.c
@@ -581,13 +581,13 @@ static Status parse_type(Parser *p, Type *type, Location *where) {
struc->params = NULL;
struc->where = parser_mk_loc(p);
struc->where.start = t->token;
- memset(&struc->scope, 0, sizeof struc->scope);
- idents_create(&struc->scope.idents, p->allocr, &struc->scope);
+ memset(&struc->body, 0, sizeof struc->body);
+ idents_create(&struc->body.idents, p->allocr, &struc->body);
memset(&struc->instances, 0, sizeof struc->instances);
- struc->scope.parent = p->block;
+ struc->body.parent = p->block;
Block *prev_block = p->block;
- p->block = &struc->scope;
+ p->block = &struc->body;
++t->token;
if (token_is_kw(t->token, KW_LPAREN)) {
@@ -619,9 +619,9 @@ static Status parse_type(Parser *p, Type *type, Location *where) {
}
p->block = prev_block;
- if (!parse_block(p, &struc->scope, PARSE_BLOCK_DONT_CREATE_IDENTS))
+ if (!parse_block(p, &struc->body, PARSE_BLOCK_DONT_CREATE_IDENTS))
return false;
- struc->where = struc->scope.where;
+ struc->where = struc->body.where;
break;
struct_fail:
diff --git a/types.c b/types.c
index a669bf7..4686e4d 100644
--- a/types.c
+++ b/types.c
@@ -581,17 +581,17 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type *
Identifier i = *ident;
#if 0
#ifdef TOC_DEBUG
- if (i->idents->scope != tr->block) {
+ if (i->idents->body != tr->block) {
printf("Ident declaration mismatch for this ident:\n");
print_location(where);
printf("Typer is typing:\n");
print_block_location(tr->block);
printf("But the identifier's scope is:\n");
- print_block_location(i->idents->scope);
+ print_block_location(i->idents->body);
abort();
}
#else
- assert(i->idents->scope == tr->block);
+ assert(i->idents->body == tr->block);
#endif
#endif
Block *b = tr->block;
@@ -602,9 +602,9 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type *
if (translated && translated->decl_kind != IDECL_NONE) {
#if 0
printf("translated %s from\n", ident_to_str(i));
- print_block_location(i->idents->scope);
+ print_block_location(i->idents->body);
printf(" to \n");
- print_block_location(translated->idents->scope);
+ print_block_location(translated->idents->body);
#endif
i = *ident = translated;
break;
@@ -730,11 +730,13 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type *
}
return true;
}
-static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s) {
+
+/* new_stmts is what s->body.stmts will become after typing is done */
+static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s, Statement **new_stmts) {
arr_foreach(b->stmts, Statement, stmt) {
if (stmt->kind == STMT_EXPR) {
if (stmt->expr.kind == EXPR_BLOCK) {
- if (!add_block_to_struct(tr, stmt->expr.block, s))
+ if (!add_block_to_struct(tr, stmt->expr.block, s, new_stmts))
return false;
continue;
}
@@ -755,6 +757,7 @@ static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s) {
return false;
}
*(Declaration **)typer_arr_add(tr, &s->constants) = d;
+ *(Statement *)typer_arr_add(tr, new_stmts) = *stmt;
} else {
if (flags & DECL_SEMI_CONST) {
err_print(d->where, "struct members can't be semi-constant.");
@@ -772,11 +775,13 @@ static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s) {
field->type = decl_type_at_index(d, i);
++i;
}
+
+ *(Statement *)typer_arr_add(tr, new_stmts) = *stmt;
}
- if (b != &s->scope) {
+ if (b != &s->body) {
/* we need to translate d's identifiers to s's scope */
arr_foreach(d->idents, Identifier, ip) {
- Identifier redeclared = ident_get(&s->scope.idents, (*ip)->str);
+ Identifier redeclared = ident_get(&s->body.idents, (*ip)->str);
if (redeclared && redeclared->decl_kind != IDECL_NONE) {
char *str = ident_to_str(*ip);
err_print(d->where, "Redeclaration of struct member %s", str);
@@ -784,7 +789,7 @@ static Status add_block_to_struct(Typer *tr, Block *b, StructDef *s) {
free(str);
return false;
}
- *ip = ident_translate_forced(*ip, &s->scope.idents);
+ *ip = ident_translate_forced(*ip, &s->body.idents);
(*ip)->decl_kind = IDECL_DECL;
(*ip)->decl = d;
}
@@ -855,13 +860,25 @@ static Status type_resolve(Typer *tr, Type *t, Location where) {
case TYPE_STRUCT: {
StructDef *s = t->struc;
if (!(s->flags & STRUCT_DEF_RESOLVED)) {
- if (!types_block(tr, &s->scope))
+ if (!types_block(tr, &s->body))
return false;
s->fields = NULL;
s->constants = NULL;
- if (!add_block_to_struct(tr, &s->scope, s))
+ Statement *new_stmts = NULL;
+ if (!add_block_to_struct(tr, &s->body, s, &new_stmts))
return false;
-
+ s->body.stmts = new_stmts;
+ /* set the field of each declaration, so that we can lookup struct members quickly */
+ Field *field = s->fields;
+ arr_foreach(new_stmts, Statement, stmt) {
+ assert(stmt->kind == STMT_DECL);
+ Declaration *decl = stmt->decl;
+ if (!(decl->flags & DECL_IS_CONST)) {
+ assert(!(decl->flags & DECL_HAS_EXPR));
+ decl->field = field;
+ field += arr_len(decl->idents);
+ }
+ }
s->instance_id = 0;
s->flags |= STRUCT_DEF_RESOLVED;
}
@@ -1484,7 +1501,7 @@ static Status get_struct_constant(StructDef *struc, Identifier member, Expressio
err_print(e->where, "To access constants from a parameterized struct, you must supply its arguments.");
return false;
}
- Identifier i = ident_translate(member, &struc->scope.idents);
+ Identifier i = ident_translate(member, &struc->body.idents);
if (!i || i->decl_kind == IDECL_NONE) {
char *member_s = ident_to_str(member);
char *struc_s = struc->name ? ident_to_str(struc->name) : "anonymous struct";
@@ -1975,7 +1992,7 @@ static Status types_expr(Typer *tr, Expression *e) {
info_print(base->struc->where, "struct was declared here.");
return false;
}
- Copier cop = copier_create(tr->allocr, base->struc->scope.parent);
+ Copier cop = copier_create(tr->allocr, base->struc->body.parent);
HashTable *table = &base->struc->instances;
StructDef struc;
copy_struct(&cop, &struc, base->struc);
@@ -2002,7 +2019,7 @@ static Status types_expr(Typer *tr, Expression *e) {
int ident_idx = 0;
/* temporarily add this instance to the stack, while we type the decl, in case you, e.g., pass t = float to struct(t::Type, u::t = "hello") */
*(Location *)arr_add(&err_ctx->instance_stack) = e->where;
- typer_block_enter(tr, &struc.scope);
+ typer_block_enter(tr, &struc.body);
bool success = types_decl(tr, param);
arr_remove_last(&err_ctx->instance_stack);
typer_block_exit(tr);
@@ -2068,7 +2085,7 @@ static Status types_expr(Typer *tr, Expression *e) {
struct_t.struc = &inst->struc;
*(Location *)arr_add(&err_ctx->instance_stack) = e->where;
Block *prev_block = tr->block;
- tr->block = &inst->struc.scope;
+ tr->block = &inst->struc.body;
bool success = type_resolve(tr, &struct_t, e->where); /* resolve the struct */
tr->block = prev_block;
arr_remove_last(&err_ctx->instance_stack);
@@ -2965,19 +2982,18 @@ static Status types_expr(Typer *tr, Expression *e) {
return false;
break;
} else if (struct_type->kind == TYPE_STRUCT) {
- bool is_field = false;
- arr_foreach(struct_type->struc->fields, Field, f) {
- if (ident_eq(f->name, rhs->ident)) {
- is_field = true;
- *t = *f->type;
- e->binary.dot.field = f;
- }
- }
- if (!is_field) {
+ StructDef *struc = struct_type->struc;
+ Identifier struct_ident = ident_translate(rhs->ident, &struc->body.idents);
+ if (ident_is_declared(struct_ident)) {
+ assert(struct_ident->decl_kind == IDECL_DECL);
+ Field *field = struct_ident->decl->field;
+ field += ident_index_in_decl(struct_ident, struct_ident->decl);
+ e->binary.dot.field = field;
+ } else {
if (!get_struct_constant(struct_type->struc, rhs->ident, e))
return false;
- break;
}
+ break;
} else if (struct_type->kind == TYPE_SLICE || struct_type->kind == TYPE_ARR || type_is_builtin(struct_type, BUILTIN_VARARGS)) {
if (ident_eq_str(rhs->ident, "data") && struct_type->kind == TYPE_SLICE) {
/* allow access of slice pointer */
diff --git a/types.h b/types.h
index 710faf8..a3a211a 100644
--- a/types.h
+++ b/types.h
@@ -522,7 +522,12 @@ typedef struct StructDef {
Location where;
U8 flags;
- Block scope; /* parameters and constants live here. statements aren't used after resolving (but are kept around because why not) */
+ /*
+ use this instead of fields when looking up a field, because it will include "use"d things.
+ this only consists of statements which are declarations after typing (and not #ifs,
+ for example)
+ */
+ Block body;
union {
HashTable instances;
struct {
@@ -888,6 +893,7 @@ typedef struct Declaration {
DeclFlags flags;
union {
Expression expr;
+ Field *field; /* pointer to the field which the first identifier in this decl refers to */
struct {
union {
struct {