summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-02-04 14:25:48 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-02-04 14:25:48 -0500
commit75fc567dfdb4a6500990d79dc3f167d3262a96c5 (patch)
tree868f2db398c9747629e689e48b4bef9fcb84baee
parent82990fa60f657861e9f2709d68c971d08e9b513c (diff)
nms . typing and fixing cgen for local namespaces
-rw-r--r--cgen.c6
-rw-r--r--identifiers.c9
-rw-r--r--main.c1
-rw-r--r--parse.c2
-rw-r--r--scope.c6
-rw-r--r--test.toc10
-rw-r--r--types.c68
7 files changed, 60 insertions, 42 deletions
diff --git a/cgen.c b/cgen.c
index 563a15c..e33aac9 100644
--- a/cgen.c
+++ b/cgen.c
@@ -307,14 +307,16 @@ static void cgen_nms_enter(CGenerator *g, Namespace *n) {
g->nms_prefix[i+chars_so_far] = s[i];
}
*(char *)arr_add(&g->nms_prefix) = '_';
- *(char *)arr_add(&g->nms_prefix) = '_';
+ if (n->associated_ident)
+ *(char *)arr_add(&g->nms_prefix) = '_';
*(char *)arr_add(&g->nms_prefix) = '\0';
free(s);
}
static void cgen_nms_exit(CGenerator *g, Namespace *n) {
char *s = cgen_nms_prefix(g, n);
- arr_set_len(&g->nms_prefix, arr_len(g->nms_prefix) - strlen(s) - 2); /* -2 for "__" */
+ bool double_underscore = n->associated_ident != NULL;
+ arr_set_len(&g->nms_prefix, arr_len(g->nms_prefix) - strlen(s) - (double_underscore ? 2 : 1));
free(s);
}
diff --git a/identifiers.c b/identifiers.c
index 25eaea1..da1db17 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -169,8 +169,13 @@ static Identifier ident_get(Identifiers *ids, char *s) {
static Identifier ident_translate_forced(Identifier i, Identifiers *to_idents) {
if (!i || i->anonymous) return NULL;
char *p = i->str;
- Identifier new_ident = ident_insert(to_idents, &p);
- return new_ident;
+ return ident_insert(to_idents, &p);
+}
+
+/* translate but don't add it if it's not there */
+static Identifier ident_translate(Identifier i, Identifiers *to_idents) {
+ if (!i || i->anonymous) return NULL;
+ return ident_get(to_idents, i->str);
}
static IdentDecl *ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) {
diff --git a/main.c b/main.c
index d8b6094..9cd967f 100644
--- a/main.c
+++ b/main.c
@@ -20,6 +20,7 @@
TODO:
namespace
try to remember why arr_set_len doesn't shrink, then write that reason there
+nms["foo"]
make sure nms {foo:= 7; } works for cgen
make sure #export still works properly
fix cgen_ident_to_str for unicode idents
diff --git a/parse.c b/parse.c
index 8f3f393..3d923f5 100644
--- a/parse.c
+++ b/parse.c
@@ -1061,7 +1061,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
++t->token;
if (!parse_block(p, &n->body))
return false;
- n->body.flags |= BLOCK_IS_NMS;
+ /* don't set BLOCK_IS_NMS yet (done by types.c) */
arr_foreach(e->nms.body.stmts, Statement, sub) {
if (sub->kind != STMT_DECL) {
err_print(sub->where, "Only declarations can be in namespaces.");
diff --git a/scope.c b/scope.c
index 1b116b7..1f3f687 100644
--- a/scope.c
+++ b/scope.c
@@ -59,6 +59,9 @@ static void remove_ident_decls(Block *b, Declaration *d) {
/* pass NULL for block for global scope */
static bool block_enter(Block *b, Statement *stmts, U16 flags) {
+ if (b && (b->flags & BLOCK_IS_NMS)) /* we only enter namespaces once, when they're created */
+ return true;
+
bool ret = true;
arr_foreach(stmts, Statement, stmt) {
if (stmt->kind == STMT_DECL) {
@@ -71,6 +74,9 @@ static bool block_enter(Block *b, Statement *stmts, U16 flags) {
}
static void block_exit(Block *b, Statement *stmts) {
+ if (b && (b->flags & BLOCK_IS_NMS))
+ return;
+
arr_foreach(stmts, Statement, stmt) {
if (stmt->kind == STMT_DECL) {
Declaration *decl = &stmt->decl;
diff --git a/test.toc b/test.toc
index c1fa02c..206d903 100644
--- a/test.toc
+++ b/test.toc
@@ -1,8 +1,10 @@
-n :: Namespace = nms {
-f ::= fn() {};
-};
main ::= fn() {
- n.f();
+ x ::= nms {
+ f ::= fn() {
+
+ };
+ };
+ // x.g();
}; \ No newline at end of file
diff --git a/types.c b/types.c
index 80bd561..5ba03a3 100644
--- a/types.c
+++ b/types.c
@@ -2024,14 +2024,11 @@ static bool types_expr(Typer *tr, Expression *e) {
}
if (struct_type->kind == TYPE_STRUCT) {
bool is_field = false;
- if (rhs->kind == EXPR_IDENT) {
- /* maybe accessing a field? */
- 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;
- }
+ 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;
}
}
@@ -2042,30 +2039,11 @@ static bool types_expr(Typer *tr, Expression *e) {
return false;
}
} else if (struct_type->kind == TYPE_SLICE || struct_type->kind == TYPE_ARR) {
- if (!(rhs->kind == EXPR_IDENT && ident_eq_str(rhs->ident, "len"))) {
-
- Value field_name;
- if (!types_expr(tr, rhs)) return false;
- if (!type_is_slicechar(rhs_type)) {
- char *s = type_to_str(rhs_type);
- err_print(e->where, "Invalid field of type %s.", s);
- free(s);
- return false;
- }
- if (!eval_expr(tr->evalr, rhs, &field_name)) return false;
- char *str = field_name.slice.data;
- if (field_name.slice.n != 3 || strcmp(str, "len") != 0) {
- char *fstr = err_malloc((size_t)(field_name.slice.n + 1));
- memcpy(fstr, field_name.slice.data, (size_t)field_name.slice.n);
- fstr[field_name.slice.n] = 0; /* null-terminate */
- char *typestr = type_to_str(lhs_type);
- err_print(e->where, "%s is not a field of type %s.", fstr, typestr);
- free(fstr); free(typestr);
- return false;
- }
+ if (!ident_eq_str(rhs->ident, "len")) {
+ err_print(rhs->where, "Field of array or slice must be .len");
+ return false;
}
-
- /* length of slice/arr */
+ /* length of slice/arr is i64 */
t->kind = TYPE_BUILTIN;
t->builtin = BUILTIN_I64;
/* change expr to UNARY_LEN */
@@ -2073,6 +2051,20 @@ static bool types_expr(Typer *tr, Expression *e) {
Expression *of = lhs;
e->unary.op = UNARY_LEN;
e->unary.of = of;
+ } else if (type_is_builtin(struct_type, BUILTIN_NMS)) {
+ Value nms_val;
+ if (!eval_expr(tr->evalr, lhs, &nms_val))
+ return false;
+ Namespace *nms = nms_val.nms;
+ Identifier translated = ident_translate(rhs->ident, &nms->idents);
+ if (!translated) {
+ char *s = ident_to_str(rhs->ident);
+ err_print(rhs->where, "%s is not a member of this namespace.", s);
+ return false;
+ }
+ if (!type_of_ident(tr, rhs->where, translated, t)) {
+ return false;
+ }
} else {
char *s = type_to_str(lhs_type);
err_print(e->where, "Operator . applied to type %s, which is not a structure or pointer to structure.", s);
@@ -2126,7 +2118,7 @@ static bool types_expr(Typer *tr, Expression *e) {
case EXPR_NMS: {
if (!types_block(tr, &e->nms.body, TYPES_BLOCK_NAMESPACE))
return false;
- e->nms.associated_ident = NULL;
+ e->nms.associated_ident = NULL; /* set when we type the declaration */
t->kind = TYPE_BUILTIN;
t->builtin = BUILTIN_NMS;
} break;
@@ -2193,6 +2185,7 @@ static bool types_block(Typer *tr, Block *b, U16 flags) {
ret:
if (flags & TYPES_BLOCK_NAMESPACE) {
/* don't exit block because we don't want to have to re-enter each time we grab something from the namespace */
+ b->flags |= BLOCK_IS_NMS;
arr_remove_last(&tr->blocks);
tr->block = *(Block **)arr_last(tr->blocks);
} else {
@@ -2336,7 +2329,16 @@ static bool types_decl(Typer *tr, Declaration *d) {
}
}
if (n_idents == 1 && d->expr.kind == EXPR_NMS) {
- d->expr.nms.associated_ident = d->idents[0];
+ bool is_at_top_level = true;
+ typedef Block *BlockPtr;
+ arr_foreach(tr->blocks, BlockPtr, b) {
+ if (*b && !((*b)->flags & BLOCK_IS_NMS)) {
+ is_at_top_level = false;
+ break;
+ }
+ }
+ if (is_at_top_level)
+ d->expr.nms.associated_ident = d->idents[0];
}