Output messages at compile time.

This commit is contained in:
Christoffer Lerno
2022-12-07 18:48:55 +01:00
parent 1ea5625183
commit eaaa5362a5
19 changed files with 154 additions and 15 deletions

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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;

View File

@@ -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:

View File

@@ -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);

View File

@@ -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:

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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:

View File

@@ -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

View File

@@ -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:

View File

@@ -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";

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.3.111"
#define COMPILER_VERSION "0.3.112"