mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Extracted macro declaration body to separately allocated field.
This commit is contained in:
committed by
Christoffer Lerno
parent
4258fe4d01
commit
fc296ea579
@@ -85,6 +85,7 @@ typedef enum
|
||||
} ConstInitType;
|
||||
|
||||
|
||||
|
||||
typedef struct ConstInitializer_
|
||||
{
|
||||
ConstInitType kind;
|
||||
@@ -293,6 +294,12 @@ struct TypeInfo_
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct BodyParam
|
||||
{
|
||||
SourceSpan span;
|
||||
const char *name;
|
||||
Decl **params;
|
||||
} BodyParam;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -503,8 +510,7 @@ typedef struct
|
||||
TypeInfoId rtype; // May be 0
|
||||
AstId body;
|
||||
Decl **parameters;
|
||||
Decl **body_parameters;
|
||||
const char *block_parameter;
|
||||
BodyParam *body_param;
|
||||
struct CompilationUnit_ *unit;
|
||||
struct AstDocDirective_ *docs;
|
||||
} MacroDecl;
|
||||
@@ -1260,7 +1266,7 @@ typedef struct Ast_
|
||||
} Ast;
|
||||
|
||||
//static_assert(sizeof(AstContinueBreakStmt) == 24, "Ooops");
|
||||
//static_assert(sizeof(Ast) == 56, "Oops");
|
||||
//static_assert(sizeof(Ast) == 56, "Not expected size on 64 bit");
|
||||
|
||||
typedef struct Module_
|
||||
{
|
||||
|
||||
@@ -1179,27 +1179,29 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
|
||||
*/
|
||||
static inline bool parse_parameter_list(ParseContext *c, Visibility parent_visibility, FunctionSignature *signature, bool is_interface)
|
||||
{
|
||||
Decl **decls = NULL;
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, false);
|
||||
Decl **decls;
|
||||
if (!parse_parameters(c, parent_visibility, &decls)) return false;
|
||||
if (vec_size(decls))
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, false);
|
||||
|
||||
signature->params = decls;
|
||||
Decl *last = VECLAST(decls);
|
||||
|
||||
// The last parameter may hold a vararg
|
||||
if (last && last->var.vararg)
|
||||
{
|
||||
Decl *last = VECLAST(decls);
|
||||
if (last->var.vararg)
|
||||
// Is it "(foo...)" (any) or "(int... foo)" (typed)?
|
||||
if (last->var.type_info)
|
||||
{
|
||||
if (!last->var.type_info)
|
||||
{
|
||||
vec_resize(decls, vec_size(decls) - 1);
|
||||
signature->variadic = VARIADIC_RAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
signature->variadic = last->var.vararg_implicit ? VARIADIC_ANY : VARIADIC_TYPED;
|
||||
}
|
||||
signature->variadic = last->var.vararg_implicit ? VARIADIC_ANY : VARIADIC_TYPED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the last element if it's a raw variant, i.e. "(...)"
|
||||
vec_pop(decls);
|
||||
signature->variadic = VARIADIC_RAW;
|
||||
}
|
||||
}
|
||||
signature->params = decls;
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1429,12 +1431,12 @@ static inline Decl *parse_top_level_const_declaration(ParseContext *c, Visibilit
|
||||
*
|
||||
* trailing_block_parameter ::= '@' IDENT ( '(' parameters ')' )?
|
||||
*/
|
||||
static bool parse_macro_arguments(ParseContext *c, Visibility visibility, Decl ***params_ref, Decl ***body_params, const char **block_parameter)
|
||||
static bool parse_macro_arguments(ParseContext *c, Visibility visibility, Decl ***params_ref, BodyParam **body_param_ref)
|
||||
{
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, false);
|
||||
*params_ref = NULL;
|
||||
*body_params = NULL;
|
||||
*block_parameter = NULL;
|
||||
*body_param_ref = NULL;
|
||||
|
||||
// Parse the regular parameters.
|
||||
if (!parse_parameters(c, visibility, params_ref)) return false;
|
||||
|
||||
@@ -1442,15 +1444,17 @@ static bool parse_macro_arguments(ParseContext *c, Visibility visibility, Decl *
|
||||
if (try_consume(c, TOKEN_EOS))
|
||||
{
|
||||
// Consume '@' IDENT
|
||||
TRY_CONSUME_OR_RET(TOKEN_AT, "Expected a trailing block with the format '@block(...).", false);
|
||||
*block_parameter = symstr(c);
|
||||
TRY_CONSUME_OR_RET(TOKEN_AT, "Expected an ending ')' or a block parameter on the format '@block(...).", false);
|
||||
BodyParam *body_param = CALLOCS(BodyParam);
|
||||
body_param->name = symstr(c);
|
||||
body_param->span = c->span;
|
||||
if (!consume_ident(c, "variable name")) return false;
|
||||
if (try_consume(c, TOKEN_LPAREN))
|
||||
{
|
||||
if (!parse_parameters(c, visibility, body_params)) return false;
|
||||
if (!parse_parameters(c, visibility, &body_param->params)) return false;
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, false);
|
||||
}
|
||||
// TODO use the body param.
|
||||
*body_param_ref = body_param;
|
||||
}
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, false);
|
||||
return true;
|
||||
@@ -1554,7 +1558,7 @@ static inline Decl *parse_define_type(ParseContext *c, Visibility visibility)
|
||||
*/
|
||||
static inline Decl *parse_define_ident(ParseContext *c, Visibility visibility)
|
||||
{
|
||||
// 1. Store the beginning of the define.
|
||||
// 1. Store the beginning of the "define".
|
||||
advance_and_verify(c, TOKEN_DEFINE);
|
||||
|
||||
// 2. At this point we expect an ident or a const token.
|
||||
@@ -1574,7 +1578,7 @@ static inline Decl *parse_define_ident(ParseContext *c, Visibility visibility)
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
// 3. Set up the define.
|
||||
// 3. Set up the "define".
|
||||
Decl *decl = decl_new(DECL_DEFINE, symstr(c), c->span, visibility);
|
||||
decl->define_decl.define_kind = DEFINE_IDENT_ALIAS;
|
||||
|
||||
@@ -1772,10 +1776,8 @@ static inline Decl *parse_macro_declaration(ParseContext *c, Visibility visibili
|
||||
TypeInfoId *method_type_ref = &decl->macro_decl.type_parent;
|
||||
if (!parse_func_macro_header(c, true, rtype_ref, method_type_ref, &decl->name, &decl->span)) return poisoned_decl;
|
||||
|
||||
|
||||
const char *block_parameter = NULL;
|
||||
if (!parse_macro_arguments(c, visibility, &decl->macro_decl.parameters, &decl->macro_decl.body_parameters, &block_parameter)) return poisoned_decl;
|
||||
decl->macro_decl.block_parameter = block_parameter;
|
||||
if (!parse_macro_arguments(c, visibility, &decl->macro_decl.parameters, &decl->macro_decl.body_param)) return poisoned_decl;
|
||||
|
||||
if (!parse_attributes(c, &decl->attributes)) return poisoned_decl;
|
||||
|
||||
|
||||
@@ -1757,12 +1757,14 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
if (!sema_check_no_duplicate_parameter(parameters, param, i, param_count)) return decl_poison(decl);
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
if (is_generic && vec_size(decl->macro_decl.body_parameters))
|
||||
BodyParam *body_param = decl->macro_decl.body_param;
|
||||
if (is_generic && decl->macro_decl.body_param)
|
||||
{
|
||||
SEMA_ERROR(decl->macro_decl.body_parameters[0], "Trailing block syntax is not allowed for generic functions.");
|
||||
SEMA_ERROR(decl->macro_decl.body_param, "Trailing block syntax is not allowed for generic functions.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
Decl **body_parameters = decl->macro_decl.body_parameters;
|
||||
|
||||
Decl **body_parameters = body_param ? body_param->params : NULL;
|
||||
unsigned body_param_count = vec_size(body_parameters);
|
||||
for (unsigned i = 0; i < body_param_count; i++)
|
||||
{
|
||||
@@ -1796,7 +1798,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
bool pure = false;
|
||||
if (!sema_analyse_doc_header(decl->macro_decl.docs, decl->macro_decl.parameters, decl->macro_decl.body_parameters, &pure)) return decl_poison(decl);
|
||||
if (!sema_analyse_doc_header(decl->macro_decl.docs, decl->macro_decl.parameters, body_parameters, &pure)) return decl_poison(decl);
|
||||
if (decl->macro_decl.type_parent)
|
||||
{
|
||||
if (!sema_analyse_macro_method(context, decl)) return decl_poison(decl);
|
||||
|
||||
@@ -1013,8 +1013,8 @@ static inline bool sema_expr_analyse_macro_expansion(SemaContext *context, Expr
|
||||
Expr *inner = expr->macro_expansion_expr.inner;
|
||||
if (inner->expr_kind == EXPR_IDENTIFIER)
|
||||
{
|
||||
const char *body = context->current_macro ? context->current_macro->macro_decl.block_parameter : NULL;
|
||||
if (body && !inner->identifier_expr.path && inner->identifier_expr.ident == body)
|
||||
BodyParam *body_param = context->current_macro ? context->current_macro->macro_decl.body_param : NULL;
|
||||
if (body_param && !inner->identifier_expr.path && inner->identifier_expr.ident == body_param->name)
|
||||
{
|
||||
expr->expr_kind = EXPR_MACRO_BODY_EXPANSION;
|
||||
expr->body_expansion_expr.ast = NULL;
|
||||
@@ -1802,7 +1802,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
Decl **params = decl_copy_list(decl->macro_decl.parameters);
|
||||
CalledDecl callee = {
|
||||
.macro = true,
|
||||
.block_parameter = decl->macro_decl.block_parameter,
|
||||
.block_parameter = decl->macro_decl.body_param ? decl->macro_decl.body_param->name : NULL,
|
||||
.params = params,
|
||||
.param_count = vec_size(params),
|
||||
.struct_var = struct_var
|
||||
@@ -1818,7 +1818,8 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
|
||||
Decl **body_params = call_expr->call_expr.body_arguments;
|
||||
unsigned body_params_count = vec_size(body_params);
|
||||
unsigned expected_body_params = vec_size(decl->macro_decl.body_parameters);
|
||||
Decl **macro_body_params = decl->macro_decl.body_param ? decl->macro_decl.body_param->params : NULL;
|
||||
unsigned expected_body_params = vec_size(macro_body_params);
|
||||
if (expected_body_params > body_params_count)
|
||||
{
|
||||
SEMA_ERROR(call_expr, "Not enough parameters for the macro body, expected %d.", expected_body_params);
|
||||
@@ -1831,7 +1832,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
}
|
||||
for (unsigned i = 0; i < expected_body_params; i++)
|
||||
{
|
||||
Decl *body_param = decl->macro_decl.body_parameters[i];
|
||||
Decl *body_param = macro_body_params[i];
|
||||
assert(body_param->resolve_status == RESOLVE_DONE);
|
||||
Decl *body_arg = call_expr->call_expr.body_arguments[i];
|
||||
if (!body_arg->var.type_info)
|
||||
@@ -2096,7 +2097,8 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
||||
{
|
||||
Decl *macro = macro_context->current_macro;
|
||||
assert(macro);
|
||||
assert(macro->macro_decl.block_parameter);
|
||||
BodyParam *body_param = macro->macro_decl.body_param;
|
||||
assert(body_param);
|
||||
|
||||
ExprCall *call_expr = &call->call_expr;
|
||||
if (vec_size(call_expr->body_arguments))
|
||||
@@ -2111,9 +2113,10 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
||||
}
|
||||
// Theoretically we could support named arguments, but that's unnecessary.
|
||||
unsigned expressions = vec_size(call_expr->arguments);
|
||||
if (expressions != vec_size(macro->macro_decl.body_parameters))
|
||||
Decl **body_parameters = body_param->params;
|
||||
if (expressions != vec_size(body_parameters))
|
||||
{
|
||||
SEMA_ERROR(call, "Expected %d parameter(s).", vec_size(macro->macro_decl.body_parameters));
|
||||
SEMA_ERROR(call, "Expected %d parameter(s).", vec_size(body_parameters));
|
||||
return false;
|
||||
}
|
||||
Expr **args = call_expr->arguments;
|
||||
@@ -7026,7 +7029,7 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr)
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
if (!expr->body_expansion_expr.ast)
|
||||
{
|
||||
SEMA_ERROR(expr, "'@%s' must be followed by ().", context->current_macro->macro_decl.block_parameter);
|
||||
SEMA_ERROR(expr, "'@%s' must be followed by ().", context->current_macro->macro_decl.body_param->name);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user