mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
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:
committed by
Christoffer Lerno
parent
321ee81c9d
commit
9572c4afc9
@@ -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
14
resources/lib/std/env.c3
Normal 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};
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
65
test/test_suite/compile_time/ct_if.c3t
Normal file
65
test/test_suite/compile_time/ct_if.c3t
Normal 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
|
||||
31
test/test_suite/compile_time/ct_if_fails.c3
Normal file
31
test/test_suite/compile_time/ct_if_fails.c3
Normal 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;
|
||||
Reference in New Issue
Block a user