summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-01-11 22:40:21 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-01-11 22:40:21 -0500
commit2069b22cbcbbf293151db0c7c2a3e29f8c29c977 (patch)
tree7ded0128f3e5673d3905cc850622703a52eefb2b
parentb4ece566e3625e5de6cec6b4773e05a07485da0d (diff)
eval for imported stuff
-rw-r--r--cgen.c2
-rw-r--r--eval.c98
-rw-r--r--identifiers.c14
-rw-r--r--location.c6
-rw-r--r--package.c24
-rw-r--r--test.toc4
-rw-r--r--tokenizer.c6
-rw-r--r--types.c24
-rw-r--r--types.h5
9 files changed, 117 insertions, 66 deletions
diff --git a/cgen.c b/cgen.c
index e8ea47f..1236148 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1280,7 +1280,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_expr(g, e->binary.lhs);
bool is_ptr = e->binary.lhs->type.kind == TYPE_PTR;
cgen_write(g, is_ptr ? "->" :".");
- cgen_ident(g, e->binary.field->name);
+ cgen_ident(g, e->binary.dot.field->name);
cgen_write(g, ")");
handled = true;
} break;
diff --git a/eval.c b/eval.c
index 28a8134..e53f0e1 100644
--- a/eval.c
+++ b/eval.c
@@ -736,7 +736,7 @@ static void *eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr) {
} else {
struc_data = struc.struc;
}
- return (char *)struc_data + dot_expr->binary.field->offset;
+ return (char *)struc_data + dot_expr->binary.dot.field->offset;
}
static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) {
@@ -843,7 +843,7 @@ static bool eval_set(Evaluator *ev, Expression *set, Value *to) {
case BINARY_DOT: {
void *ptr = eval_ptr_to_struct_field(ev, set);
if (!ptr) return false;
- eval_deref_set(ptr, to, &set->binary.field->type);
+ eval_deref_set(ptr, to, &set->binary.dot.field->type);
} break;
default: assert(0); break;
}
@@ -1019,6 +1019,51 @@ static bool val_is_nonnegative(Value *v, Type *t) {
return val_to_i64(v, t->builtin) >= 0;
}
+static bool eval_ident(Evaluator *ev, Identifier ident, Value *v, Location where) {
+ IdentDecl *idecl = ident_decl(ident);
+ if (!idecl) {
+ char *s = ident_to_str(ident);
+ err_print(where, "Undeclared identifier: %s.", s);
+ free(s);
+ return false;
+ }
+ bool is_decl = idecl->kind == IDECL_DECL;
+ Declaration *d = NULL;
+ if (is_decl) {
+ d = idecl->decl;
+
+ if ((d->flags & DECL_FOUND_VAL) && type_is_builtin(&d->type, BUILTIN_TYPE) && d->val.type->kind == TYPE_STRUCT) {
+ v->type = allocr_malloc(ev->allocr, sizeof *v->type);
+ v->type->flags = TYPE_IS_RESOLVED;
+ v->type->kind = TYPE_STRUCT;
+ v->type->struc = d->val.type->struc;
+ return true;
+ } else {
+ if (!types_decl(ev->typer, d)) return false;
+ assert(d->type.flags & TYPE_IS_RESOLVED);
+ }
+ }
+ if (idecl->flags & IDECL_HAS_VAL) {
+ *v = idecl->val;
+ } else if (is_decl && (d->flags & DECL_IS_CONST)) {
+ if (!(d->flags & DECL_FOUND_VAL)) {
+ assert(d->flags & DECL_HAS_EXPR);
+ if (!eval_expr(ev, &d->expr, &d->val)) return false;
+ d->flags |= DECL_FOUND_VAL;
+ }
+ int index = ident_index_in_decl(ident, d);
+ assert(index != -1);
+ *v = *decl_val_at_index(d, index);
+ } else {
+ char *s = ident_to_str(ident);
+
+ err_print(where, "Cannot evaluate non-constant '%s' at compile time.", s);
+ free(s);
+ return false;
+ }
+ return true;
+}
+
static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
#define eval_unary_op_one(low, up, op) \
@@ -1109,6 +1154,11 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
if (!eval_expr(ev, rhs_expr, &rhs)) return false;
switch (e->binary.op) {
case BINARY_DOT: {
+ if (type_is_builtin(&lhs_expr->type, BUILTIN_PKG)) {
+ if (!eval_ident(ev, e->binary.dot.pkg_ident, v, rhs_expr->where))
+ return false;
+ break;
+ }
void *ptr = eval_ptr_to_struct_field(ev, e);
if (!ptr) return false;
eval_deref(v, ptr, &e->type);
@@ -1332,48 +1382,10 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
case EXPR_FN:
v->fn = e->fn;
break;
- case EXPR_IDENT: {
- IdentDecl *idecl = ident_decl(e->ident);
- if (!idecl) {
- char *s = ident_to_str(e->ident);
- err_print(e->where, "Undeclared identifier: %s.", s);
- free(s);
- return false;
- }
- bool is_decl = idecl->kind == IDECL_DECL;
- Declaration *d = NULL;
- if (is_decl) {
- d = idecl->decl;
- if ((d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_TYPE && d->expr.typeval.kind == TYPE_STRUCT) {
- v->type = allocr_malloc(ev->allocr, sizeof *v->type);
- v->type->flags = TYPE_IS_RESOLVED;
- v->type->kind = TYPE_STRUCT;
- v->type->struc = d->expr.typeval.struc;
- break;
- } else {
- if (!types_decl(ev->typer, d)) return false;
- assert(d->type.flags & TYPE_IS_RESOLVED);
- }
- }
- if (idecl->flags & IDECL_HAS_VAL) {
- *v = idecl->val;
- } else if (is_decl && (d->flags & DECL_IS_CONST)) {
- if (!(d->flags & DECL_FOUND_VAL)) {
- assert(d->flags & DECL_HAS_EXPR);
- if (!eval_expr(ev, &d->expr, &d->val)) return false;
- d->flags |= DECL_FOUND_VAL;
- }
- int index = ident_index_in_decl(e->ident, d);
- assert(index != -1);
- *v = *decl_val_at_index(d, index);
- } else {
- char *s = ident_to_str(e->ident);
-
- err_print(e->where, "Cannot evaluate non-constant '%s' at compile time.", s);
- free(s);
+ case EXPR_IDENT:
+ if (!eval_ident(ev, e->ident, v, e->where))
return false;
- }
- } break;
+ break;
case EXPR_TUPLE: {
size_t i, n = arr_len(e->tuple);
v->tuple = err_malloc(n * sizeof *v->tuple);
diff --git a/identifiers.c b/identifiers.c
index de8a106..c562d52 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -9,7 +9,7 @@
#endif
/* can this character be used in an identifier? */
-static int isident(int c) {
+static int is_ident(int c) {
if (c >= 'a' && c <= 'z')
return 1;
if (c >= 'A' && c <= 'Z')
@@ -71,7 +71,7 @@ static void idents_create(Identifiers *ids) {
static Identifier ident_insert(Identifiers *ids, char **s) {
IdentTree *tree = ids->root;
while (1) {
- if (!isident(**s)) {
+ if (!is_ident(**s)) {
return tree;
}
int c = ident_char_to_uchar(**s);
@@ -117,6 +117,7 @@ static char *ident_to_str(Identifier i) {
return str;
}
+
static void fprint_ident(FILE *out, Identifier id) {
char *str = ident_to_str(id);
fprintf(out, "%s", str);
@@ -172,6 +173,15 @@ static Identifier ident_get(Identifiers *ids, const char *s) {
return tree;
}
+static Identifier ident_translate(Identifier i, Identifiers *to_idents) {
+ /* OPTIM */
+ if (!i || i->anonymous) return NULL;
+ char *s = ident_to_str(i);
+ Identifier new_ident = ident_get(to_idents, s);
+ free(s);
+ return new_ident;
+}
+
static IdentDecl *ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) {
IdentDecl *id_decl = arr_add(&i->decls);
id_decl->decl = d;
diff --git a/location.c b/location.c
index 2cc63e5..35952de 100644
--- a/location.c
+++ b/location.c
@@ -9,7 +9,11 @@ static Location const LOCATION_NONE = {0};
/* for debugging */
static void fprint_location(FILE *out, Location location) {
if (!location.start) {
- fprintf(out, "No location available.");
+ if (location.simple_location) {
+ fprintf(out, "Line %lu of %s\n", (unsigned long)location.simple_location->line, location.simple_location->ctx->filename);
+ } else {
+ fprintf(out, "No location available.");
+ }
return;
}
/* TODO: show end */
diff --git a/package.c b/package.c
index 9ce338a..75945b7 100644
--- a/package.c
+++ b/package.c
@@ -199,7 +199,7 @@ static void exptr_start(Exporter *ex, const char *pkg_name, size_t pkg_name_len)
}
}
-/* where = where was this imported */
+/* where = where was this imported. don't free fname while imported stuff is in use. */
static bool import_pkg(Allocator *allocr, Package *p, FILE *f, const char *fname, Identifiers *parent_idents, ErrCtx *parent_ctx, Location where) {
Importer i = {0};
ErrCtx *err_ctx = &i.err_ctx;
@@ -246,11 +246,18 @@ static bool import_pkg(Allocator *allocr, Package *p, FILE *f, const char *fname
return false;
fseek(f, decls_offset, SEEK_SET);
/* read declarations */
+ Statement *stmts = NULL;
while (import_u8(&i)) {
- import_decl(&i, arr_add(&i.decls));
+ Statement *s = arr_add(&stmts);
+ s->kind = STMT_DECL;
+ import_decl(&i, &s->decl);
}
free(i.ident_map);
+ /* TOOD: LEAK! exit at some point */
+ if (!block_enter(NULL, stmts, 0))
+ return false;
+
return true;
}
@@ -960,14 +967,12 @@ static void import_decl(Importer *im, Declaration *d) {
}
if (d->flags & DECL_FOUND_VAL) {
d->val = import_val(im, &d->type);
- printf("TYPE: ");
- print_type(&d->type);
- printf("VALUE: ");
- print_val(d->val, &d->type);
+ if (d->flags & DECL_HAS_EXPR) {
+ d->expr.kind = EXPR_VAL;
+ d->expr.val = d->val;
+ }
} else if (d->flags & DECL_HAS_EXPR) {
import_expr(im, &d->expr);
- printf("EXPRESSION: ");
- print_expr(&d->expr);
}
}
@@ -1182,8 +1187,9 @@ static bool import_footer(Importer *im) {
import_struct(im, s);
import_arr(im, &im->fns);
- arr_foreach(im->fns, FnExpr, f)
+ arr_foreach(im->fns, FnExpr, f) {
import_fn(im, f);
+ }
if (ferror(im->in)) {
warn_print(im->import_location, "An error occured while reading the package. It may be incorrect.");
diff --git a/test.toc b/test.toc
index 53bae45..f557425 100644
--- a/test.toc
+++ b/test.toc
@@ -11,4 +11,6 @@ putf ::= fn(x: float) {
point ::= pkg "point";
-main ::= fn() {}; \ No newline at end of file
+main ::= fn() {
+ x : point.Point;
+}; \ No newline at end of file
diff --git a/tokenizer.c b/tokenizer.c
index b3e300b..48579bc 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -32,7 +32,7 @@ static Keyword tokenize_kw(char **s) {
/*
it's not a symbol, so we need to check if it's something like "intfoo"
*/
- if (isident((*s)[len])) {
+ if (is_ident((*s)[len])) {
continue;
}
}
@@ -50,7 +50,7 @@ static Directive tokenize_direct(char **s) {
for (Directive d = 0; d < DIRECT_COUNT; d = d + 1) {
size_t len = strlen(directives[d]);
if (strncmp(*s, directives[d], len) == 0) {
- if (isident((*s)[len])) {
+ if (is_ident((*s)[len])) {
continue;
}
*s += len;
@@ -517,7 +517,7 @@ static bool tokenize_string(Tokenizer *t, char *str) {
continue;
}
- if (isident(*t->s)) {
+ if (is_ident(*t->s)) {
/* it's an identifier */
Token *token = tokr_add(t);
Identifier ident = ident_insert(t->idents, &t->s);
diff --git a/types.c b/types.c
index 591cc92..6742c86 100644
--- a/types.c
+++ b/types.c
@@ -987,7 +987,7 @@ static bool types_expr(Typer *tr, Expression *e) {
free(name_cstr);
e->pkg.name_ident = name_ident;
if (!name_ident->pkg) {
- char *filename = err_malloc(name_str_len + 5);
+ char *filename = typer_malloc(tr, name_str_len + 5);
Package *pkg = name_ident->pkg = allocr_calloc(tr->allocr, 1, sizeof *pkg);
memcpy(filename, name_str.data, name_str_len);
strcpy(filename + name_str.n, ".top");
@@ -999,10 +999,8 @@ static bool types_expr(Typer *tr, Expression *e) {
return false;
}
if (!import_pkg(tr->allocr, pkg, fp, filename, tr->idents, tr->err_ctx, e->where)) {
- free(filename);
return false;
}
- free(filename);
fclose(fp);
}
} break;
@@ -1901,7 +1899,7 @@ static bool types_expr(Typer *tr, Expression *e) {
if (ident_eq_str(f->name, field_name.slice.data)) {
is_field = true;
*t = f->type;
- e->binary.field = f;
+ e->binary.dot.field = f;
}
}
if (!is_field) {
@@ -1925,6 +1923,22 @@ static bool types_expr(Typer *tr, Expression *e) {
case BINARY_DOT: {
if (!types_expr(tr, lhs)) return false;
Type *struct_type = lhs_type;
+ if (type_is_builtin(struct_type, BUILTIN_PKG)) {
+ if (rhs->kind != EXPR_IDENT) {
+ err_print(rhs->where, "Expected identifier for package access, but got %s.",
+ expr_kind_to_str(rhs->kind));
+ return false;
+ }
+ Value pkg_val;
+ if (!eval_expr(tr->evalr, lhs, &pkg_val))
+ return false;
+ e->binary.dot.pkg_ident = ident_translate(rhs->ident, &pkg_val.pkg->idents);
+ if (!type_of_ident(tr, e->where, e->binary.dot.pkg_ident, t)) {
+ return false;
+ }
+ break;
+ }
+
if (struct_type->kind == TYPE_PTR)
struct_type = struct_type->ptr;
if (rhs->kind != EXPR_IDENT) {
@@ -1940,7 +1954,7 @@ static bool types_expr(Typer *tr, Expression *e) {
if (f->name == rhs->ident) {
is_field = true;
*t = f->type;
- e->binary.field = f;
+ e->binary.dot.field = f;
}
}
}
diff --git a/types.h b/types.h
index 17e2954..2e136b4 100644
--- a/types.h
+++ b/types.h
@@ -651,7 +651,10 @@ typedef struct Expression {
BinaryOp op;
struct Expression *lhs;
struct Expression *rhs;
- Field *field; /* for . only */
+ union {
+ Field *field; /* for struct. */
+ Identifier pkg_ident; /* for Package. */
+ } dot;
} binary;
CallExpr call;
struct {