mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Output messages at compile time.
This commit is contained in:
@@ -96,6 +96,7 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type, V
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
case DECL_CT_ECHO:
|
||||
UNREACHABLE
|
||||
}
|
||||
Type *type = type_new(kind, name ? name : "$anon");
|
||||
@@ -126,6 +127,8 @@ const char *decl_to_a_name(Decl *decl)
|
||||
return "a poisoned decl";
|
||||
case DECL_CT_ASSERT:
|
||||
return "a compile time assert";
|
||||
case DECL_CT_ECHO:
|
||||
return "a compile time echo";
|
||||
case DECL_CT_CASE:
|
||||
return "a compile time case";
|
||||
case DECL_CT_ELIF:
|
||||
|
||||
@@ -710,6 +710,7 @@ typedef struct Decl_
|
||||
CtSwitchDecl ct_switch_decl;
|
||||
CtCaseDecl ct_case_decl;
|
||||
Ast *ct_assert_decl;
|
||||
Ast *ct_echo_decl;
|
||||
Decl** ct_else_decl;
|
||||
|
||||
};
|
||||
@@ -1549,6 +1550,7 @@ struct CompilationUnit_
|
||||
};
|
||||
Decl **ct_ifs;
|
||||
Decl **ct_asserts;
|
||||
Decl **ct_echos;
|
||||
Decl **xxlizers;
|
||||
Decl **vars;
|
||||
Decl **macros;
|
||||
@@ -2190,6 +2192,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl);
|
||||
bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl);
|
||||
bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local);
|
||||
bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement);
|
||||
bool sema_analyse_ct_echo_stmt(SemaContext *context, Ast *statement);
|
||||
bool sema_analyse_statement(SemaContext *context, Ast *statement);
|
||||
bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped_var);
|
||||
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr);
|
||||
|
||||
@@ -141,6 +141,7 @@ void decl_register(Decl *decl)
|
||||
case DECL_CT_IF:
|
||||
case DECL_CT_SWITCH:
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_FAULTVALUE:
|
||||
case DECL_IMPORT:
|
||||
@@ -263,6 +264,9 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
case DECL_CT_SWITCH:
|
||||
vec_add(unit->ct_ifs, decl);
|
||||
return;
|
||||
case DECL_CT_ECHO:
|
||||
vec_add(unit->ct_echos, decl);
|
||||
return;
|
||||
case DECL_CT_ASSERT:
|
||||
vec_add(unit->ct_asserts, decl);
|
||||
return;
|
||||
|
||||
@@ -586,6 +586,7 @@ RETRY:
|
||||
copy_reg_ref(c, source, ast);
|
||||
fixup_astid(c, &ast->defer_stmt.prev_defer);
|
||||
break;
|
||||
case AST_CT_ECHO_STMT:
|
||||
case AST_EXPR_STMT:
|
||||
MACRO_COPY_EXPR(ast->expr_stmt);
|
||||
break;
|
||||
@@ -863,6 +864,9 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
MACRO_COPY_DECL(decl->ct_if_decl.elif);
|
||||
MACRO_COPY_DECL_LIST(decl->ct_if_decl.then);
|
||||
break;
|
||||
case DECL_CT_ECHO:
|
||||
MACRO_COPY_AST(decl->ct_echo_decl);
|
||||
break;
|
||||
case DECL_CT_ASSERT:
|
||||
MACRO_COPY_AST(decl->ct_assert_decl);
|
||||
break;
|
||||
|
||||
@@ -53,10 +53,11 @@ typedef enum
|
||||
AST_COMPOUND_STMT,
|
||||
AST_CONTINUE_STMT,
|
||||
AST_CT_ASSERT,
|
||||
AST_CT_IF_STMT,
|
||||
AST_CT_ECHO_STMT,
|
||||
AST_CT_ELSE_STMT,
|
||||
AST_CT_FOR_STMT,
|
||||
AST_CT_FOREACH_STMT,
|
||||
AST_CT_FOR_STMT,
|
||||
AST_CT_IF_STMT,
|
||||
AST_CT_SWITCH_STMT,
|
||||
AST_DECLARE_STMT,
|
||||
AST_DEFAULT_STMT,
|
||||
@@ -138,6 +139,7 @@ typedef enum
|
||||
DECL_CT_IF,
|
||||
DECL_CT_SWITCH,
|
||||
DECL_CT_ASSERT,
|
||||
DECL_CT_ECHO,
|
||||
DECL_DEFINE,
|
||||
DECL_DISTINCT,
|
||||
DECL_ENUM,
|
||||
@@ -162,7 +164,8 @@ typedef enum
|
||||
#define NON_TYPE_DECLS DECL_IMPORT: case DECL_MACRO: \
|
||||
case DECL_DECLARRAY: case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \
|
||||
case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \
|
||||
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC: case DECL_INITIALIZE: case DECL_FINALIZE
|
||||
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC: case DECL_INITIALIZE: \
|
||||
case DECL_FINALIZE: case DECL_CT_ECHO
|
||||
|
||||
#define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \
|
||||
case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
|
||||
@@ -563,17 +566,18 @@ typedef enum
|
||||
TOKEN_CT_CHECKS, // $checks
|
||||
TOKEN_CT_DEFAULT, // $default
|
||||
TOKEN_CT_DEFINED, // $defined
|
||||
TOKEN_CT_FOR, // $for
|
||||
TOKEN_CT_FOREACH, // $foreach
|
||||
TOKEN_CT_ECHO, // $echo
|
||||
TOKEN_CT_ELIF, // $elif
|
||||
TOKEN_CT_ELSE, // $else
|
||||
TOKEN_CT_EVAL, // $eval
|
||||
TOKEN_CT_EVALTYPE, // $evaltype
|
||||
TOKEN_CT_ENDIF, // $endif
|
||||
TOKEN_CT_ENDSWITCH, // $endswitch
|
||||
TOKEN_CT_ENDFOR, // $endfor
|
||||
TOKEN_CT_ENDFOREACH, // $endforeach
|
||||
TOKEN_CT_ENDIF, // $endif
|
||||
TOKEN_CT_ENDSWITCH, // $endswitch
|
||||
TOKEN_CT_EVAL, // $eval
|
||||
TOKEN_CT_EVALTYPE, // $evaltype
|
||||
TOKEN_CT_EXTNAMEOF, // $extnameof
|
||||
TOKEN_CT_FOR, // $for
|
||||
TOKEN_CT_FOREACH, // $foreach
|
||||
TOKEN_CT_IF, // $if
|
||||
TOKEN_CT_NAMEOF, // $nameof
|
||||
TOKEN_CT_OFFSETOF, // $offsetof
|
||||
@@ -809,6 +813,7 @@ typedef enum
|
||||
ANALYSIS_REGISTER_GLOBALS,
|
||||
ANALYSIS_CONDITIONAL_COMPILATION,
|
||||
ANALYSIS_DECLS,
|
||||
ANALYSIS_CT_ECHO,
|
||||
ANALYSIS_CT_ASSERT,
|
||||
ANALYSIS_FUNCTIONS,
|
||||
ANALYSIS_LAST = ANALYSIS_FUNCTIONS
|
||||
|
||||
@@ -1001,6 +1001,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_CT_ECHO:
|
||||
UNREACHABLE;
|
||||
}
|
||||
UNREACHABLE
|
||||
|
||||
@@ -1412,6 +1412,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
|
||||
case AST_CT_SWITCH_STMT:
|
||||
case AST_CASE_STMT:
|
||||
case AST_DEFAULT_STMT:
|
||||
case AST_CT_ECHO_STMT:
|
||||
case AST_CT_FOREACH_STMT:
|
||||
UNREACHABLE
|
||||
case AST_SWITCH_STMT:
|
||||
|
||||
@@ -1470,7 +1470,11 @@ bool parse_struct_body(ParseContext *c, Decl *parent)
|
||||
|
||||
while (1)
|
||||
{
|
||||
EXPECT_OR_RET(TOKEN_IDENT, false);
|
||||
if (!tok_is(c, TOKEN_IDENT))
|
||||
{
|
||||
SEMA_ERROR_HERE("A valid member name was expected here.");
|
||||
return false;
|
||||
}
|
||||
Decl *member = DECL_VAR_NEW(type, VARDECL_MEMBER, parent->visibility);
|
||||
vec_add(parent->strukt.members, member);
|
||||
index++;
|
||||
@@ -2635,6 +2639,19 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref)
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
case TOKEN_CT_ECHO:
|
||||
if (!check_no_visibility_before(c, visibility)) return poisoned_decl;
|
||||
{
|
||||
ASSIGN_AST_OR_RET(Ast *ast, parse_ct_echo_stmt(c), poisoned_decl);
|
||||
decl = decl_new_ct(DECL_CT_ECHO, ast->span);
|
||||
decl->ct_echo_decl = ast;
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before $echo, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
case TOKEN_CT_IF:
|
||||
{
|
||||
if (!check_no_visibility_before(c, visibility)) return poisoned_decl;
|
||||
|
||||
@@ -1097,6 +1097,27 @@ Ast *parse_ct_assert_stmt(ParseContext *c)
|
||||
return ast;
|
||||
}
|
||||
|
||||
Ast *parse_ct_echo_stmt(ParseContext *c)
|
||||
{
|
||||
Ast *ast = ast_new_curr(c, AST_CT_ECHO_STMT);
|
||||
advance_and_verify(c, TOKEN_CT_ECHO);
|
||||
TRY_CONSUME_OR_RET(TOKEN_LPAREN, "'$echo' needs a '(' here, did you forget it?", poisoned_ast);
|
||||
ASSIGN_EXPR_OR_RET(ast->expr_stmt, parse_constant_expr(c), poisoned_ast);
|
||||
|
||||
TRY_CONSUME_OR_RET(TOKEN_RPAREN, "The ending ')' was expected here.", poisoned_ast);
|
||||
do
|
||||
{
|
||||
if (!tok_is(c, TOKEN_EOS))
|
||||
{
|
||||
sema_error_at_after(c->prev_span, "Expected ';'");
|
||||
return poisoned_ast;
|
||||
}
|
||||
advance(c);
|
||||
}
|
||||
while (0);
|
||||
return ast;
|
||||
}
|
||||
|
||||
Ast *parse_stmt(ParseContext *c)
|
||||
{
|
||||
switch (c->tok)
|
||||
@@ -1166,6 +1187,8 @@ Ast *parse_stmt(ParseContext *c)
|
||||
SEMA_ERROR_HERE("'default' was found outside of 'switch', did you mismatch a '{ }' pair?");
|
||||
advance(c);
|
||||
return poisoned_ast;
|
||||
case TOKEN_CT_ECHO:
|
||||
return parse_ct_echo_stmt(c);
|
||||
case TOKEN_CT_ASSERT:
|
||||
return parse_ct_assert_stmt(c);
|
||||
case TOKEN_CT_IF:
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
Decl *parse_top_level_statement(ParseContext *c, ParseContext **new_context);
|
||||
Ast *parse_ct_assert_stmt(ParseContext *c);
|
||||
Ast *parse_ct_echo_stmt(ParseContext *c);
|
||||
Ast *parse_stmt(ParseContext *c);
|
||||
Path *parse_path_prefix(ParseContext *c, bool *had_error);
|
||||
Expr *parse_type_expression_with_path(ParseContext *c, Path *path);
|
||||
|
||||
@@ -2850,6 +2850,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
|
||||
case DECL_CT_CASE:
|
||||
case DECL_CT_IF:
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_FAULTVALUE:
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_BODYPARAM:
|
||||
|
||||
@@ -566,6 +566,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_DEFINE:
|
||||
case DECL_CT_ECHO:
|
||||
UNREACHABLE
|
||||
}
|
||||
switch (decl->var.kind)
|
||||
|
||||
@@ -68,6 +68,7 @@ void sema_analysis_pass_register_globals(Module *module);
|
||||
void sema_analysis_pass_conditional_compilation(Module *module);
|
||||
void sema_analysis_pass_decls(Module *module);
|
||||
void sema_analysis_pass_ct_assert(Module *module);
|
||||
void sema_analysis_pass_ct_echo(Module *module);
|
||||
void sema_analysis_pass_functions(Module *module);
|
||||
void sema_analyze_stage(Module *module, AnalysisStage stage);
|
||||
|
||||
|
||||
@@ -337,6 +337,29 @@ void sema_analysis_pass_ct_assert(Module *module)
|
||||
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);
|
||||
}
|
||||
|
||||
void sema_analysis_pass_ct_echo(Module *module)
|
||||
{
|
||||
DEBUG_LOG("Pass: $echo checks %s", module->name->module);
|
||||
VECEACH(module->units, index)
|
||||
{
|
||||
SemaContext context;
|
||||
sema_context_init(&context, module->units[index]);
|
||||
Decl **echos = context.unit->ct_echos;
|
||||
bool success = true;
|
||||
VECEACH(echos, i)
|
||||
{
|
||||
if (!sema_analyse_ct_echo_stmt(&context, echos[i]->ct_echo_decl))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sema_context_destroy(&context);
|
||||
if (!success) break;
|
||||
}
|
||||
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);
|
||||
}
|
||||
|
||||
static inline bool analyse_func_body(SemaContext *context, Decl *decl)
|
||||
{
|
||||
if (!decl->func_decl.body) return true;
|
||||
|
||||
@@ -2402,9 +2402,6 @@ static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
Expr *expr = exprptr(statement->assert_stmt.expr);
|
||||
@@ -2424,7 +2421,7 @@ bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement)
|
||||
if (res == -1) return false;
|
||||
if (!res)
|
||||
{
|
||||
if (message)
|
||||
if (message_expr)
|
||||
{
|
||||
SEMA_ERROR(expr, "Compile time assert - %.*s", EXPAND_EXPR_STRING(message_expr));
|
||||
}
|
||||
@@ -2438,6 +2435,51 @@ bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sema_analyse_ct_echo_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
Expr *message = statement->expr_stmt;
|
||||
if (!sema_analyse_expr(context, message)) return false;
|
||||
if (message->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(message, "Expected a constant value.");
|
||||
return false;
|
||||
}
|
||||
printf("] ");
|
||||
switch (message->const_expr.const_kind)
|
||||
{
|
||||
case CONST_FLOAT:
|
||||
printf("%f\n", (double)message->const_expr.fxx.f);
|
||||
break;
|
||||
case CONST_INTEGER:
|
||||
puts(int_to_str(message->const_expr.ixx, 10));
|
||||
break;
|
||||
case CONST_BOOL:
|
||||
puts(message->const_expr.b ? "true" : "false");
|
||||
break;
|
||||
case CONST_ENUM:
|
||||
case CONST_ERR:
|
||||
puts(message->const_expr.enum_err_val->name);
|
||||
break;
|
||||
case CONST_STRING:
|
||||
printf("%.*s\n", EXPAND_EXPR_STRING(message));
|
||||
break;
|
||||
case CONST_POINTER:
|
||||
printf("%p\n", (void*)message->const_expr.ptr);
|
||||
break;
|
||||
case CONST_TYPEID:
|
||||
puts(type_to_error_string(message->const_expr.typeid));
|
||||
break;
|
||||
case CONST_BYTES:
|
||||
case CONST_INITIALIZER:
|
||||
case CONST_UNTYPED_LIST:
|
||||
case CONST_MEMBER:
|
||||
SEMA_ERROR(message, "Unsupported type for '$echo'");
|
||||
break;
|
||||
}
|
||||
statement->ast_kind = AST_NOP_STMT;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* $for(<list of ct decl/expr>, <cond>, <incr>):
|
||||
*/
|
||||
@@ -2560,6 +2602,8 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state
|
||||
return sema_analyse_ct_assert_stmt(context, statement);
|
||||
case AST_CT_IF_STMT:
|
||||
return sema_analyse_ct_if_stmt(context, statement);
|
||||
case AST_CT_ECHO_STMT:
|
||||
return sema_analyse_ct_echo_stmt(context, statement);
|
||||
case AST_DECLARE_STMT:
|
||||
return sema_analyse_declare_stmt(context, statement);
|
||||
case AST_DEFAULT_STMT:
|
||||
|
||||
@@ -240,6 +240,7 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
|
||||
case DECL_CT_SWITCH:
|
||||
case DECL_CT_CASE:
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_BODYPARAM:
|
||||
UNREACHABLE
|
||||
|
||||
@@ -141,6 +141,9 @@ void sema_analyze_stage(Module *module, AnalysisStage stage)
|
||||
case ANALYSIS_DECLS:
|
||||
sema_analysis_pass_decls(module);
|
||||
break;
|
||||
case ANALYSIS_CT_ECHO:
|
||||
sema_analysis_pass_ct_echo(module);
|
||||
break;
|
||||
case ANALYSIS_CT_ASSERT:
|
||||
sema_analysis_pass_ct_assert(module);
|
||||
break;
|
||||
@@ -166,6 +169,7 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls)
|
||||
case DECL_IMPORT:
|
||||
case DECL_LABEL:
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
|
||||
@@ -390,6 +390,8 @@ const char *token_type_to_string(TokenType type)
|
||||
return "$typeof";
|
||||
case TOKEN_CT_STRINGIFY:
|
||||
return "$stringify";
|
||||
case TOKEN_CT_ECHO:
|
||||
return "$echo";
|
||||
case TOKEN_EOF:
|
||||
return "EOF";
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.111"
|
||||
#define COMPILER_VERSION "0.3.112"
|
||||
Reference in New Issue
Block a user