diff options
Diffstat (limited to 'bootstrap')
-rw-r--r-- | bootstrap/ast.c | 33 | ||||
-rw-r--r-- | bootstrap/compiler.h | 14 | ||||
-rw-r--r-- | bootstrap/outdecl.c | 9 | ||||
-rw-r--r-- | bootstrap/outexpr.c | 5 | ||||
-rw-r--r-- | bootstrap/parsedecl.c | 7 | ||||
-rw-r--r-- | bootstrap/parseexpr.c | 46 | ||||
-rw-r--r-- | bootstrap/typechk.c | 19 |
7 files changed, 100 insertions, 33 deletions
diff --git a/bootstrap/ast.c b/bootstrap/ast.c index 034c11e..ee2a79e 100644 --- a/bootstrap/ast.c +++ b/bootstrap/ast.c @@ -17,7 +17,8 @@ struct Func *current_func; static struct Type **type_nextptr, **inner_type_nextptr; static struct Func **func_nextptr; static struct Func **type_func_nextptr, **innertype_func_nextptr; -static struct Var **var_nextptr; +/* TODO should constants in "utility files" be allowed? */ +/*static struct Var **var_nextptr;*/ static struct Var **type_var_nextptr, **innertype_var_nextptr; void module_start(void) @@ -26,8 +27,10 @@ void module_start(void) NO_NULL(mod); mod->types = NULL; mod->funcs = NULL; + /*mod->consts = NULL;*/ mod->types_list = NULL; mod->funcs_list = NULL; + /*mod->consts_list = NULL;*/ mod->next = modules; modules = mod; @@ -37,6 +40,7 @@ void module_start(void) type_nextptr = &module->types_list; func_nextptr = &module->funcs_list; + /*var_nextptr = &module->consts_list;*/ } struct Type *map_named_type(const char *name, size_t len) @@ -176,9 +180,34 @@ void toplevel_var_add(struct Var *var) } else if (current_type) { nextptr = &type_var_nextptr; } else { - nextptr = &var_nextptr; + /* TODO should constants in "utility files" be allowed? */ + /*nextptr = &var_nextptr;*/ + assert(0); } var->next = NULL; **nextptr = var; *nextptr = &var->next; } + +bool funcdefs_seen(void) +{ + /* TODO should constants in "utility files" be allowed? */ + /*if (!current_type) { + return module->funcs != NULL; + } else { + return current_type->funcs != NULL; + }*/ + assert(current_type != NULL); + return current_type->funcs != NULL; +} + +struct Var *lookup_instance_var(const char *name, size_t len) +{ + HashCode h; + + assert(current_type != NULL); + assert(name != NULL); + assert(len != 0); + h = hash_str(name, len); + return (struct Var *)tree_search(current_type->vars, h, len, name); +} diff --git a/bootstrap/compiler.h b/bootstrap/compiler.h index d44ab45..acce974 100644 --- a/bootstrap/compiler.h +++ b/bootstrap/compiler.h @@ -231,7 +231,8 @@ enum ExprKind { E_INTEGER, E_STRING, /* Terminals - Identifiers */ - E_IDENT, + E_LOCALVAR, + E_INSTVAR, E_MEMBER, /* Terminals - Multi-argument */ E_ARRAY, @@ -395,8 +396,17 @@ struct Func { struct Module { struct TreeNode *types; struct TreeNode *funcs; + /*struct TreeNode *consts;*/ struct Type *types_list; struct Func *funcs_list; + /* FIXME how to access these? + * could allow only local constants in utility files. + - in that case, local functions should be allowed too + * alternatively, simply disallow constants in + utility files (either in the bootstrap compiler only, + or in the language spec itself) + */ + /*struct Var *consts_list;*/ struct Module *next; }; @@ -408,6 +418,7 @@ struct Func *map_named_func(const char *name, size_t len); void func_start(const char *name, size_t len); void func_end(void); void toplevel_var_add(struct Var *var); +bool funcdefs_seen(void); void srcloc_init(struct SourceLocation *srcloc); /* ======================================================================= @@ -438,6 +449,7 @@ void parse_func_body(void); struct Expr *parse_expr(void); struct Var *parse_var(struct TreeNode **root, enum VarType vartype); struct Var *lookup_local_var(const char *name, size_t len); +struct Var *lookup_instance_var(const char *name, size_t len); /** Reports an error in the source code and exits */ NORETURN void error(const char *s); /** Reports a warning in the source code (doesn't exit) */ diff --git a/bootstrap/outdecl.c b/bootstrap/outdecl.c index 138464b..5da2fe6 100644 --- a/bootstrap/outdecl.c +++ b/bootstrap/outdecl.c @@ -78,9 +78,16 @@ static void emit_func_decl(struct Func *func, bool is_pre_decl) emit_func_ident(func); } outc('('); - if (func->num_params == 0) { + if (func->num_params == 0 && !func->class_) { outf("void"); } else { + if (func->class_) { + emit_type(func->class_); + outf(" *this"); + if (func->num_params != 0) { + outf(", "); + } + } emit_param_list(func->params); } outc(')'); diff --git a/bootstrap/outexpr.c b/bootstrap/outexpr.c index 2ce2a51..7935f6a 100644 --- a/bootstrap/outexpr.c +++ b/bootstrap/outexpr.c @@ -236,7 +236,10 @@ void emit_expr(const struct TypeRef *typeref, outf("((const struct String *)&strconst__%u)", expr->u.strval->id); break; /* Terminals - Identifiers */ - case E_IDENT: { + case E_INSTVAR: + outf("this->"); + /* Fall through */ + case E_LOCALVAR: { const struct TreeNode *ident; assert(expr->u.ident.namelen == 0); ident = &expr->u.ident.u.var->ident.node; diff --git a/bootstrap/parsedecl.c b/bootstrap/parsedecl.c index 29cb2dd..402c261 100644 --- a/bootstrap/parsedecl.c +++ b/bootstrap/parsedecl.c @@ -354,6 +354,13 @@ void parse_file(FILE *f, const char *basename) case T_KW_long: case T_UpperIdent: /* Instance variable definition */ + if (current_type == NULL) { + error("Variables/constants are only allowed in classes " + "(e.g. A.slul but not a.slul)"); + } + if (funcdefs_seen()) { + error("Variables must come before function definitions"); + } /* TODO disallow modifiable variables (or variables of modifiable types) inside non-class (utility) files */ unread_token(); diff --git a/bootstrap/parseexpr.c b/bootstrap/parseexpr.c index db00366..870c7d1 100644 --- a/bootstrap/parseexpr.c +++ b/bootstrap/parseexpr.c @@ -63,7 +63,8 @@ static const struct OpInfo opinfo[NUM_EXPRKINDS] = { /* E_TRUE */ { 0, 0, 0, 0 }, /* E_INTEGER */ { 0, 0, 0, 0 }, /* E_STRING */ { 0, 0, 0, 0 }, - /* E_IDENT */ { 0, 0, 0, 0 }, + /* E_LOCALVAR */ { 0, 0, 0, 0 }, + /* E_INSTVAR */ { 0, 0, 0, 0 }, /* E_MEMBER */ { 0, 0, 0, 0 }, /* E_ARRAY */ { 0, 0, 0, 0 }, /* E_CALL */ { 0, 0, 0, 0 }, @@ -198,27 +199,36 @@ struct Expr *parse_expr(void) e->u.strval = str; break; } case T_LowerIdent: { + struct ExprCall *call; struct Var *var = lookup_local_var(li.string, li.len); - if (!var) { - /* Assume it's a function call */ - struct ExprCall *call = malloc(sizeof(struct ExprCall)); - NO_NULL(call); - call->ident.namelen = li.len; - call->ident.u.name = dupmemz(li.string, li.len); - call->args = NULL; - call->nextptr = &call->args; - e->kind = E_CALL; - e->u.call = call; - e->rpnnext = opstack; - opstack = e; - operator_expected = false; - goto token_processed; - } else { - e->kind = E_IDENT; + if (var) { + e->kind = E_LOCALVAR; e->u.ident.namelen = 0; e->u.ident.u.var = var; + break; } - break; } + if (current_type) { + var = lookup_instance_var(li.string, li.len); + if (var) { + e->kind = E_INSTVAR; + e->u.ident.namelen = 0; + e->u.ident.u.var = var; + break; + } + } + /* Assume it's a function call */ + call = malloc(sizeof(struct ExprCall)); + NO_NULL(call); + call->ident.namelen = li.len; + call->ident.u.name = dupmemz(li.string, li.len); + call->args = NULL; + call->nextptr = &call->args; + e->kind = E_CALL; + e->u.call = call; + e->rpnnext = opstack; + opstack = e; + operator_expected = false; + goto token_processed; } /* Unary prefix operators */ case T_SYM_Minus: if (opstack && opstack->kind == E_CALL) { diff --git a/bootstrap/typechk.c b/bootstrap/typechk.c index ad6ef30..037662f 100644 --- a/bootstrap/typechk.c +++ b/bootstrap/typechk.c @@ -101,7 +101,7 @@ static void require_type(const struct Expr *expr, enum TypeRefKind kind, assert(expr->typeref != NULL); if (expr->typeref->kind == TR_UNKNOWN) { /* TODO TR_UNKNOWN means unimplemented. - E_IDENT...E_CALL are unimplemented */ + E_MEMBER/E_ARRAY are unimplemented */ return; } if (expr->typeref->kind != kind) { @@ -369,15 +369,14 @@ void typecheck_expr(const struct TypeRef *typeref, struct Expr *expr) tr.quals = 0; /* TODO set qualifiers */ tr.u.class_ = &builtin_string_class; break; - case E_IDENT: - if (e->u.ident.namelen != 0) { - tr = funccall_check(e); - } else { - struct Var *var = e->u.ident.u.var; - /* TODO varstate tracking */ - tr = *var->typeref; - } - break; + case E_LOCALVAR: + case E_INSTVAR: { + struct Var *var; + assert(e->u.ident.namelen == 0); /* already bound */ + var = e->u.ident.u.var; + /* TODO varstate tracking */ + tr = *var->typeref; + break; } case E_MEMBER: case E_ARRAY: /* TODO implement these. the code below just sets a dummy type */ |