Top level $if now uses $if: / $endif; Fix of boolean globals. Fix of $else: clause. Fix of $assert inside of $if

This commit is contained in:
Christoffer Lerno
2021-06-24 17:59:29 +02:00
committed by Christoffer Lerno
parent 321ee81c9d
commit 9572c4afc9
21 changed files with 254 additions and 139 deletions

View File

@@ -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};
*/

14
resources/lib/std/env.c3 Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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