harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit bc5fefcf470a9d24aef2f838cf27bac9c1e72d9b
parent 9df76fa33503566a65a893dc5f1c05f1d22a20e4
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 12 Jan 2021 11:03:51 -0500

Implement Hare-style variadism

Diffstat:
Minclude/type_store.h | 3+++
Msrc/check.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/gen.c | 4++--
Msrc/parse.c | 8++++----
Msrc/type_store.c | 18++++++++++++++++++
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(&params->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 = &param->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); +}