commit bc5fefcf470a9d24aef2f838cf27bac9c1e72d9b
parent 9df76fa33503566a65a893dc5f1c05f1d22a20e4
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 12 Jan 2021 11:03:51 -0500
Implement Hare-style variadism
Diffstat:
5 files changed, 87 insertions(+), 8 deletions(-)
diff --git a/include/type_store.h b/include/type_store.h
@@ -40,4 +40,7 @@ const struct type *type_store_lookup_pointer(struct type_store *store,
const struct type *type_store_lookup_array(struct type_store *store,
const struct type *members, size_t len, bool expandable);
+const struct type *type_store_lookup_slice(struct type_store *store,
+ const struct type *members);
+
#endif
diff --git a/src/check.c b/src/check.c
@@ -318,6 +318,46 @@ check_expr_binding(struct context *ctx,
}
}
+// Lower Hare-style variadic arguments into an array literal
+static void
+lower_vaargs(struct context *ctx,
+ const struct ast_call_argument *aarg,
+ struct expression *vaargs,
+ const struct type *type)
+{
+ struct ast_expression val = {
+ .type = EXPR_CONSTANT,
+ .loc = aarg->value->loc,
+ .constant = {
+ .storage = TYPE_STORAGE_ARRAY,
+ },
+ };
+ struct ast_array_constant **next = &val.constant.array;
+ while (aarg) {
+ struct ast_array_constant *item = *next =
+ xcalloc(1, sizeof(struct ast_array_constant));
+ item->value = aarg->value;
+ aarg = aarg->next;
+ next = &item->next;
+ }
+
+ // XXX: This error handling is minimum-effort and bad
+ ctx->type_hint = type_store_lookup_array(
+ &ctx->store, type, SIZE_UNDEFINED, false);
+ check_expression(ctx, &val, vaargs);
+ ctx->type_hint = NULL;
+ assert(vaargs->result->storage == TYPE_STORAGE_ARRAY);
+ expect(&val.loc, vaargs->result->array.members == type,
+ "Argument is not assignable to variadic parameter type");
+
+ struct ast_array_constant *item = val.constant.array;
+ while (item) {
+ struct ast_array_constant *next = item->next;
+ free(item);
+ item = next;
+ }
+}
+
static void
check_expr_call(struct context *ctx,
const struct ast_expression *aexpr,
@@ -337,7 +377,6 @@ check_expr_call(struct context *ctx,
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;
@@ -347,6 +386,17 @@ check_expr_call(struct context *ctx,
assert(!aarg->variadic); // TODO
arg = *next = xcalloc(1, sizeof(struct call_argument));
arg->value = xcalloc(1, sizeof(struct expression));
+
+ if (!param->next && fntype->func.variadism == VARIADISM_HARE) {
+ lower_vaargs(ctx, aarg, arg->value,
+ param->type->array.members);
+ arg->value = lower_implicit_cast(param->type, arg->value);
+ param = NULL;
+ aarg = NULL;
+ trleave(TR_CHECK, NULL);
+ break;
+ }
+
check_expression(ctx, aarg->value, arg->value);
expect(&aarg->value->loc,
@@ -890,6 +940,10 @@ check_function(struct context *ctx,
assert(fntype); // Invariant
ctx->current_fntype = fntype;
+ expect(&adecl->loc,
+ fntype->func.variadism != VARIADISM_C,
+ "C-style variadism is not allowed for function declarations");
+
struct declaration *decl = xcalloc(1, sizeof(struct declaration));
decl->type = DECL_FUNC;
decl->func.type = fntype;
@@ -905,12 +959,16 @@ check_function(struct context *ctx,
struct ast_function_parameters *params = afndecl->prototype.params;
while (params) {
expect(¶ms->loc, params->name,
- "Function parameters must be named");
+ "Function parameters must be named");
struct identifier ident = {
.name = params->name,
};
const struct type *type = type_store_lookup_atype(
&ctx->store, params->type);
+ if (fntype->func.variadism == VARIADISM_HARE
+ && !params->next) {
+ type = type_store_lookup_slice(&ctx->store, type);
+ }
scope_insert(decl->func.scope, O_BIND,
&ident, &ident, type, NULL);
params = params->next;
diff --git a/src/gen.c b/src/gen.c
@@ -646,8 +646,8 @@ gen_expr_cast(struct gen_context *ctx,
return;
}
- if (type_is_aggregate(expr->result)) {
- alloc_temp(ctx, &in, expr->result, "cast.in.%d");
+ if (type_is_aggregate(expr->cast.value->result)) {
+ alloc_temp(ctx, &in, expr->cast.value->result, "cast.in.%d");
qval_deref(&in);
} else {
gen_temp(ctx, &in, qtype_for_type(ctx, from, false), "cast.in.%d");
diff --git a/src/parse.c b/src/parse.c
@@ -209,12 +209,12 @@ parse_parameter_list(struct lexer *lexer, struct ast_function_type *type)
case T_COMMA:
switch (lex(lexer, &tok)) {
case T_ELLIPSIS:
- type->variadism = VARIADISM_HARE;
+ type->variadism = VARIADISM_C;
if (lex(lexer, &tok) != T_COMMA) {
unlex(lexer, &tok);
}
more = false;
- trace(TR_PARSE, ", ...");
+ trace(TR_PARSE, ", ... (C style)");
break;
case T_RPAREN:
more = false;
@@ -228,12 +228,12 @@ parse_parameter_list(struct lexer *lexer, struct ast_function_type *type)
}
break;
case T_ELLIPSIS:
- type->variadism = VARIADISM_C;
+ type->variadism = VARIADISM_HARE;
if (lex(lexer, &tok) != T_COMMA) {
unlex(lexer, &tok);
}
more = false;
- trace(TR_PARSE, "...");
+ trace(TR_PARSE, "... (Hare style)");
break;
default:
more = false;
diff --git a/src/type_store.c b/src/type_store.c
@@ -592,6 +592,11 @@ type_init_from_atype(struct type_store *store,
aparam; aparam = aparam->next) {
param = *next = xcalloc(1, sizeof(struct type_func_param));
param->type = type_store_lookup_atype(store, aparam->type);
+ if (atype->func.variadism == VARIADISM_HARE
+ && !aparam->next) {
+ param->type = type_store_lookup_slice(
+ store, param->type);
+ }
next = ¶m->next;
}
break;
@@ -809,3 +814,16 @@ type_store_lookup_array(struct type_store *store,
};
return type_store_lookup_type(store, &array);
}
+
+const struct type *
+type_store_lookup_slice(struct type_store *store, const struct type *members)
+{
+ struct type slice = {
+ .storage = TYPE_STORAGE_SLICE,
+ .array = {
+ .members = members,
+ .length = SIZE_UNDEFINED,
+ },
+ };
+ return type_store_lookup_type(store, &slice);
+}