commit 440f489eb0b70733552aad5d2c3a4dc0421cdffc
parent 3f1e08ba7ad9bc236a8fcdf5573845dd2a35fd53
Author: Eyal Sawady <ecs@d2evs.net>
Date: Fri, 22 Jan 2021 12:34:22 -0500
check: implement allocations
Diffstat:
6 files changed, 103 insertions(+), 11 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -117,12 +117,6 @@ struct ast_expression_access {
};
};
-enum alloc_kind {
- ALLOC_KIND_ALLOC,
- ALLOC_KIND_APPEND,
- ALLOC_KIND_FREE,
-};
-
struct ast_append_values {
struct ast_expression *value;
struct ast_append_values *next;
@@ -133,10 +127,10 @@ struct ast_expression_allocation {
struct ast_expression *expr;
// For allocs only
struct ast_type *type;
+ struct ast_expression *cap;
// For appends only
bool variadic;
struct ast_append_values *values;
- struct ast_expression *cap;
};
struct ast_expression_assert {
diff --git a/include/expr.h b/include/expr.h
@@ -9,6 +9,7 @@ struct scope_object;
enum expr_type {
EXPR_ACCESS,
+ EXPR_ALLOC,
EXPR_ASSERT,
EXPR_ASSIGN,
EXPR_BINARITHM,
@@ -52,6 +53,28 @@ struct expression_access {
};
};
+enum alloc_kind {
+ AKIND_ALLOC,
+ AKIND_APPEND,
+ AKIND_FREE,
+};
+
+struct append_values {
+ struct expression *value;
+ struct append_values *next;
+};
+
+struct expression_alloc {
+ enum alloc_kind kind;
+ struct expression *expr;
+ // For allocs only
+ // Allocated type goes in expr->result
+ struct expression *cap;
+ // For appends only
+ bool variadic;
+ struct append_values *values;
+};
+
struct expression_assert {
struct expression *cond;
struct expression *message;
@@ -238,6 +261,7 @@ struct expression {
bool terminates;
union {
struct expression_access access;
+ struct expression_alloc alloc;
struct expression_assert assert;
struct expression_assign assign;
struct expression_binarithm binarithm;
diff --git a/src/check.c b/src/check.c
@@ -57,7 +57,7 @@ lower_implicit_cast(const struct type *to, struct expression *expr)
void check_expression(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr,
- const struct type *type);
+ const struct type *hint);
static void
check_expr_access(struct context *ctx,
@@ -135,6 +135,70 @@ check_expr_access(struct context *ctx,
}
static void
+check_alloc(struct context *ctx, const struct ast_expression *aexpr,
+ struct expression *expr)
+{
+ expr->alloc.expr = xcalloc(sizeof(struct expression), 1);
+ expr->result =
+ type_store_lookup_atype(ctx->store, aexpr->alloc.type);
+ check_expression(ctx, aexpr->alloc.expr, expr->alloc.expr, expr->result);
+ enum type_storage storage = type_dealias(expr->result)->storage;
+ switch (storage) {
+ case TYPE_STORAGE_POINTER:
+ if (aexpr->alloc.cap != NULL) {
+ // We can't just expect(aexpr->alloc.cap != NULL)
+ // because we want to use aexpr->alloc.cap->loc
+ expect(&aexpr->alloc.cap->loc, false,
+ "Allocation with capacity must be of slice type, not %s",
+ type_storage_unparse(storage));
+ }
+ break;
+ case TYPE_STORAGE_SLICE:
+ if (aexpr->alloc.cap != NULL) {
+ expr->alloc.cap = xcalloc(sizeof(struct expression), 1);
+ check_expression(ctx, aexpr->alloc.cap, expr->alloc.cap,
+ &builtin_type_size);
+ expect(&aexpr->alloc.cap->loc,
+ type_is_assignable(ctx->store,
+ &builtin_type_size,
+ expr->alloc.cap->result),
+ "Allocation capacity must be assignable to size");
+ }
+ break;
+ default:
+ expect(&aexpr->loc, false,
+ "Allocation type must be pointer or slice, not %s",
+ type_storage_unparse(storage));
+ }
+}
+
+static void
+check_expr_alloc(struct context *ctx,
+ const struct ast_expression *aexpr,
+ struct expression *expr,
+ const struct type *hint)
+{
+ assert(aexpr->type == EXPR_ALLOC);
+ expr->type = EXPR_ALLOC;
+ expr->alloc.kind = aexpr->alloc.kind;
+ switch (expr->alloc.kind) {
+ case AKIND_ALLOC:
+ trace(TR_CHECK, "alloc");
+ check_alloc(ctx, aexpr, expr);
+ break;
+ case AKIND_APPEND:
+ trace(TR_CHECK, "append");
+ assert(0); // TODO
+ case AKIND_FREE:
+ trace(TR_CHECK, "free");
+ expr->alloc.expr = xcalloc(sizeof(struct expression), 1);
+ check_expression(ctx, aexpr->alloc.expr, expr->alloc.expr, NULL);
+ expr->result = &builtin_type_void;
+ break;
+ }
+}
+
+static void
check_expr_assert(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr,
@@ -1114,6 +1178,9 @@ check_expression(struct context *ctx,
case EXPR_ACCESS:
check_expr_access(ctx, aexpr, expr, hint);
break;
+ case EXPR_ALLOC:
+ check_expr_alloc(ctx, aexpr, expr, hint);
+ break;
case EXPR_ASSERT:
check_expr_assert(ctx, aexpr, expr, hint);
break;
diff --git a/src/eval.c b/src/eval.c
@@ -380,6 +380,7 @@ eval_expr(struct context *ctx, struct expression *in, struct expression *out)
case EXPR_STRUCT:
case EXPR_UNARITHM:
assert(0); // TODO
+ case EXPR_ALLOC:
case EXPR_ASSERT:
case EXPR_ASSIGN:
case EXPR_BINDING:
diff --git a/src/gen.c b/src/gen.c
@@ -1596,6 +1596,9 @@ gen_expression(struct gen_context *ctx,
case EXPR_ACCESS:
gen_expr_access(ctx, expr, out);
break;
+ case EXPR_ALLOC:
+ assert(0); // TODO
+ break;
case EXPR_ASSERT:
gen_expr_assert(ctx, expr, out);
break;
diff --git a/src/parse.c b/src/parse.c
@@ -1159,7 +1159,8 @@ parse_allocation_expression(struct lexer *lexer)
switch (lex(lexer, &tok)) {
case T_ALLOC:
trace(TR_PARSE, "alloc");
- exp->alloc.kind = ALLOC_KIND_ALLOC;
+ exp->type = EXPR_ALLOC;
+ exp->alloc.kind = AKIND_ALLOC;
want(lexer, T_LPAREN, NULL);
exp->alloc.type = parse_type(lexer);
want(lexer, T_COMMA, NULL);
@@ -1177,7 +1178,8 @@ parse_allocation_expression(struct lexer *lexer)
break;
case T_APPEND:
trace(TR_PARSE, "append");
- exp->alloc.kind = ALLOC_KIND_APPEND;
+ exp->type = EXPR_ALLOC;
+ exp->alloc.kind = AKIND_APPEND;
want(lexer, T_LPAREN, NULL);
exp->alloc.expr = parse_simple_expression(lexer);
want(lexer, T_COMMA, NULL);
@@ -1204,7 +1206,8 @@ parse_allocation_expression(struct lexer *lexer)
break;
case T_FREE:
trace(TR_PARSE, "free");
- exp->alloc.kind = ALLOC_KIND_FREE;
+ exp->type = EXPR_ALLOC;
+ exp->alloc.kind = AKIND_FREE;
want(lexer, T_LPAREN, NULL);
exp->alloc.expr = parse_simple_expression(lexer);
want(lexer, T_RPAREN, NULL);