aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/ast.c33
-rw-r--r--bootstrap/compiler.h14
-rw-r--r--bootstrap/outdecl.c9
-rw-r--r--bootstrap/outexpr.c5
-rw-r--r--bootstrap/parsedecl.c7
-rw-r--r--bootstrap/parseexpr.c46
-rw-r--r--bootstrap/typechk.c19
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 */