aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyze.c240
-rw-r--r--src/ast.c16
-rw-r--r--src/debug.c10
-rw-r--r--src/lower.c221
-rw-r--r--src/move.c51
-rw-r--r--src/parser.y48
6 files changed, 441 insertions, 145 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) {
diff --git a/src/ast.c b/src/ast.c
index f8b3447..9515775 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -215,11 +215,12 @@ void ast_dump(int depth, struct ast *n)
DUMP(AST_IF);
DUMP(AST_NIL);
DUMP(AST_LET);
+ DUMP(AST_PUT);
+ DUMP(AST_WRITE);
DUMP(AST_INIT);
DUMP(AST_CALL);
DUMP(AST_PROC_DEF);
DUMP(AST_VAR_DEF);
- DUMP(AST_DOT);
DUMP(AST_BLOCK);
DUMP(AST_ID);
DUMP(AST_EMPTY);
@@ -247,10 +248,11 @@ void ast_dump(int depth, struct ast *n)
DUMP(AST_BNEG);
DUMP(AST_SIZEOF);
DUMP(AST_AS);
- DUMP(AST_ARR);
- DUMP(AST_ASSIGN);
DUMP(AST_CONSTRUCTION);
DUMP(AST_CONSTRUCT);
+ DUMP(AST_DECONSTRUCTION);
+ DUMP(AST_DECONSTRUCT);
+ DUMP(AST_EXPLODE);
DUMP(AST_SELF);
DUMP(AST_FORGET);
DUMP(AST_PASTE);
@@ -661,11 +663,12 @@ const char *ast_str(enum ast_kind k)
CASE(AST_IF);
CASE(AST_NIL);
CASE(AST_LET);
+ CASE(AST_PUT);
+ CASE(AST_WRITE);
CASE(AST_INIT);
CASE(AST_CALL);
CASE(AST_PROC_DEF);
CASE(AST_VAR_DEF);
- CASE(AST_DOT);
CASE(AST_BLOCK);
CASE(AST_ID);
CASE(AST_EMPTY);
@@ -693,8 +696,6 @@ const char *ast_str(enum ast_kind k)
CASE(AST_BNEG);
CASE(AST_SIZEOF);
CASE(AST_AS);
- CASE(AST_ARR);
- CASE(AST_ASSIGN);
CASE(AST_CONSTRUCTION);
CASE(AST_CONSTRUCT);
CASE(AST_SELF);
@@ -710,6 +711,9 @@ const char *ast_str(enum ast_kind k)
CASE(AST_CONST_BOOL);
CASE(AST_CONST_FLOAT);
CASE(AST_CONST_STR);
+ CASE(AST_DECONSTRUCT);
+ CASE(AST_DECONSTRUCTION);
+ CASE(AST_EXPLODE);
}
#undef CASE
diff --git a/src/debug.c b/src/debug.c
index 8ef4293..538fdfe 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -222,6 +222,10 @@ static void _type_str(FILE *f, struct type *type)
fprintf(f, "u64");
break;
+ case TYPE_BOOL:
+ fprintf(f, "bool");
+ break;
+
case TYPE_VOID:
fprintf(f, "void");
break;
@@ -230,12 +234,6 @@ static void _type_str(FILE *f, struct type *type)
fprintf(f, "nil");
break;
- case TYPE_ARR:
- /** @todo length? */
- fprintf(f, "[]");
- _type_list_str(f, tarr_base(type));
- break;
-
case TYPE_PTR:
fprintf(f, "*");
_type_list_str(f, tptr_base(type));
diff --git a/src/lower.c b/src/lower.c
index e29365d..9689928 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -27,7 +27,11 @@
static inline void mangle(FILE *f, struct ast *id)
{
- assert(id->k == AST_PROC_DEF || id->k == AST_VAR_DEF || id->k == AST_ID);
+ assert(id->k == AST_STRUCT_DEF
+ || id->k == AST_PROC_DEF
+ || id->k == AST_VAR_DEF
+ || id->k == AST_ID);
+
assert(id->s && id->scope);
fprintf(f, "%s_s%zu", id->s, id->scope->number);
}
@@ -150,6 +154,12 @@ static void add_defn(struct state *state, char *defn)
string_vec_append(state->defns, defn);
}
+static bool type_lowered(struct ast *type)
+{
+ assert(type->k == AST_STRUCT_DEF);
+ return ast_flags(type, AST_FLAG_LOWERED);
+}
+
static void add_type(struct state *state, char *type)
{
string_vec_append(state->types, type);
@@ -160,8 +170,10 @@ static int lower_block(struct state *state, struct ast *block, bool last);
static int lower_params(struct state *state, struct ast *params);
static int lower_expr(struct state *state, struct ast *expr);
static int lower_proc(struct state *state, struct ast *proc);
+static int lower_type_def(struct state *state, struct ast *type);
+static char *lower_type_str(struct state *state, struct scope *scope, struct type *type);
-static void _type_str(FILE *f, struct type *type)
+static int _type_str(FILE *f, struct state *state, struct scope *scope, struct type *type)
{
assert(type);
switch (type->k) {
@@ -201,14 +213,40 @@ static void _type_str(FILE *f, struct type *type)
fprintf(f, "fwd_closure_t");
break;
+ case TYPE_PURE_CLOSURE:
+ fprintf(f, "fwd_closure_t");
+ break;
+
+ case TYPE_ID: {
+ struct ast *def = file_scope_find_type(scope, type_str(type));
+
+ if (!ast_flags(def, AST_FLAG_LOWERED))
+ if (lower_type_def(state, def))
+ return -1;
+
+ char *name = mangle2(def);
+ fprintf(f, "%s", name);
+ free(name);
+ break;
+ }
+
+ case TYPE_PTR: {
+ char *rest = lower_type_str(state, scope, tptr_base(type));
+ fprintf(f, "%s*", rest);
+ free(rest);
+ break;
+ }
+
default:
internal_error("unhandled type lowering for %s", type_str(type));
abort();
break;
}
+
+ return 0;
}
-static char *lower_type_str(struct type *type)
+static char *lower_type_str(struct state *state, struct scope *scope, struct type *type)
{
assert(type);
@@ -216,9 +254,15 @@ static char *lower_type_str(struct type *type)
FILE *f = open_memstream(&type_buf, &type_len);
assert(f);
- _type_str(f, type);
+ int r = _type_str(f, state, scope, type);
fclose(f);
assert(type_buf);
+
+ if (r) {
+ free(type_buf);
+ return NULL;
+ }
+
return type_buf;
}
@@ -243,7 +287,7 @@ static int lower_closure_call(struct state *state, struct ast *call, struct ast
foreach_node(a, call_args(call)) {
returning |= a->k == AST_CLOSURE;
- char *type = lower_type_str(a->t);
+ char *type = lower_type_str(state, a->scope, a->t);
fprintf(ctx, " %s a%zu;\n", type, idx);
free(type);
@@ -269,7 +313,7 @@ out:
q, q);
}
else {
- fprintf(state->code, "stack = %s_call(stack, %s_ctx);\n",
+ fprintf(state->code, "stack = %s(stack, %s_ctx);\n",
q, q);
}
@@ -340,10 +384,26 @@ static int lower_comparison(struct state *state, struct ast *expr)
fprintf(state->code, " <= ");
break;
+ case AST_GE:
+ fprintf(state->code, " >= ");
+ break;
+
case AST_LT:
fprintf(state->code, " < ");
break;
+ case AST_GT:
+ fprintf(state->code, " > ");
+ break;
+
+ case AST_EQ:
+ fprintf(state->code, " == ");
+ break;
+
+ case AST_NE:
+ fprintf(state->code, " != ");
+ break;
+
default:
internal_error("unhandled lowering for comparison %s", ast_str(expr->k));
abort();
@@ -366,8 +426,12 @@ static int lower_binop(struct state *state, struct ast *expr)
fprintf(state->code, " + ");
break;
+ case AST_MUL:
+ fprintf(state->code, " * ");
+ break;
+
default:
- internal_error("unhandled comparison %s", ast_str(expr->k));
+ internal_error("unhandled binop %s", ast_str(expr->k));
abort();
}
@@ -406,6 +470,41 @@ static int lower_expr(struct state *state, struct ast *expr)
fprintf(state->code, "%lld", (long long)int_val(expr));
break;
}
+
+ case AST_NIL: {
+ fprintf(state->code, "NULL");
+ break;
+ }
+
+ case AST_CONSTRUCT: {
+ char *name = lower_type_str(state, expr->scope, expr->t);
+ fprintf(state->code, "(%s){", name);
+ free(name);
+
+ foreach_node(n, construct_members(expr)) {
+ fprintf(state->code, ".%s = ", construction_id(n));
+
+ if (lower_expr(state, construction_expr(n)))
+ return -1;
+
+ fprintf(state->code, ", ");
+ }
+ fprintf(state->code, "}");
+ break;
+ }
+
+ case AST_AS: {
+ char *name = lower_type_str(state, expr->scope, expr->t);
+ fprintf(state->code, "(%s)(", name);
+ free(name);
+
+ if (lower_expr(state, as_expr(expr)))
+ return -1;
+
+ fprintf(state->code, ")");
+ break;
+ }
+
default:
internal_error("unhandled expr lowering: %s", ast_str(expr->k));
abort();
@@ -445,7 +544,7 @@ static int lower_call(struct state *state, struct ast *call, bool last)
foreach_node(a, call_args(call)) {
returning |= a->k == AST_CLOSURE;
- char *type = lower_type_str(a->t);
+ char *type = lower_type_str(state, a->scope, a->t);
fprintf(ctx, " %s a%zu;\n", type, idx);
free(type);
@@ -508,11 +607,72 @@ static int lower_if(struct state *state, struct ast *stmt, bool last)
return lower_block(state, if_else(stmt), last);
}
+static int lower_explode(struct state *state, struct ast *stmt, bool last)
+{
+ /* not significant to us */
+ (void)last;
+
+ int u = uniq(state);
+ struct ast *expr = explode_expr(stmt);
+
+ char *type = lower_type_str(state, expr->scope, expr->t);
+
+ indent(state);
+ fprintf(state->code, "%s explode_%d = ", type, u);
+ free(type);
+
+ if (lower_expr(state, expr))
+ return -1;
+
+ fprintf(state->code, ";\n");
+
+ foreach_node(node, explode_deconstruct(stmt)) {
+ struct ast *var = deconstruction_var(node);
+
+ char *type = lower_type_str(state, var->scope, var->t);
+ char *name = mangle2(var);
+
+ indent(state);
+ fprintf(state->code, "%s %s = explode_%d.%s;\n",
+ type, name, u, deconstruction_id(node));
+
+ free(type);
+ free(name);
+ }
+
+ return 0;
+}
+
+static int lower_let(struct state *state, struct ast *stmt, bool last)
+{
+ /* not relevant */
+ (void)last;
+
+ struct ast *var = let_var(stmt);
+ char *type = lower_type_str(state, var->scope, var->t);
+ char *name = mangle2(var);
+
+ indent(state);
+ fprintf(state->code, "%s %s = ", type, name);
+
+ free(type);
+ free(name);
+
+ if (lower_expr(state, let_expr(stmt)))
+ return -1;
+
+ fprintf(state->code, ";\n");
+ return 0;
+}
+
static int lower_stmt(struct state *state, struct ast *stmt, bool last)
{
switch (stmt->k) {
case AST_CALL: return lower_call(state, stmt, last);
case AST_IF: return lower_if(state, stmt, last);
+ case AST_EXPLODE: return lower_explode(state, stmt, last);
+ case AST_LET: return lower_let(state, stmt, last);
+ case AST_EMPTY: break;
default:
internal_error("unhandled statement kind %s", ast_str(stmt->k));
abort();
@@ -548,7 +708,7 @@ static int lower_block(struct state *state, struct ast *block, bool last)
static int lower_param(struct state *state, struct ast *param)
{
- char *type = lower_type_str(param->t);
+ char *type = lower_type_str(state, param->scope, param->t);
char *name = mangle2(param);
fprintf(state->ctx, " %s %s;\n", type, name);
@@ -644,7 +804,7 @@ static int lower_extern_proc(struct state *state, struct ast *proc)
idx + 1, fwd_typeid(p->t), fwd_typeparam(p->t), idx);
- char *type_str = lower_type_str(p->t);
+ char *type_str = lower_type_str(state, p->scope, p->t);
fprintf(new_state.ctx, " %s a%zu;\n", type_str, idx);
free(type_str);
idx++;
@@ -679,7 +839,7 @@ static int lower_extern_proc(struct state *state, struct ast *proc)
static int lower_param_copy(struct state *state, struct ast *param, FILE *f, size_t idx)
{
- char *type = lower_type_str(param->t);
+ char *type = lower_type_str(state, param->scope, param->t);
fprintf(f, " %s a%zu;\n", type, idx);
free(type);
@@ -716,6 +876,45 @@ static int lower_param_copies(struct state *state, struct ast *params)
return 0;
}
+static int lower_type_def(struct state *state, struct ast *type)
+{
+ assert(type->k == AST_STRUCT_DEF);
+ if (type_lowered(type))
+ return 0;
+
+ ast_flags(type, AST_FLAG_LOWERED);
+
+ char *decl_buf = NULL; size_t decl_len = 0;
+ FILE *decl = open_memstream(&decl_buf, &decl_len);
+ assert(decl);
+
+ char *name = mangle2(type);
+ fprintf(decl, "struct %s;\n", name);
+ fclose(decl);
+
+ char *defn_buf = NULL; size_t defn_len = 0;
+ FILE *defn = open_memstream(&defn_buf, &defn_len);
+ assert(defn);
+
+ fprintf(defn, "typedef struct %s {\n", name);
+
+ foreach_node(n, struct_body(type)) {
+ assert(n->k == AST_VAR_DEF);
+ char *t = lower_type_str(state, n->scope, var_type(n));
+ fprintf(defn, "\t%s %s;\n", t, var_id(n));
+ free(t);
+ }
+
+ fprintf(defn, "} %s;\n", name);
+
+ fclose(defn);
+ free(name);
+
+ add_type(state, decl_buf);
+ add_type(state, defn_buf);
+ return 0;
+}
+
static int lower_proc(struct state *state, struct ast *proc)
{
if (proc_lowered(state, proc))
diff --git a/src/move.c b/src/move.c
index 9e8cfa0..2a55d3d 100644
--- a/src/move.c
+++ b/src/move.c
@@ -418,6 +418,7 @@ static int mvcheck_if(struct state *state, struct ast *node)
return -1;
}
+ if (if_else(node))
if (mvcheck(&else_state, if_else(node))) {
destroy_state(&body_state);
destroy_state(&else_state);
@@ -480,6 +481,46 @@ static int mvcheck_statements(struct state *state, struct ast *nodes)
return 0;
}
+static int mvcheck_construct(struct state *state, struct ast *node)
+{
+ foreach_node(expr, construct_members(node)) {
+ if (mvcheck(state, expr))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mvcheck_construction(struct state *state, struct ast *node)
+{
+ return mvcheck(state, construction_expr(node));
+}
+
+static int mvcheck_as(struct state *state, struct ast *as)
+{
+ return mvcheck(state, as_expr(as));
+}
+
+static int mvcheck_forget(struct state *state, struct ast *node)
+{
+ struct ast *def = file_scope_find_symbol(node->scope, forget_id(node));
+ assert(def);
+
+ /* act as if a move has happened */
+ insert_move(state, def, node);
+ return 0;
+}
+
+static int mvcheck_explode(struct state *state, struct ast *node)
+{
+ return mvcheck(state, explode_expr(node));
+}
+
+static int mvcheck_write(struct state *state, struct ast *node)
+{
+ return mvcheck(state, write_src(node));
+}
+
static int mvcheck(struct state *state, struct ast *node)
{
if (is_unop(node))
@@ -502,12 +543,22 @@ static int mvcheck(struct state *state, struct ast *node)
case AST_IF: return mvcheck_if (state, node);
case AST_REF: return mvcheck_ref (state, node);
case AST_DEREF: return mvcheck_deref (state, node);
+ case AST_CONSTRUCT: return mvcheck_construct (state, node);
+ case AST_AS: return mvcheck_as (state, node);
+ case AST_FORGET: return mvcheck_forget (state, node);
+ case AST_EXPLODE: return mvcheck_explode (state, node);
+ case AST_WRITE: return mvcheck_write (state, node);
+ case AST_CONSTRUCTION: return mvcheck_construction(state, node);
+ case AST_NIL_CHECK:
+ case AST_SIZEOF:
+ case AST_STRUCT_DEF:
case AST_EMPTY:
case AST_IMPORT:
case AST_CONST_INT:
case AST_CONST_STR:
case AST_CONST_FLOAT:
case AST_CONST_CHAR:
+ case AST_NIL:
return 0;
default: break;
}
diff --git a/src/parser.y b/src/parser.y
index 023c10a..9607e71 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -101,7 +101,7 @@
%nterm <node> exprs statements closures trailing_closure
%nterm <node> opt_exprs opt_statements opt_trailing_closure
%nterm <node> rev_exprs rev_closures rev_statements
-%nterm <node> let if nil unop binop construct import
+%nterm <node> let put if nil unop binop construct import
%nterm <node> opt_vars vars rev_vars var
%nterm <node> opt_params params rev_params param
@@ -113,12 +113,12 @@
%nterm <node> opt_elements elements rev_elements element
%nterm <node> instance template supertemplate
%nterm <node> opt_constructions constructions construction
-%nterm <node> id impl forget assign
+%nterm <node> opt_deconstructions deconstructions deconstruction
+%nterm <node> id impl forget
+%nterm <node> explode
%nterm <type> type rev_types types opt_types
-
-
%{
/** Modifies the signature of yylex to fit our parser better. */
@@ -262,10 +262,6 @@ unop
type
: ID { $$ = tgen_id($1, src_loc(@$)); }
| "(" opt_types ")" { $$ = tgen_closure($2, src_loc(@$)); }
- | "[" "]" type {
- /* TODO static sizes? */
- $$ = tgen_arr($3, NULL, src_loc(@$));
- }
| "&&" type {
if ($2->k == TYPE_CLOSURE) {
$$ = $2; $$->k = TYPE_PURE_CLOSURE;
@@ -315,8 +311,21 @@ opt_constructions
: constructions
| { $$ = NULL; }
+deconstruction
+ : ID "=>" var {
+ $$ = gen_deconstruction($1, $3, src_loc(@$));
+ }
+
+deconstructions
+ : deconstructions "," deconstruction { $$ = $3; $$->n = $1; }
+ | deconstruction
+
+opt_deconstructions
+ : deconstructions
+ | { $$ = NULL; }
+
construct
- : "(" opt_constructions ")" ID {
+ : "[" opt_constructions "]" ID {
$$ = gen_construct($4, $2, src_loc(@$));
}
@@ -325,8 +334,6 @@ id
expr
: "sizeof" "(" type ")" { $$ = gen_sizeof($3, src_loc(@$)); }
- | expr "." ID { $$ = gen_dot($3, $1, src_loc(@$)); }
- | expr "[" expr "]" { $$ = gen_arr($1, $3, src_loc(@$)); }
| STRING { $$ = gen_const_str(strip($1), src_loc(@$)); }
| FLOAT { $$ = gen_const_float($1, src_loc(@$)); }
| BOOL { $$ = gen_const_bool($1, src_loc(@$)); }
@@ -403,8 +410,18 @@ call
$$ = gen_call($[expr], $[opt_exprs], src_loc(@$));
}
+put
+ : put "*" { $$ = gen_put($1, src_loc(@$)); }
+ | id "*" { $$ = gen_put($1, src_loc(@$)); }
+
let
: expr "=>" var ";" { $$ = gen_let($3, $1, src_loc(@$)); }
+ | expr "=>" put ";" { $$ = gen_write($3, $1, src_loc(@$)); }
+
+explode
+ : expr "=>" "[" opt_deconstructions "]" {
+ $$ = gen_explode($4, $1, src_loc(@$));
+ }
if
: "if" expr body { $$ = gen_if($2, $3, NULL, src_loc(@$)); }
@@ -413,6 +430,8 @@ if
nil
: "nil" expr body "=>" var ";" {
+ /** @todo should nil check define new scope for created
+ * variable? */
$$ = gen_nil_check($2, $3, $5, src_loc(@$));
}
@@ -421,16 +440,11 @@ forget
$$ = gen_forget($2, src_loc(@$));
}
-assign
- : expr "=" expr ";" {
- $$ = gen_assign($1, $3, src_loc(@$));
- }
-
statement
: call
| forget
- | assign
| body
+ | explode
| let
| nil
| if