commit 6961bfd6431a3a8c1b776d998c8fdd35094c6112
parent 76ca5aba26366d1417a4f5e05d38c17a1cd25381
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 24 Dec 2020 14:56:35 -0500
check: implement call expressions
Diffstat:
4 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -82,6 +82,17 @@ struct expression_binding {
struct expression_binding *next;
};
+struct call_argument {
+ bool variadic;
+ struct expression *value;
+ struct call_argument *next;
+};
+
+struct expression_call {
+ struct expression *lvalue;
+ struct call_argument *args;
+};
+
union expression_constant {
bool bval;
struct {
@@ -147,6 +158,7 @@ struct expression {
struct expression_assign assign;
struct expression_binarithm binarithm;
struct expression_binding binding;
+ struct expression_call call;
union expression_constant constant;
struct expression_list list;
struct expression_measure measure;
diff --git a/include/types.h b/include/types.h
@@ -91,6 +91,8 @@ bool type_is_signed(const struct type *type);
bool type_is_integer(const struct type *type);
bool type_is_numeric(const struct type *type);
+const struct type *type_dereference(const struct type *type);
+
// Built-in type singletons
extern const struct type
// Primitive
diff --git a/src/check.c b/src/check.c
@@ -182,6 +182,48 @@ check_expr_binding(struct context *ctx,
}
static void
+check_expr_call(struct context *ctx,
+ const struct ast_expression *aexpr,
+ struct expression *expr)
+{
+ trenter(TR_CHECK, "call");
+ expr->type = EXPR_CALL;
+
+ struct expression *lvalue = calloc(1, sizeof(struct expression));
+ check_expression(ctx, aexpr->call.lvalue, lvalue);
+ expr->call.lvalue = lvalue;
+
+ const struct type *fntype = type_dereference(lvalue->result);
+ expect(fntype->storage == TYPE_STORAGE_FUNCTION,
+ "Cannot call non-function type");
+ expr->result = fntype->func.result;
+ assert(fntype->func.variadism == VARIADISM_NONE); // TODO
+
+ struct call_argument *arg, **next = &expr->call.args;
+ struct ast_call_argument *aarg = aexpr->call.args;
+ struct type_func_param *param = fntype->func.params;
+ while (param && aarg) {
+ assert(!aarg->variadic); // TODO
+ arg = *next = calloc(1, sizeof(struct call_argument));
+ arg->value = calloc(1, sizeof(struct expression));
+ check_expression(ctx, aarg->value, arg->value);
+
+ // TODO: Test for assignability
+ expect(arg->value->result->storage == param->type->storage,
+ "Invalid type for parameter");
+
+ aarg = aarg->next;
+ param = param->next;
+ next = &arg->next;
+ }
+
+ expect(!aarg, "Too many parameters for function call");
+ expect(!param, "Not enough parameters for function call");
+
+ trleave(TR_CHECK, NULL);
+}
+
+static void
check_expr_constant(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr)
@@ -385,7 +427,10 @@ check_expression(struct context *ctx,
check_expr_binding(ctx, aexpr, expr);
break;
case EXPR_BREAK:
+ assert(0); // TODO
case EXPR_CALL:
+ check_expr_call(ctx, aexpr, expr);
+ break;
case EXPR_CAST:
assert(0); // TODO
case EXPR_CONSTANT:
diff --git a/src/types.c b/src/types.c
@@ -181,6 +181,15 @@ type_is_signed(const struct type *type)
assert(0); // Unreachable
}
+const struct type *
+type_dereference(const struct type *type)
+{
+ if (type->storage != TYPE_STORAGE_POINTER) {
+ return type;
+ }
+ return type_dereference(type->pointer.referent);
+}
+
// Built-in type singletons
const struct type builtin_type_bool = {
.storage = TYPE_STORAGE_BOOL,