aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analyze.c')
-rw-r--r--src/analyze.c240
1 files changed, 135 insertions, 105 deletions
diff --git a/src/analyze.c b/src/analyze.c
index 4f98ac6..2dc039a 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -106,6 +106,19 @@ static int analyze_binop(struct state *state, struct scope *scope,
if (analyze(state, scope, rhs))
return -1;
+ /* allow pointer arithmetic, follows C conventions */
+ if (node->k == AST_ADD || node->k == AST_SUB) {
+ if (is_ptr_type(lhs->t->k) && is_int_type(rhs->t->k)) {
+ node->t = lhs->t;
+ return 0;
+ }
+
+ if (is_ptr_type(rhs->t->k) && is_int_type(lhs->t->k)) {
+ node->t = rhs->t;
+ return 0;
+ }
+ }
+
if (!types_match(lhs->t, rhs->t)) {
type_mismatch(scope, node, lhs->t, rhs->t);
@@ -135,17 +148,9 @@ static int analyze_comparison(struct state *state, struct scope *scope,
return -1;
}
- /** @todo check type is some primitive */
- char *tf = strdup("bool");
- if (!tf) {
- internal_error("failed allocating comparison bool str");
- return -1;
- }
-
- node->t = tgen_id(tf, node->loc);
+ node->t = tgen_type(TYPE_BOOL, NULL, NULL, node->loc);
if (!node->t) {
internal_error("failed allocating comparison bool type");
- free(tf);
return -1;
}
@@ -190,10 +195,14 @@ static int analyze_var(struct state *state, struct scope *scope,
static int analyze_let(struct state *state, struct scope *scope,
struct ast *node)
{
- if (analyze(state, scope, let_var(node)))
+ if (analyze(state, scope, let_expr(node)))
return -1;
- if (analyze(state, scope, let_expr(node)))
+ struct ast *var = let_var(node);
+ if (!(var_type(var)))
+ var_type(var) = (let_expr(node))->t;
+
+ if (analyze(state, scope, var))
return -1;
struct type *l = (let_var(node))->t;
@@ -232,7 +241,11 @@ static int deduce_closure_types(struct scope *scope, struct ast *node, struct ty
}
struct ast *param = closure_bindings(node);
- struct type *t = tclosure_args(type);
+ struct type *t = (type->k == TYPE_CLOSURE)
+ ? tclosure_args(type)
+ : tpure_closure_args(type)
+ ;
+
if (ast_list_len(param) != type_list_len(t)) {
semantic_error(scope, node, "expected %zu closure parameters, got %zu",
type_list_len(t), ast_list_len(param));
@@ -535,7 +548,7 @@ static int analyze_construct(struct state *state, struct scope *scope, struct as
{
struct ast *def = file_scope_find_type(scope, construct_id(node));
if (!def) {
- semantic_error(scope, node, "no such type");
+ semantic_error(scope, node, "no such type: %s", construct_id(node));
return -1;
}
@@ -578,6 +591,69 @@ static int analyze_construct(struct state *state, struct scope *scope, struct as
return 0;
}
+static int analyze_explode(struct state *state, struct scope *scope, struct ast *node)
+{
+ if (analyze(state, scope, explode_expr(node)))
+ return -1;
+
+ struct type *type = (explode_expr(node))->t;
+ if (type->k != TYPE_ID) {
+ char *str = type_str(type);
+ semantic_error(scope, explode_expr(node),
+ "expected struct type, got %s\n",
+ str);
+ free(str);
+ return -1;
+ }
+
+ struct ast *def = file_scope_find_type(scope, type->id);
+ if (!def || def->k != AST_STRUCT_DEF) {
+ semantic_error(scope, explode_expr(node),
+ "no such struct type: %s\n",
+ type->id);
+ return -1;
+ }
+
+ struct ast *params = struct_body(def);
+ struct ast *args = explode_deconstruct(node);
+
+ if (ast_list_len(params) != ast_list_len(args)) {
+ semantic_error(scope, node, "expected %zu args, got %zu\n",
+ ast_list_len(params), ast_list_len(args));
+ return -1;
+ }
+
+ foreach_node(arg, args) {
+ struct ast *var = deconstruction_var(arg);
+ struct ast *exists = scope_find_symbol(def->scope, deconstruction_id(arg));
+ if (!exists) {
+ semantic_error(scope, arg, "no member %s in %s\n",
+ deconstruction_id(arg), type->id);
+ return -1;
+ }
+
+ if (!var_type(var))
+ (var_type(var)) = exists->t;
+
+ if (analyze(state, scope, var))
+ return -1;
+
+ if (!types_match(exists->t, var->t)) {
+ type_mismatch(scope, arg, exists->t, var->t);
+ return -1;
+ }
+
+ if (scope_add_symbol(scope, var))
+ return -1;
+
+ /** @todo check for duplicates, preferably not in O(n^2) or with
+ * a memory allocation? */
+ }
+
+ node->t = tgen_void(node->loc);
+ return 0;
+}
+
static int analyze_if(struct state *state, struct scope *scope,
struct ast *node)
{
@@ -661,66 +737,6 @@ static int analyze_as(struct state *state, struct scope *scope, struct ast *node
return 0;
}
-static int analyze_assign(struct state *state, struct scope *scope, struct ast *node)
-{
- struct ast *expr = assign_expr(node);
- if (analyze(state, scope, expr))
- return -1;
-
- struct ast *target = assign_target(node);
- if (analyze(state, scope, target))
- return -1;
-
-
- if (!types_match(expr->t, target->t)) {
- type_mismatch(scope, node, target->t, expr->t);
- return -1;
- }
-
- if (!is_lvalue(target)) {
- semantic_error(scope, target, "not an lvalue");
- return -1;
- }
-
- node->t = target->t;
- return 0;
-}
-
-static int analyze_dot(struct state *state, struct scope *scope, struct ast *node)
-{
- struct ast *expr = dot_expr(node);
- if (analyze(state, scope, expr))
- return -1;
-
- struct type *type = expr->t;
- if (type->k != TYPE_ID) {
- char *s = type_str(type);
- semantic_error(scope, node, "type %s does not have any members", s);
- free(s);
- return -1;
- }
-
- struct ast *def = file_scope_find_type(scope, tid_str(type));
- if (!def) {
- semantic_error(scope, node, "no such type: %s", tid_str(type));
- return -1;
- }
-
- if (def->k != AST_STRUCT_DEF) {
- semantic_error(scope, node, "not a struct type: %s", tid_str(type));
- return -1;
- }
-
- struct ast *member = scope_find_symbol(def->scope, dot_id(node));
- if (!member) {
- semantic_error(scope, node, "no such member: %s", dot_id(node));
- return -1;
- }
-
- node->t = member->t;
- return 0;
-}
-
static int analyze_sizeof(struct state *state, struct scope *scope, struct ast *node)
{
if (analyze_type(state, scope, sizeof_type(node)))
@@ -731,34 +747,6 @@ static int analyze_sizeof(struct state *state, struct scope *scope, struct ast *
return 0;
}
-static int analyze_arr(struct state *state, struct scope *scope, struct ast *node)
-{
- struct ast *base = arr_base(node);
- if (analyze(state, scope, base))
- return -1;
-
- if (base->t->k != TYPE_ARR) {
- char *s = type_str(base->t);
- semantic_error(scope, base, "expected array type, got %s", s);
- free(s);
- return -1;
- }
-
- struct ast *idx = arr_idx(node);
- if (analyze(state, scope, idx))
- return -1;
-
- if (!is_int_type(idx->t->k)) {
- char *s = type_str(idx->t);
- semantic_error(scope, idx, "expected int type, got %s", s);
- free(s);
- return -1;
- }
-
- node->t = tarr_base(base->t);
- return 0;
-}
-
static int analyze_nil_check(struct state *state, struct scope *scope, struct ast *node)
{
struct ast *expr = nil_check_expr(node);
@@ -805,6 +793,43 @@ static int analyze_forget(struct state *state, struct scope *scope, struct ast *
return 0;
}
+static int analyze_put(struct state *state, struct scope *scope, struct ast *put)
+{
+ struct ast *dst = put_dst(put);
+ if (analyze(state, scope, dst))
+ return -1;
+
+ struct type *type = dst->t;
+ if (type->k != TYPE_REF) {
+ char *str = type_str(type);
+ semantic_error(scope, put, "trying to write to non-ref type %s\n", str);
+ free(str);
+ return -1;
+ }
+
+ put->t = tref_base(type);
+ return 0;
+}
+
+static int analyze_write(struct state *state, struct scope *scope, struct ast *write)
+{
+ struct ast *src = write_src(write);
+ if (analyze(state, scope, src))
+ return -1;
+
+ struct ast *dst = write_dst(write);
+ if (analyze(state, scope, dst))
+ return -1;
+
+ if (!types_match(src->t, dst->t)) {
+ type_mismatch(scope, write, src->t, dst->t);
+ return -1;
+ }
+
+ write->t = tgen_void(write->loc);
+ return 0;
+}
+
static int analyze(struct state *state, struct scope *scope, struct ast *node)
{
if (!node)
@@ -864,14 +889,14 @@ static int analyze(struct state *state, struct scope *scope, struct ast *node)
case AST_STRUCT_DEF: ret = analyze_struct(state, scope, node); break;
case AST_CONSTRUCT: ret = analyze_construct(state, scope, node); break;
+ case AST_EXPLODE: ret = analyze_explode(state, scope, node); break;
case AST_SIZEOF: ret = analyze_sizeof(state, scope, node); break;
case AST_NIL: ret = analyze_nil(state, scope, node); break;
case AST_AS: ret = analyze_as(state, scope, node); break;
- case AST_ASSIGN: ret = analyze_assign(state, scope, node); break;
- case AST_ARR: ret = analyze_arr(state, scope, node); break;
- case AST_DOT: ret = analyze_dot(state, scope, node); break;
+ case AST_WRITE: ret = analyze_write(state, scope, node); break;
+ case AST_PUT: ret = analyze_put(state, scope, node); break;
case AST_FORGET: ret = analyze_forget(state, scope, node); break;
@@ -919,7 +944,7 @@ static int analyze_list(struct state *state, struct scope *scope,
static int analyze_type(struct state *state, struct scope *scope,
struct type *type)
{
- if (type->t0 && analyze_type(state, scope, type->t0))
+ if (type->t0 && analyze_type_list(state, scope, type->t0))
return -1;
/* temporary */
@@ -969,6 +994,11 @@ static int analyze_type(struct state *state, struct scope *scope,
return 0;
}
+ if (strcmp(id, "bool") == 0) {
+ type->k = TYPE_BOOL;
+ return 0;
+ }
+
/* check for user-defined types */
struct ast *def = file_scope_find_type(scope, id);
if (!def) {