mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Handle "splice splat" in the vararg slot as an expression.
This commit is contained in:
@@ -693,7 +693,6 @@ typedef struct
|
||||
ExprId macro_body;
|
||||
bool is_type_method : 1;
|
||||
bool is_pointer_call : 1;
|
||||
bool splat_vararg : 1;
|
||||
bool attr_force_inline : 1;
|
||||
bool attr_force_noinline : 1;
|
||||
bool is_builtin : 1;
|
||||
@@ -704,11 +703,11 @@ typedef struct
|
||||
bool has_optional_arg : 1;
|
||||
bool must_use : 1;
|
||||
bool is_optional_return : 1;
|
||||
bool va_is_splat : 1;
|
||||
Expr **arguments;
|
||||
union
|
||||
{
|
||||
union {
|
||||
Expr **varargs;
|
||||
Expr *splat;
|
||||
Expr *vasplat;
|
||||
};
|
||||
} ExprCall;
|
||||
|
||||
@@ -3217,6 +3216,9 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc)
|
||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||
expr_list_set_span(expr->designated_init_list, loc);
|
||||
return;
|
||||
case EXPR_SPLAT:
|
||||
expr_set_span(expr->inner_expr, loc);
|
||||
return;
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
case EXPR_ACCESS:
|
||||
case EXPR_BITACCESS:
|
||||
|
||||
@@ -447,11 +447,12 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
case EXPR_CT_AND_OR:
|
||||
MACRO_COPY_EXPR_LIST(expr->ct_and_or_expr.args);
|
||||
return expr;
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
case EXPR_OPTIONAL:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_CT_IS_CONST:
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
case EXPR_OPTIONAL:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_STRINGIFY:
|
||||
MACRO_COPY_EXPR(expr->inner_expr);
|
||||
return expr;
|
||||
case EXPR_DEFAULT_ARG:
|
||||
@@ -516,9 +517,9 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
MACRO_COPY_EXPR_LIST(expr->call_expr.arguments);
|
||||
if (expr->call_expr.varargs)
|
||||
{
|
||||
if (expr->call_expr.splat_vararg)
|
||||
if (expr->call_expr.va_is_splat)
|
||||
{
|
||||
MACRO_COPY_EXPR(expr->call_expr.splat);
|
||||
MACRO_COPY_EXPR(expr->call_expr.vasplat);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -806,6 +806,7 @@ typedef enum
|
||||
EXPR_SLICE,
|
||||
EXPR_SLICE_ASSIGN,
|
||||
EXPR_SLICE_COPY,
|
||||
EXPR_SPLAT,
|
||||
EXPR_STRINGIFY,
|
||||
EXPR_SUBSCRIPT,
|
||||
EXPR_SUBSCRIPT_ADDR,
|
||||
@@ -1603,8 +1604,8 @@ typedef enum
|
||||
case EXPR_CT_DEFINED: case EXPR_CT_AND_OR:\
|
||||
case EXPR_CT_CASTABLE: case EXPR_CT_IS_CONST: \
|
||||
case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
|
||||
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \
|
||||
case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_TAGOF: \
|
||||
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \
|
||||
case EXPR_SPLAT: case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_TAGOF: \
|
||||
case EXPR_CT_EVAL: case EXPR_CT_CONCAT: case EXPR_CT_APPEND
|
||||
|
||||
static_assert(EXPR_LAST < 128, "Too many expression types");
|
||||
|
||||
@@ -226,6 +226,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
case EXPR_POST_UNARY:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_MACRO_BLOCK:
|
||||
case EXPR_RETHROW:
|
||||
case EXPR_MEMBER_GET:
|
||||
@@ -765,6 +766,7 @@ bool expr_is_pure(Expr *expr)
|
||||
case EXPR_POST_UNARY:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_TRY_UNWRAP:
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
|
||||
@@ -6091,9 +6091,9 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
|
||||
|
||||
Expr *vararg_splat = NULL;
|
||||
Expr **varargs = NULL;
|
||||
if (expr->call_expr.splat_vararg)
|
||||
if (expr->call_expr.va_is_splat)
|
||||
{
|
||||
vararg_splat = expr->call_expr.splat;
|
||||
vararg_splat = expr->call_expr.vasplat;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -484,10 +484,10 @@ END:
|
||||
*
|
||||
* parameter ::= ((param_path '=')? expr) | param_path
|
||||
*/
|
||||
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat)
|
||||
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool vasplat)
|
||||
{
|
||||
*result = NULL;
|
||||
if (splat) *splat = false;
|
||||
bool has_splat = false;
|
||||
while (1)
|
||||
{
|
||||
Expr *expr = NULL;
|
||||
@@ -528,16 +528,16 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *
|
||||
ASSIGN_EXPR_OR_RET(expr, parse_vasplat(c), false);
|
||||
goto DONE;
|
||||
}
|
||||
if (splat)
|
||||
if (try_consume(c, TOKEN_ELLIPSIS))
|
||||
{
|
||||
if (*splat)
|
||||
{
|
||||
PRINT_ERROR_HERE("'...' is only allowed on the last argument in a call.");
|
||||
return false;
|
||||
}
|
||||
*splat = try_consume(c, TOKEN_ELLIPSIS);
|
||||
expr = expr_new(EXPR_SPLAT, start_span);
|
||||
ASSIGN_EXPR_OR_RET(expr->inner_expr, parse_expr(c), false);
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(expr, parse_expr(c), false);
|
||||
}
|
||||
ASSIGN_EXPR_OR_RET(expr, parse_expr(c), false);
|
||||
DONE:
|
||||
vec_add(*result, expr);
|
||||
if (!try_consume(c, TOKEN_COMMA))
|
||||
@@ -545,9 +545,6 @@ DONE:
|
||||
return true;
|
||||
}
|
||||
if (tok_is(c, param_end)) return true;
|
||||
if (splat && *splat)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,13 +968,12 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left)
|
||||
|
||||
Expr **params = NULL;
|
||||
advance_and_verify(c, TOKEN_LPAREN);
|
||||
bool splat = false;
|
||||
Decl **body_args = NULL;
|
||||
if (!tok_is(c, TOKEN_RPAREN) && !tok_is(c, TOKEN_EOS))
|
||||
{
|
||||
// Pick a modest guess.
|
||||
params = VECNEW(Expr*, 4);
|
||||
if (!parse_arg_list(c, ¶ms, TOKEN_RPAREN, &splat, true)) return poisoned_expr;
|
||||
params = VECNEW(Expr*, 8);
|
||||
if (!parse_arg_list(c, ¶ms, TOKEN_RPAREN, true)) return poisoned_expr;
|
||||
}
|
||||
if (try_consume(c, TOKEN_EOS))
|
||||
{
|
||||
@@ -998,7 +994,6 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left)
|
||||
Expr *call = expr_new_expr(EXPR_CALL, left);
|
||||
call->call_expr.function = exprid(left);
|
||||
call->call_expr.arguments = params;
|
||||
call->call_expr.splat_vararg = splat;
|
||||
RANGE_EXTEND_PREV(call);
|
||||
if (body_args && !tok_is(c, TOKEN_LBRACE))
|
||||
{
|
||||
|
||||
@@ -2213,7 +2213,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
else
|
||||
{
|
||||
CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl);
|
||||
if (!parse_arg_list(c, &enum_const->enum_constant.args, TOKEN_RBRACE, NULL, false)) return poisoned_decl;
|
||||
if (!parse_arg_list(c, &enum_const->enum_constant.args, TOKEN_RBRACE, 0)) return poisoned_decl;
|
||||
CONSUME_OR_RET(TOKEN_RBRACE, poisoned_decl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ bool parse_generic_parameters(ParseContext *c, Expr ***exprs_ref);
|
||||
bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,
|
||||
Variadic *variadic, int *vararg_index_ref, ParameterParseKind parse_kind);
|
||||
|
||||
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat);
|
||||
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool vasplat);
|
||||
Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *type_info);
|
||||
|
||||
INLINE void add_decl_to_list(Decl ***list, Decl *decl)
|
||||
|
||||
@@ -139,7 +139,7 @@ static inline bool sema_call_analyse_func_invocation(SemaContext *context, Decl
|
||||
static inline bool sema_call_check_invalid_body_arguments(SemaContext *context, Expr *call, CalledDecl *callee);
|
||||
INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, Expr *call,
|
||||
Expr **args, unsigned func_param_count,
|
||||
Variadic variadic, unsigned vararg_index, bool *optional,
|
||||
Variadic variadic, unsigned vaarg_index, bool *optional,
|
||||
Expr ***varargs_ref, Expr **vararg_splat_ref, bool *no_match_ref);
|
||||
static inline bool sema_call_check_contract_param_match(SemaContext *context, Decl *param, Expr *expr);
|
||||
static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *call);
|
||||
@@ -550,6 +550,7 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp
|
||||
case EXPR_RETVAL:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_TAGOF:
|
||||
case EXPR_TERNARY:
|
||||
@@ -686,6 +687,7 @@ static bool expr_may_ref(Expr *expr)
|
||||
case EXPR_RETVAL:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_TERNARY:
|
||||
case EXPR_TEST_HOOK:
|
||||
@@ -1227,7 +1229,7 @@ static inline bool sema_call_check_invalid_body_arguments(SemaContext *context,
|
||||
|
||||
|
||||
INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, Expr *call, Expr **args,
|
||||
unsigned func_param_count, Variadic variadic, unsigned vararg_index,
|
||||
unsigned func_param_count, Variadic variadic, unsigned vaarg_index,
|
||||
bool *optional, Expr ***varargs_ref, Expr **vararg_splat_ref,
|
||||
bool *no_match_ref)
|
||||
{
|
||||
@@ -1251,6 +1253,20 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
|
||||
Expr *arg = args[i];
|
||||
assert(expr_ok(arg));
|
||||
|
||||
if (arg->expr_kind == EXPR_SPLAT)
|
||||
{
|
||||
if (variadic == VARIADIC_NONE)
|
||||
{
|
||||
RETURN_SEMA_ERROR(arg, "Splat is only possible with variadic functions.");
|
||||
}
|
||||
if (i != vaarg_index)
|
||||
{
|
||||
RETURN_SEMA_ERROR(arg, "Expected a splat only in the vaarg slot.");
|
||||
}
|
||||
call->call_expr.va_is_splat = true;
|
||||
*vararg_splat_ref = args[i] = arg->inner_expr;
|
||||
continue;
|
||||
}
|
||||
if (arg->expr_kind == EXPR_NAMED_ARGUMENT)
|
||||
{
|
||||
// Find the location of the parameter.
|
||||
@@ -1278,7 +1294,6 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
|
||||
|
||||
if (last_index > index)
|
||||
{
|
||||
|
||||
SEMA_ERROR(arg, "Named arguments must always be declared in order.");
|
||||
SEMA_NOTE(last_named_arg, "Place it before this argument.");
|
||||
return false;
|
||||
@@ -1313,16 +1328,9 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
|
||||
|
||||
// 10. If we exceed the function parameter count (remember we reduced this by one
|
||||
// in the case of typed vararg) we're now in a variadic list.
|
||||
if (variadic != VARIADIC_NONE && i >= vararg_index)
|
||||
if (variadic != VARIADIC_NONE && i >= vaarg_index)
|
||||
{
|
||||
|
||||
// 11a. Look if we did a splat
|
||||
if (call->call_expr.splat_vararg)
|
||||
{
|
||||
*vararg_splat_ref = arg;
|
||||
continue;
|
||||
}
|
||||
else if (variadic == VARIADIC_ANY)
|
||||
if (variadic == VARIADIC_ANY)
|
||||
{
|
||||
if (!sema_analyse_expr(context, arg)) return false;
|
||||
Type *type = arg->type;
|
||||
@@ -1344,7 +1352,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
|
||||
{
|
||||
// 17a. Assigned a value - skip
|
||||
if (actual_args[i]) continue;
|
||||
if (i == vararg_index && variadic != VARIADIC_NONE) continue;
|
||||
if (i == vaarg_index && variadic != VARIADIC_NONE) continue;
|
||||
|
||||
// 17b. Set the init expression.
|
||||
Decl *param = params[i];
|
||||
@@ -1408,7 +1416,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
|
||||
}
|
||||
RETURN_SEMA_FUNC_ERROR(callee->definition, call, "This call expected a parameter, did you forget it?");
|
||||
}
|
||||
if (variadic != VARIADIC_NONE && i > vararg_index)
|
||||
if (variadic != VARIADIC_NONE && i > vaarg_index)
|
||||
{
|
||||
if (!param)
|
||||
{
|
||||
@@ -1646,7 +1654,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call
|
||||
}
|
||||
|
||||
// 4. Check for splat of the variadic argument.
|
||||
bool splat = call->call_expr.splat_vararg;
|
||||
bool splat = call->call_expr.va_is_splat;
|
||||
if (splat)
|
||||
{
|
||||
// 4a. Is this *not* a variadic function/macro? - Then that's an error.
|
||||
@@ -1739,7 +1747,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call
|
||||
return false;
|
||||
}
|
||||
*optional |= IS_OPTIONAL(vararg_splat);
|
||||
call->call_expr.splat = vararg_splat;
|
||||
call->call_expr.vasplat = vararg_splat;
|
||||
}
|
||||
// 7. Loop through the parameters.
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
@@ -1979,9 +1987,9 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
{
|
||||
if (!param) continue;
|
||||
// Splat? That's the simple case.
|
||||
if (call_expr->call_expr.splat_vararg)
|
||||
if (call_expr->call_expr.va_is_splat)
|
||||
{
|
||||
if (!sema_analyse_expr(context, args[i] = call_expr->call_expr.splat)) return false;
|
||||
if (!sema_analyse_expr(context, args[i] = call_expr->call_expr.vasplat)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2309,7 +2317,7 @@ static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *c
|
||||
PRINT_ERROR_AT(call, "Nested expansion is not possible.");
|
||||
return false;
|
||||
}
|
||||
if (call_expr->splat_vararg)
|
||||
if (call_expr->va_is_splat)
|
||||
{
|
||||
PRINT_ERROR_AT(call, "Expanding parameters is not allowed for macro invocations.");
|
||||
}
|
||||
@@ -8383,6 +8391,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
case EXPR_SLICE:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_SWIZZLE:
|
||||
case EXPR_SUBSCRIPT_ADDR:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
@@ -8844,24 +8853,25 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_COND:
|
||||
case EXPR_DESIGNATOR:
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
case EXPR_NOP:
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
case EXPR_TRY_UNWRAP:
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
case EXPR_ANYSWITCH:
|
||||
case EXPR_TYPEID_INFO:
|
||||
case EXPR_ASM:
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_BENCHMARK_HOOK:
|
||||
case EXPR_TEST_HOOK:
|
||||
case EXPR_SWIZZLE:
|
||||
case EXPR_MACRO_BODY:
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
case EXPR_COND:
|
||||
case EXPR_DEFAULT_ARG:
|
||||
case EXPR_DESIGNATOR:
|
||||
case EXPR_MACRO_BODY:
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
case EXPR_MEMBER_GET:
|
||||
case EXPR_NAMED_ARGUMENT:
|
||||
case EXPR_NOP:
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_SWIZZLE:
|
||||
case EXPR_TEST_HOOK:
|
||||
case EXPR_TRY_UNWRAP:
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
case EXPR_TYPEID_INFO:
|
||||
UNREACHABLE
|
||||
case EXPR_TAGOF:
|
||||
RETURN_SEMA_ERROR(expr, "Expected '()' after this.");
|
||||
|
||||
@@ -299,9 +299,9 @@ RETRY:
|
||||
sema_trace_expr_list_liveness(expr->call_expr.arguments);
|
||||
if (expr->call_expr.varargs)
|
||||
{
|
||||
if (expr->call_expr.splat_vararg)
|
||||
if (expr->call_expr.va_is_splat)
|
||||
{
|
||||
sema_trace_expr_liveness(expr->call_expr.splat);
|
||||
sema_trace_expr_liveness(expr->call_expr.vasplat);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -698,6 +698,7 @@ static inline bool sema_expr_valid_try_expression(Expr *expr)
|
||||
case EXPR_SLICE:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
case EXPR_SPLAT:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_SUBSCRIPT:
|
||||
case EXPR_SWIZZLE:
|
||||
|
||||
Reference in New Issue
Block a user