From 9572c4afc91ba79def6fd1f137fe9738824522b0 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 24 Jun 2021 17:59:29 +0200 Subject: [PATCH] Top level $if now uses $if: / $endif; Fix of boolean globals. Fix of $else: clause. Fix of $assert inside of $if --- resources/lib/std/cinterop.c3 | 93 ++++++++++----------- resources/lib/std/env.c3 | 14 ++++ src/compiler/ast.c | 6 ++ src/compiler/compiler.c | 36 +++++--- src/compiler/compiler_internal.h | 3 +- src/compiler/context.c | 3 + src/compiler/copying.c | 3 + src/compiler/enums.h | 13 ++- src/compiler/headers.c | 15 +--- src/compiler/llvm_codegen.c | 4 + src/compiler/llvm_codegen_function.c | 10 +-- src/compiler/parse_expr.c | 2 + src/compiler/parse_global.c | 57 +++++-------- src/compiler/parse_stmt.c | 27 +----- src/compiler/sema_decls.c | 1 + src/compiler/sema_expr.c | 1 + src/compiler/sema_passes.c | 4 +- src/compiler/sema_types.c | 1 + src/compiler/tokens.c | 4 + test/test_suite/compile_time/ct_if.c3t | 65 ++++++++++++++ test/test_suite/compile_time/ct_if_fails.c3 | 31 +++++++ 21 files changed, 254 insertions(+), 139 deletions(-) create mode 100644 resources/lib/std/env.c3 create mode 100644 test/test_suite/compile_time/ct_if.c3t create mode 100644 test/test_suite/compile_time/ct_if_fails.c3 diff --git a/resources/lib/std/cinterop.c3 b/resources/lib/std/cinterop.c3 index 5a9b5bebe..4259d8603 100644 --- a/resources/lib/std/cinterop.c3 +++ b/resources/lib/std/cinterop.c3 @@ -1,78 +1,77 @@ module std::cinterop; -$assert (${C_SHORT_SIZE} < 32); -$assert (${C_LONG_TYPE) < 128); +const C_INT_SIZE = ${C_INT_SIZE}; +const C_LONG_SIZE = ${C_LONG_SIZE}; +const C_SHORT_SIZE = ${C_SHORT_SIZE}; +const C_LONG_LONG_SIZE = ${C_LONG_LONG_SIZE}; -$if (${C_INT_SIZE} == 64) -{ +$assert (C_SHORT_SIZE < 32); +$assert (C_INT_SIZE < 128); +$assert (C_LONG_SIZE < 128); +$assert (C_LONG_LONG_SIZE <= 128); +$assert (C_SHORT_SIZE <= C_INT_SIZE); +$assert (C_INT_SIZE <= C_LONG_SIZE); +$assert (C_LONG_SIZE <= C_LONG_LONG_SIZE); + +$if (C_INT_SIZE == 64): define CInt = long; define CUInt = ulong; -} -$elseif (${C_INT_SIZE} == 32) -{ +$elif (C_INT_SIZE == 32): define CInt = int; define CUInt = uint; -} -$elseif (${C_INT_SIZE} == 16) -{ +$elif (C_INT_SIZE == 16): define CInt = short; define CUInt = ushort; -} -$else -{ +$else: $assert(false, "Invalid C int size"); -} +$endif; -$if (${C_LONG_SIZE} == 64) -{ +$if (C_LONG_SIZE == 64): define CLong = long; define CULong = ulong; -} -$elseif (${C_LONG_SIZE} == 32) -{ +$elif (C_LONG_SIZE == 32): define CLong = int; define CULong = uint; -} -$elseif (${C_LONG_SIZE} == 16) -{ +$elif (C_LONG_SIZE == 16): define CLong = short; define CULong = ushort; -} -$else -{ +$else: $assert(false, "Invalid C long size"); -} +$endif; -$if (${C_SHORT_SIZE} == 32) -{ +$if (C_SHORT_SIZE == 32): define CShort = int; define CUShort = uint; -} -$elseif (${C_SHORT_SIZE} == 16) -{ +$elif (C_SHORT_SIZE == 16): define CShort = short; define CUShort = ushort; -} -$elseif (${C_SHORT_SIZE} == 8) -{ +$elif (C_SHORT_SIZE == 8): define CShort = ichar; define CUShort = char; -} -$else -{ +$else: $assert(false, "Invalid C short size"); -} +$endif; + +$if (C_LONG_LONG_SIZE == 128): + define CLongLong = i128; + define CULongLong = u128; +$elif (C_LONG_LONG_SIZE == 64): + define CLongLong = long; + define CULongLong = ulong; +$elif (C_LONG_LONG_SIZE == 32): + define CLongLong = int; + define CULongLong = uint; +$elif (C_LONG_LONG_SIZE == 16): + define CLongLong = short; + define CULongLong = ushort; +$else: + $assert(false, "Invalid C long long size"); +$endif; + +define CSChar = ichar; +define CUChar = char; /* define CChar = ${C_CHAR_TYPE}; define CSChar = ${C_SCHAR_TYPE}; -define CShort = ${C_SHORT_TYPE}; -define CInt = ${C_INT_TYPE}; -define CLong = $(C_LONG_TYPE); -define CLongLong = ${C_LONGLONG_TYPE}; -define CUChar = ${C_UCHAR_TYPE}; -define CUShort = ${C_USHORT_TYPE}; -define CUInt = ${C_UINT_TYPE}; -define CULong = $(C_ULONG_TYPE); -define CULongLong = ${C_ULONGLONG_TYPE}; */ diff --git a/resources/lib/std/env.c3 b/resources/lib/std/env.c3 new file mode 100644 index 000000000..3a63bbd55 --- /dev/null +++ b/resources/lib/std/env.c3 @@ -0,0 +1,14 @@ +module std::env; + +enum CompilerOptLevel +{ + O0, + O1, + O2, + O3 +} + +const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)(${COMPILER_OPT_LEVEL}); +const bool LITTLE_ENDIAN = ${PLATFORM_LITTLE_ENDIAN}; +const bool I128_SUPPORT = ${PLATFORM_I128_SUPPORTED}; +const bool COMPILER_SAFE_MODE = ${COMPILER_SAFE_MODE}; diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 16d9a1962..3e9781743 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -52,6 +52,8 @@ const char *decl_to_name(Decl *decl) { case DECL_POISONED: return "poisoned decl"; + case DECL_CT_ASSERT: + return "compile time assert"; case DECL_CT_CASE: return "compile time case"; case DECL_CT_ELIF: @@ -185,6 +187,7 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_DEFINE: + case DECL_CT_ASSERT: UNREACHABLE } Type *type = type_new(kind, !name.index ? "anon" : TOKSTR(name)); @@ -881,6 +884,9 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent) break; } DUMPEND(); + case DECL_CT_ASSERT: + DUMP("$assert"); + DUMPEND(); case DECL_DEFINE: DUMPF("(define %s", decl->name); DUMPEND(); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index ba2673b02..137c76249 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -158,6 +158,7 @@ static void register_generic_decls(Module *module, Decl **decls) case DECL_ENUM_CONSTANT: case DECL_IMPORT: case DECL_LABEL: + case DECL_CT_ASSERT: continue; case DECL_ATTRIBUTE: break; @@ -239,22 +240,12 @@ static void add_global_define(const char *name, Expr *value) stable_set(&dec->module->symbols, dec->name, dec); } -static void add_global_define_int(const char *name, uint64_t int_value) -{ - Expr *value = expr_new(EXPR_CONST, INVALID_RANGE); - value->const_expr.kind = TYPE_IXX; - value->original_type = type_compint; - expr_const_set_int(&value->const_expr, int_value, TYPE_IXX); - value->type = type_compint; - value->resolve_status = RESOLVE_DONE; - add_global_define(name, value); -} - static void setup_int_define(const char *id, uint64_t i) { TokenType token_type = TOKEN_CONST_IDENT; id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type); Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE); + expr->constant = true; expr_const_set_int(&expr->const_expr, i, TYPE_IXX); expr->original_type = expr->type = type_compint; expr->span = INVALID_RANGE; @@ -266,17 +257,40 @@ static void setup_int_define(const char *id, uint64_t i) } } +static void setup_bool_define(const char *id, bool value) +{ + TokenType token_type = TOKEN_CONST_IDENT; + id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type); + Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE); + expr_const_set_bool(&expr->const_expr, value); + expr->original_type = expr->type = type_bool; + expr->constant = true; + expr->span = INVALID_RANGE; + expr->resolve_status = RESOLVE_NOT_DONE; + void *previous = stable_set(&global_context.compiler_defines, id, expr); + if (previous) + { + error_exit("Redefined ident %s", id); + } +} void compiler_compile(void) { setup_int_define("C_SHORT_SIZE", platform_target.width_c_short); setup_int_define("C_INT_SIZE", platform_target.width_c_int); setup_int_define("C_LONG_SIZE", platform_target.width_c_long); setup_int_define("C_LONG_LONG_SIZE", platform_target.width_c_long_long); + setup_bool_define("PLATFORM_LITTLE_ENDIAN", platform_target.little_endian); + setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128); + setup_int_define("COMPILER_OPT_LEVEL", (int)active_target.optimization_level); + setup_int_define("COMPILER_SIZE_OPT_LEVEL", (int)active_target.size_optimization_level); + setup_bool_define("COMPILER_SAFE_MODE", active_target.feature.safe_mode); global_context_clear_errors(); if (global_context.lib_dir) { + vec_add(global_context.sources, strformat("%s/std/env.c3", global_context.lib_dir)); + vec_add(global_context.sources, strformat("%s/std/cinterop.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/runtime.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/builtin.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/io.c3", global_context.lib_dir)); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 88290c8fd..491a0a2e7 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -532,6 +532,7 @@ typedef struct Decl_ CtIfDecl ct_elif_decl; CtSwitchDecl ct_switch_decl; CtCaseDecl ct_case_decl; + Ast *ct_assert_decl; Decl** ct_else_decl; Expr *incr_array_decl; }; @@ -1274,7 +1275,7 @@ typedef struct Context_ Decl **vars; Decl **incr_array; Decl **ct_ifs; - Ast **ct_asserts; + Decl **ct_asserts; Decl *active_function_for_analysis; Token *comments; Token *lead_comment; diff --git a/src/compiler/context.c b/src/compiler/context.c index 2a849eb52..eba757701 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -167,6 +167,9 @@ void context_register_global_decl(Context *context, Decl *decl) case DECL_CT_SWITCH: vec_add(context->ct_ifs, decl); return; + case DECL_CT_ASSERT: + vec_add(context->ct_asserts, decl); + return; } DEBUG_LOG("Registering symbol '%s'.", decl->name); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index aadd2cafa..b0653ead4 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -541,6 +541,9 @@ Decl *copy_decl(Decl *decl) MACRO_COPY_DECL(decl->ct_if_decl.elif); MACRO_COPY_DECL_LIST(decl->ct_if_decl.then); break; + case DECL_CT_ASSERT: + MACRO_COPY_AST(decl->ct_assert_decl); + break; case DECL_CT_ELSE: MACRO_COPY_DECL_LIST(decl->ct_else_decl); break; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index cb5066506..3bd01be48 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -138,6 +138,7 @@ typedef enum DECL_CT_ELSE, DECL_CT_IF, DECL_CT_SWITCH, + DECL_CT_ASSERT, DECL_DEFINE, DECL_DISTINCT, DECL_ENUM, @@ -158,7 +159,7 @@ typedef enum #define NON_TYPE_DECLS DECL_ARRAY_VALUE: case DECL_IMPORT: case DECL_MACRO: \ case DECL_GENERIC: 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_DEFINE: case DECL_CT_ASSERT typedef enum { @@ -347,6 +348,7 @@ typedef enum TOKEN_DOUBLE, TOKEN_FLOAT, TOKEN_HALF, + TOKEN_I128, TOKEN_ICHAR, TOKEN_INT, TOKEN_IPTR, @@ -354,6 +356,7 @@ typedef enum TOKEN_ISIZE, TOKEN_LONG, TOKEN_SHORT, + TOKEN_U128, TOKEN_UINT, TOKEN_ULONG, TOKEN_UPTR, @@ -460,6 +463,14 @@ typedef enum TOKEN_LAST = TOKEN_EOF, } TokenType; +#define NON_VOID_TYPE_TOKENS \ + TOKEN_BOOL: case TOKEN_CHAR: case TOKEN_DOUBLE: case TOKEN_FLOAT: \ + case TOKEN_HALF: case TOKEN_I128: case TOKEN_ICHAR: case TOKEN_INT: \ + case TOKEN_IPTR: case TOKEN_IPTRDIFF: case TOKEN_ISIZE: case TOKEN_LONG: \ + case TOKEN_SHORT: case TOKEN_U128: case TOKEN_UINT: case TOKEN_ULONG: \ + case TOKEN_UPTR: case TOKEN_UPTRDIFF: case TOKEN_USHORT: case TOKEN_USIZE: \ + case TOKEN_QUAD: case TOKEN_TYPEID +#define TYPE_TOKENS NON_VOID_TYPE_TOKENS: case TOKEN_VOID // Note that ordering matters here. If ordering is changed, // So must type_find_max_type and friends. diff --git a/src/compiler/headers.c b/src/compiler/headers.c index c195c6865..ec0b4d4fa 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -192,21 +192,10 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl) { switch (decl->decl_kind) { + case NON_TYPE_DECLS: + case DECL_ENUM_CONSTANT: case DECL_POISONED: case DECL_VAR: - case DECL_LABEL: - case DECL_ENUM_CONSTANT: - case DECL_ARRAY_VALUE: - case DECL_IMPORT: - case DECL_MACRO: - case DECL_GENERIC: - 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_DEFINE: case DECL_INTERFACE: UNREACHABLE case DECL_FUNC: diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 3f76f548e..b57c13219 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -788,6 +788,10 @@ LLVMValueRef llvm_value_rvalue_store(GenContext *c, BEValue *value) value->alignment ?: type_abi_alignment(value->type), ""); case BE_BOOLEAN: + if (!c->builder) + { + return LLVMConstZExt(value->value, c->byte_type); + } return LLVMBuildZExt(c->builder, value->value, c->byte_type, ""); } UNREACHABLE diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index a51f40c7b..c970ce3dc 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -617,8 +617,6 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl) switch (decl->decl_kind) { case DECL_POISONED: - case DECL_TYPEDEF: - case DECL_DISTINCT: UNREACHABLE; case DECL_FUNC: decl->backend_ref = LLVMAddFunction(context->module, decl->cname ?: decl->external_name, @@ -629,8 +627,6 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl) decl->backend_ref = LLVMAddGlobal(context->module, llvm_get_type(context, decl->type), decl->cname ?: decl->external_name); LLVMSetVisibility(decl->backend_ref, LLVMDefaultVisibility); break; - case DECL_ENUM_CONSTANT: - TODO case DECL_STRUCT: case DECL_UNION: case DECL_ERR: @@ -646,9 +642,13 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl) { llvm_emit_function_decl(context, decl->methods[i]); } - TODO + // TODO // Fix typeid + return; + case DECL_TYPEDEF: + case DECL_DISTINCT: case NON_TYPE_DECLS: case DECL_INTERFACE: + case DECL_ENUM_CONSTANT: return; } } diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 2223c111e..4d64b03e4 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -1047,6 +1047,8 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_UINT] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_LONG] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_ULONG] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_I128] = { parse_type_identifier, NULL, PREC_NONE }, + [TOKEN_U128] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_ISIZE] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_USIZE] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_IPTR] = { parse_type_identifier, NULL, PREC_NONE }, diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 2af23c9ac..5c695df4e 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -95,27 +95,7 @@ void recover_top_level(Context *context) case TOKEN_CT_FOR: case TOKEN_CT_SWITCH: case TOKEN_FUNC: - case TOKEN_VOID: - case TOKEN_BOOL: - case TOKEN_CHAR: - case TOKEN_DOUBLE: - case TOKEN_FLOAT: - case TOKEN_HALF: - case TOKEN_ICHAR: - case TOKEN_INT: - case TOKEN_IPTR: - case TOKEN_IPTRDIFF: - case TOKEN_ISIZE: - case TOKEN_LONG: - case TOKEN_SHORT: - case TOKEN_UINT: - case TOKEN_ULONG: - case TOKEN_UPTR: - case TOKEN_UPTRDIFF: - case TOKEN_USHORT: - case TOKEN_USIZE: - case TOKEN_QUAD: - case TOKEN_TYPEID: + case TYPE_TOKENS: // Only recover if this is in the first col. if (TOKLOC(context->tok)->col == 1) return; advance(context); @@ -129,30 +109,30 @@ void recover_top_level(Context *context) #pragma mark --- Parse CT conditional code -static inline bool parse_top_level_block(Context *context, Decl ***decls) +static inline bool parse_top_level_block(Context *context, Decl ***decls, TokenType end1, TokenType end2, TokenType end3) { - CONSUME_OR(TOKEN_LBRACE, false); - while (!TOKEN_IS(TOKEN_RBRACE) && !TOKEN_IS(TOKEN_EOF)) + CONSUME_OR(TOKEN_COLON, false); + while (!TOKEN_IS(end1) && !TOKEN_IS(end2) && !TOKEN_IS(end3) && !TOKEN_IS(TOKEN_EOF)) { Decl *decl = parse_top_level_statement(context); - if (decl == NULL) continue; + assert(decl); if (decl_ok(decl)) { vec_add(*decls, decl); } else { - recover_top_level(context); + return false; } } - CONSUME_OR(TOKEN_RBRACE, false); return true; } /** - * ct_if_top_level ::= CT_IF const_paren_expr top_level_block - (CT_ELIF const_paren_expr top_level_block)* + * ct_if_top_level ::= CT_IF const_paren_expr ':' top_level_block + (CT_ELIF const_paren_expr ':' top_level_block)* (CT_ELSE top_level_block)? + CT_ENDIF * @param context * @return the declaration if successfully parsed, poisoned_decl otherwise. */ @@ -162,7 +142,7 @@ static inline Decl *parse_ct_if_top_level(Context *context) advance_and_verify(context, TOKEN_CT_IF); ct->ct_if_decl.expr = TRY_EXPR_OR(parse_const_paren_expr(context), poisoned_decl); - if (!parse_top_level_block(context, &ct->ct_if_decl.then)) return poisoned_decl; + if (!parse_top_level_block(context, &ct->ct_if_decl.then, TOKEN_CT_ENDIF, TOKEN_CT_ELIF, TOKEN_CT_ELSE)) return poisoned_decl; CtIfDecl *ct_if_decl = &ct->ct_if_decl; while (TOKEN_IS(TOKEN_CT_ELIF)) @@ -170,7 +150,7 @@ static inline Decl *parse_ct_if_top_level(Context *context) advance_and_verify(context, TOKEN_CT_ELIF); Decl *ct_elif = DECL_NEW(DECL_CT_ELIF, VISIBLE_LOCAL); ct_elif->ct_elif_decl.expr = TRY_EXPR_OR(parse_const_paren_expr(context), poisoned_decl); - if (!parse_top_level_block(context, &ct_elif->ct_elif_decl.then)) return poisoned_decl; + if (!parse_top_level_block(context, &ct_elif->ct_elif_decl.then, TOKEN_CT_ENDIF, TOKEN_CT_ELIF, TOKEN_CT_ELSE)) return poisoned_decl; ct_if_decl->elif = ct_elif; ct_if_decl = &ct_elif->ct_elif_decl; } @@ -179,8 +159,10 @@ static inline Decl *parse_ct_if_top_level(Context *context) advance_and_verify(context, TOKEN_CT_ELSE); Decl *ct_else = DECL_NEW(DECL_CT_ELSE, VISIBLE_LOCAL); ct_if_decl->elif = ct_else; - if (!parse_top_level_block(context, &ct_else->ct_else_decl)) return poisoned_decl; + if (!parse_top_level_block(context, &ct_else->ct_else_decl, TOKEN_CT_ENDIF, TOKEN_CT_ENDIF, TOKEN_CT_ENDIF)) return poisoned_decl; } + CONSUME_OR(TOKEN_CT_ENDIF, poisoned_decl); + CONSUME_OR(TOKEN_EOS, poisoned_decl); return ct; } @@ -567,6 +549,9 @@ static inline TypeInfo *parse_base_type(Context *context) case TOKEN_FLOAT: type_found = type_float; break; + case TOKEN_I128: + type_found = type_i128; + break; case TOKEN_ICHAR: type_found = type_ichar; break; @@ -588,6 +573,9 @@ static inline TypeInfo *parse_base_type(Context *context) case TOKEN_SHORT: type_found = type_short; break; + case TOKEN_U128: + type_found = type_u128; + break; case TOKEN_UINT: type_found = type_uint; break; @@ -2288,13 +2276,14 @@ Decl *parse_top_level_statement(Context *context) if (!check_no_visibility_before(context, visibility)) return poisoned_decl; { Ast *ast = TRY_AST_OR(parse_ct_assert_stmt(context), false); - vec_add(context->ct_asserts, ast); + decl = decl_new(DECL_CT_ASSERT, ast->span.loc, visibility); + decl->ct_assert_decl = ast; if (docs) { SEMA_ERROR(docs, "Unexpected doc comment before $assert, did you mean to use a regular comment?"); return poisoned_decl; } - return NULL; + return decl; } case TOKEN_CT_IF: if (!check_no_visibility_before(context, visibility)) return poisoned_decl; diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 3c9794f74..05e921c1a 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -994,37 +994,14 @@ Ast *parse_stmt(Context *context) UNREACHABLE case TOKEN_LBRACE: return parse_compound_stmt(context); - case TOKEN_HALF: - case TOKEN_QUAD: - SEMA_TOKEN_ERROR(context->tok, "Type is unsupported by platform."); - advance(context); - return poisoned_ast; - case TOKEN_VOID: - case TOKEN_CHAR: - case TOKEN_BOOL: - case TOKEN_DOUBLE: - case TOKEN_FLOAT: - case TOKEN_ICHAR: - case TOKEN_INT: - case TOKEN_ISIZE: - case TOKEN_LONG: - case TOKEN_SHORT: - case TOKEN_UINT: - case TOKEN_ULONG: - case TOKEN_USHORT: - case TOKEN_USIZE: - case TOKEN_IPTRDIFF: - case TOKEN_UPTRDIFF: - case TOKEN_IPTR: - case TOKEN_UPTR: + case TYPE_TOKENS: + case TOKEN_ERR: case TOKEN_VIRTUAL: - case TOKEN_TYPEID: case TOKEN_CT_TYPE_IDENT: case TOKEN_HASH_TYPE_IDENT: case TOKEN_HASH_CONST_IDENT: case TOKEN_HASH_IDENT: case TOKEN_TYPE_IDENT: - case TOKEN_ERR: case TOKEN_IDENT: case TOKEN_CONST_IDENT: return parse_decl_or_expr_stmt(context); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index f7d3fe59c..1871ded64 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1310,6 +1310,7 @@ bool sema_analyse_decl(Context *context, Decl *decl) case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_CT_IF: + case DECL_CT_ASSERT: UNREACHABLE } decl->resolve_status = RESOLVE_DONE; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 35d777f2b..8d7ad8f43 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -210,6 +210,7 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: + case DECL_CT_ASSERT: UNREACHABLE case DECL_DEFINE: TODO diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 34c6a2256..c6db39b34 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -148,7 +148,7 @@ static inline bool sema_analyse_top_level_if(Context *context, Decl *ct_if) else { assert(ct_elif->decl_kind == DECL_CT_ELSE); - sema_append_decls(context, ct_elif->ct_elif_decl.then); + sema_append_decls(context, ct_elif->ct_else_decl); return true; } } @@ -180,7 +180,7 @@ void sema_analysis_pass_ct_assert(Module *module) Context *context = module->contexts[index]; VECEACH(context->ct_asserts, i) { - sema_analyse_ct_assert_stmt(context, context->ct_asserts[i]); + sema_analyse_ct_assert_stmt(context, context->ct_asserts[i]->ct_assert_decl); } } DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index be3c706a6..15fbf61b9 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -129,6 +129,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_ATTRIBUTE: case DECL_CT_SWITCH: case DECL_CT_CASE: + case DECL_CT_ASSERT: UNREACHABLE } UNREACHABLE diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index ae1bab177..de17c4603 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -280,6 +280,10 @@ const char *token_type_to_string(TokenType type) return "long"; case TOKEN_ULONG: return "ulong"; + case TOKEN_I128: + return "i128"; + case TOKEN_U128: + return "u128"; case TOKEN_INT: return "int"; case TOKEN_UINT: diff --git a/test/test_suite/compile_time/ct_if.c3t b/test/test_suite/compile_time/ct_if.c3t new file mode 100644 index 000000000..006554164 --- /dev/null +++ b/test/test_suite/compile_time/ct_if.c3t @@ -0,0 +1,65 @@ +$if (0): +$else: + $if (0): + $elif (0): + $elif (0): + $else: + int x = 1; + $endif; +$endif; + +$if (0): +$assert(false); +$elif (0): +$assert(false); +$else: +$assert(true); +$endif; + +$if (1): +$assert(true); +int d = 5; +$elif (0): +$assert(false); +$else: +$assert(false); +$endif; + +$if (0): +$assert(true); +$elif (1): +$assert(true); +int c = 5; +$else: +$assert(false); +$endif; + +$if (0): +$assert(true); +$elif (1): +$assert(true); +int b = 4; +$elif (0): +$assert(false); +$else: +$assert(false); +$endif; + +$if (0): +$assert(true); +$elif (0): +$assert(false); +$elif (1): +$assert(true); +int a = 3; +$else: +$assert(false); +$endif; + +// #expect: ct_if.ll + +@ct_if.d = global i32 5, align 4 +@ct_if.c = global i32 5, align 4 +@ct_if.b = global i32 4, align 4 +@ct_if.a = global i32 3, align 4 +@ct_if.x = global i32 1, align 4 \ No newline at end of file diff --git a/test/test_suite/compile_time/ct_if_fails.c3 b/test/test_suite/compile_time/ct_if_fails.c3 new file mode 100644 index 000000000..c40e74589 --- /dev/null +++ b/test/test_suite/compile_time/ct_if_fails.c3 @@ -0,0 +1,31 @@ +$if 3: // #error: Expected '(' +$endif; + +int x; +$if (x > 0): +$endif; + +$if (0): + $assert(false); +$endif; + +$if (1): +$else: +$endif; + +$if (1): +$else: +$else: // #error: Expected a top level declaration here. +$endif; + + +$if (1): +$elif (2): +$else: +$endif; + +$if (1): +$elif (2): +$elif (3): +$else: +$endif;