mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Removed original_type, pure, removed bigint, added i128 type, lots of fixes to $Foo, reassigning ct type, catch/macro, "!", removed type inference.
This commit is contained in:
committed by
Christoffer Lerno
parent
1b086e06f1
commit
b4df56db54
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,4 +1,4 @@
|
|||||||
$ cat .gitattributes
|
$ cat .gitattributes
|
||||||
* text=auto
|
* text=lf
|
||||||
*.c3 linguist-language=C
|
*.c3 linguist-language=C
|
||||||
*.c3t linguist-language=C
|
*.c3t linguist-language=C
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ add_executable(c3c
|
|||||||
src/compiler/sema_types.c
|
src/compiler/sema_types.c
|
||||||
src/compiler/sema_stmts.c
|
src/compiler/sema_stmts.c
|
||||||
src/compiler/number.c
|
src/compiler/number.c
|
||||||
|
src/compiler/float.c
|
||||||
src/compiler/linker.c
|
src/compiler/linker.c
|
||||||
src/utils/vmem.c
|
src/utils/vmem.c
|
||||||
src/utils/vmem.h
|
src/utils/vmem.h
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ const DOUBLE_MIN_10_EXP = -307;
|
|||||||
const DOUBLE_MAX_EXP = 1024;
|
const DOUBLE_MAX_EXP = 1024;
|
||||||
const DOUBLE_MIN_EXP = -1021;
|
const DOUBLE_MIN_EXP = -1021;
|
||||||
const DOUBLE_EPSILON = 2.22044604925031308085e-16;
|
const DOUBLE_EPSILON = 2.22044604925031308085e-16;
|
||||||
|
/*
|
||||||
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
|
const QUAD_MAX = 1.18973149535723176508575932662800702e+4932;
|
||||||
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
|
const QUAD_MIN = 3.36210314311209350626267781732175260e-4932;
|
||||||
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
|
const QUAD_DENORM_MIN = 6.47517511943802511092443895822764655e-4966;
|
||||||
@@ -62,7 +62,7 @@ const QUAD_MIN_10_EXP = -4931;
|
|||||||
const QUAD_MAX_EXP = 16384;
|
const QUAD_MAX_EXP = 16384;
|
||||||
const QUAD_MIN_EXP = -16481;
|
const QUAD_MIN_EXP = -16481;
|
||||||
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
|
const QUAD_EPSILON = 1.92592994438723585305597794258492732e-34;
|
||||||
|
*/
|
||||||
private union DoubleLong
|
private union DoubleLong
|
||||||
{
|
{
|
||||||
double f;
|
double f;
|
||||||
@@ -107,13 +107,13 @@ func double log10(double x)
|
|||||||
hx += 0x3ff00000 - 0x3fe6a09e;
|
hx += 0x3ff00000 - 0x3fe6a09e;
|
||||||
k += (int)(hx >> 20) - 0x3ff;
|
k += (int)(hx >> 20) - 0x3ff;
|
||||||
hx = (hx & 0x000fffff) + 0x3fe6a09e;
|
hx = (hx & 0x000fffff) + 0x3fe6a09e;
|
||||||
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff);
|
u.i = (ulong)(hx << 32) | (u.i & 0xffffffffu64);
|
||||||
x = u.f;
|
x = u.f;
|
||||||
|
|
||||||
hx += 0x3ff00000 - 0x3fe6a09e;
|
hx += 0x3ff00000 - 0x3fe6a09e;
|
||||||
k += (int)(hx >> 20) - 0x3ff;
|
k += (int)(hx >> 20) - 0x3ff;
|
||||||
hx = (hx & 0x000fffff) + 0x3fe6a09e;
|
hx = (hx & 0x000fffff) + 0x3fe6a09e;
|
||||||
u.i = (ulong)(hx << 32) | (u.i & 0xffffffff);
|
u.i = (ulong)(hx << 32) | (u.i & 0xffffffffu64);
|
||||||
x = u.f;
|
x = u.f;
|
||||||
|
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ func double log10(double x)
|
|||||||
double hi = f - hfsq;
|
double hi = f - hfsq;
|
||||||
u.f = hi;
|
u.f = hi;
|
||||||
// u.i &= (ulong)(-1) << 32;
|
// u.i &= (ulong)(-1) << 32;
|
||||||
u.i &= 0xFFFFFFFF00000000;
|
u.i &= 0xFFFFFFFF00000000u64;
|
||||||
hi = u.f;
|
hi = u.f;
|
||||||
double lo = f - hi - hfsq + s * (hfsq + r);
|
double lo = f - hi - hfsq + s * (hfsq + r);
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ Expr *expr_new(ExprKind kind, SourceSpan start)
|
|||||||
Expr *expr = expr_calloc();
|
Expr *expr = expr_calloc();
|
||||||
expr->expr_kind = kind;
|
expr->expr_kind = kind;
|
||||||
expr->span = start;
|
expr->span = start;
|
||||||
expr->type = expr->original_type = NULL;
|
expr->type = NULL;
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,10 +293,6 @@ UnaryOp unary_op[TOKEN_LAST + 1] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
PostUnaryOp post_unary_op[TOKEN_LAST + 1] = {
|
|
||||||
[TOKEN_PLUSPLUS] = POSTUNARYOP_INC,
|
|
||||||
[TOKEN_MINUSMINUS] = POSTUNARYOP_DEC,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -319,11 +315,6 @@ UnaryOp unaryop_from_token(TokenType type)
|
|||||||
return unary_op[type];
|
return unary_op[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
PostUnaryOp post_unaryop_from_token(TokenType type)
|
|
||||||
{
|
|
||||||
return post_unary_op[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
static Ast poison_ast = { .ast_kind = AST_POISONED };
|
static Ast poison_ast = { .ast_kind = AST_POISONED };
|
||||||
Ast *poisoned_ast = &poison_ast;
|
Ast *poisoned_ast = &poison_ast;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,8 @@ typedef struct
|
|||||||
unsigned float_regs;
|
unsigned float_regs;
|
||||||
} Regs;
|
} Regs;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ABIArgInfo *c_abi_classify_return_type_default(Type *type);
|
ABIArgInfo *c_abi_classify_return_type_default(Type *type);
|
||||||
ABIArgInfo *c_abi_classify_argument_type_default(Type *type);
|
ABIArgInfo *c_abi_classify_argument_type_default(Type *type);
|
||||||
void c_abi_func_create_win64(FunctionSignature *signature);
|
void c_abi_func_create_win64(FunctionSignature *signature);
|
||||||
@@ -49,6 +51,7 @@ void c_abi_func_create_aarch64(FunctionSignature *signature);
|
|||||||
void c_abi_func_create_riscv(FunctionSignature *signature);
|
void c_abi_func_create_riscv(FunctionSignature *signature);
|
||||||
void c_abi_func_create_wasm(FunctionSignature *signature);
|
void c_abi_func_create_wasm(FunctionSignature *signature);
|
||||||
|
|
||||||
|
|
||||||
// Implementation
|
// Implementation
|
||||||
static inline ABIArgInfo *abi_arg_by_reg_attr(ABIArgInfo *info)
|
static inline ABIArgInfo *abi_arg_by_reg_attr(ABIArgInfo *info)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -242,13 +242,19 @@ static void add_global_define(const char *name, Expr *value)
|
|||||||
stable_set(&dec->module->symbols, dec->name, dec);
|
stable_set(&dec->module->symbols, dec->name, dec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_int_define(const char *id, uint64_t i)
|
static void setup_int_define(const char *id, uint64_t i, Type *type)
|
||||||
{
|
{
|
||||||
TokenType token_type = TOKEN_CONST_IDENT;
|
TokenType token_type = TOKEN_CONST_IDENT;
|
||||||
id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type);
|
id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type);
|
||||||
Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE);
|
Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE);
|
||||||
expr_const_set_int(&expr->const_expr, i, TYPE_IXX);
|
assert(type_is_integer(type));
|
||||||
expr->original_type = expr->type = type_compint;
|
expr_const_set_int(&expr->const_expr, i, type->type_kind);
|
||||||
|
if (expr_const_will_overflow(&expr->const_expr, type->type_kind))
|
||||||
|
{
|
||||||
|
error_exit("Integer define %s overflow.", id);
|
||||||
|
}
|
||||||
|
expr->type = type;
|
||||||
|
expr->const_expr.narrowable = true;
|
||||||
expr->span = INVALID_RANGE;
|
expr->span = INVALID_RANGE;
|
||||||
expr->resolve_status = RESOLVE_NOT_DONE;
|
expr->resolve_status = RESOLVE_NOT_DONE;
|
||||||
void *previous = stable_set(&global_context.compiler_defines, id, expr);
|
void *previous = stable_set(&global_context.compiler_defines, id, expr);
|
||||||
@@ -264,7 +270,7 @@ static void setup_bool_define(const char *id, bool value)
|
|||||||
id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type);
|
id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type);
|
||||||
Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE);
|
Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE);
|
||||||
expr_const_set_bool(&expr->const_expr, value);
|
expr_const_set_bool(&expr->const_expr, value);
|
||||||
expr->original_type = expr->type = type_bool;
|
expr->type = type_bool;
|
||||||
expr->span = INVALID_RANGE;
|
expr->span = INVALID_RANGE;
|
||||||
expr->resolve_status = RESOLVE_NOT_DONE;
|
expr->resolve_status = RESOLVE_NOT_DONE;
|
||||||
void *previous = stable_set(&global_context.compiler_defines, id, expr);
|
void *previous = stable_set(&global_context.compiler_defines, id, expr);
|
||||||
@@ -275,15 +281,15 @@ static void setup_bool_define(const char *id, bool value)
|
|||||||
}
|
}
|
||||||
void compiler_compile(void)
|
void compiler_compile(void)
|
||||||
{
|
{
|
||||||
setup_int_define("C_SHORT_SIZE", platform_target.width_c_short);
|
setup_int_define("C_SHORT_SIZE", platform_target.width_c_short, type_long);
|
||||||
setup_int_define("C_INT_SIZE", platform_target.width_c_int);
|
setup_int_define("C_INT_SIZE", platform_target.width_c_int, type_long);
|
||||||
setup_int_define("C_LONG_SIZE", platform_target.width_c_long);
|
setup_int_define("C_LONG_SIZE", platform_target.width_c_long, type_long);
|
||||||
setup_int_define("C_LONG_LONG_SIZE", platform_target.width_c_long_long);
|
setup_int_define("C_LONG_LONG_SIZE", platform_target.width_c_long_long, type_long);
|
||||||
setup_bool_define("C_CHAR_IS_SIGNED", platform_target.signed_c_char);
|
setup_bool_define("C_CHAR_IS_SIGNED", platform_target.signed_c_char);
|
||||||
setup_bool_define("PLATFORM_BIG_ENDIAN", platform_target.big_endian);
|
setup_bool_define("PLATFORM_BIG_ENDIAN", platform_target.big_endian);
|
||||||
setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128);
|
setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128);
|
||||||
setup_int_define("COMPILER_OPT_LEVEL", (int)active_target.optimization_level);
|
setup_int_define("COMPILER_OPT_LEVEL", (int)active_target.optimization_level, type_int);
|
||||||
setup_int_define("COMPILER_SIZE_OPT_LEVEL", (int)active_target.size_optimization_level);
|
setup_int_define("COMPILER_SIZE_OPT_LEVEL", (int)active_target.size_optimization_level, type_int);
|
||||||
setup_bool_define("COMPILER_SAFE_MODE", active_target.feature.safe_mode);
|
setup_bool_define("COMPILER_SAFE_MODE", active_target.feature.safe_mode);
|
||||||
|
|
||||||
global_context_clear_errors();
|
global_context_clear_errors();
|
||||||
|
|||||||
@@ -12,17 +12,8 @@
|
|||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#if DBL_DIG == LDBL_DIG
|
|
||||||
#define LONG_DOUBLE 0
|
|
||||||
#else
|
|
||||||
#define LONG_DOUBLE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LONG_DOUBLE
|
|
||||||
typedef long double Real;
|
|
||||||
#else
|
|
||||||
typedef double Real;
|
typedef double Real;
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAX_ARRAYINDEX INT64_MAX
|
#define MAX_ARRAYINDEX INT64_MAX
|
||||||
typedef uint64_t ByteSize;
|
typedef uint64_t ByteSize;
|
||||||
@@ -69,16 +60,27 @@ typedef struct Type_ Type;
|
|||||||
|
|
||||||
typedef unsigned AstId;
|
typedef unsigned AstId;
|
||||||
|
|
||||||
typedef struct BigInt_
|
typedef struct Int128_
|
||||||
{
|
{
|
||||||
unsigned digit_count;
|
uint64_t high;
|
||||||
bool is_negative;
|
uint64_t low;
|
||||||
union {
|
} Int128;
|
||||||
uint64_t digit;
|
|
||||||
uint64_t *digits;
|
|
||||||
};
|
|
||||||
} BigInt;
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Int128 i;
|
||||||
|
TypeKind type;
|
||||||
|
} Int;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Real f;
|
||||||
|
TypeKind type;
|
||||||
|
} Float;
|
||||||
|
|
||||||
|
#define UINT128_MAX ((Int128) { UINT64_MAX, UINT64_MAX })
|
||||||
|
#define INT128_MAX ((Int128) { INT64_MAX, UINT64_MAX })
|
||||||
|
#define INT128_MIN ((Int128) { (uint64_t)INT64_MIN, 0 })
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -125,19 +127,12 @@ typedef struct ConstInitializer_
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
ConstKind const_kind;
|
ConstKind const_kind : 8;
|
||||||
|
bool narrowable : 1;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
Float fxx;
|
||||||
{
|
Int ixx;
|
||||||
Real f;
|
|
||||||
TypeKind float_type;
|
|
||||||
};
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
BigInt i;
|
|
||||||
TypeKind int_type;
|
|
||||||
};
|
|
||||||
bool b;
|
bool b;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@@ -266,7 +261,7 @@ typedef struct
|
|||||||
|
|
||||||
struct Type_
|
struct Type_
|
||||||
{
|
{
|
||||||
TypeKind type_kind : 8;
|
TypeKind type_kind;
|
||||||
Type *canonical;
|
Type *canonical;
|
||||||
const char *name;
|
const char *name;
|
||||||
Type **type_cache;
|
Type **type_cache;
|
||||||
@@ -288,6 +283,8 @@ struct Type_
|
|||||||
Type *pointer;
|
Type *pointer;
|
||||||
// Type[<123>] or Type<[123]>
|
// Type[<123>] or Type<[123]>
|
||||||
TypeVector vector;
|
TypeVector vector;
|
||||||
|
// Failable
|
||||||
|
Type *failable;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -295,6 +292,7 @@ struct TypeInfo_
|
|||||||
{
|
{
|
||||||
ResolveStatus resolve_status : 3;
|
ResolveStatus resolve_status : 3;
|
||||||
bool virtual_type : 1;
|
bool virtual_type : 1;
|
||||||
|
bool failable : 1;
|
||||||
Type *type;
|
Type *type;
|
||||||
TypeInfoKind kind;
|
TypeInfoKind kind;
|
||||||
SourceSpan span;
|
SourceSpan span;
|
||||||
@@ -349,7 +347,6 @@ typedef struct VarDecl_
|
|||||||
{
|
{
|
||||||
VarDeclKind kind : 4;
|
VarDeclKind kind : 4;
|
||||||
bool constant : 1;
|
bool constant : 1;
|
||||||
bool failable : 1;
|
|
||||||
bool unwrap : 1;
|
bool unwrap : 1;
|
||||||
bool vararg : 1;
|
bool vararg : 1;
|
||||||
bool is_static : 1;
|
bool is_static : 1;
|
||||||
@@ -420,7 +417,6 @@ typedef struct FunctionSignature_
|
|||||||
CallABI call_abi : 4;
|
CallABI call_abi : 4;
|
||||||
Variadic variadic : 3;
|
Variadic variadic : 3;
|
||||||
bool has_default : 1;
|
bool has_default : 1;
|
||||||
bool failable : 1;
|
|
||||||
bool use_win64 : 1;
|
bool use_win64 : 1;
|
||||||
TypeInfo *rtype;
|
TypeInfo *rtype;
|
||||||
struct ABIArgInfo_ *ret_abi_info;
|
struct ABIArgInfo_ *ret_abi_info;
|
||||||
@@ -493,7 +489,6 @@ typedef struct
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool failable : 1;
|
|
||||||
Decl **parameters;
|
Decl **parameters;
|
||||||
TypeInfo *type_parent; // May be null
|
TypeInfo *type_parent; // May be null
|
||||||
TypeInfo *rtype; // May be null!
|
TypeInfo *rtype; // May be null!
|
||||||
@@ -663,12 +658,6 @@ typedef struct
|
|||||||
} ExprUnary;
|
} ExprUnary;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Expr* expr;
|
|
||||||
PostUnaryOp operator;
|
|
||||||
} ExprPostUnary;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -797,6 +786,7 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
CastKind kind;
|
CastKind kind;
|
||||||
|
bool implicit;
|
||||||
Expr *expr;
|
Expr *expr;
|
||||||
TypeInfo *type_info;
|
TypeInfo *type_info;
|
||||||
union
|
union
|
||||||
@@ -919,12 +909,9 @@ typedef struct
|
|||||||
struct Expr_
|
struct Expr_
|
||||||
{
|
{
|
||||||
ExprKind expr_kind : 8;
|
ExprKind expr_kind : 8;
|
||||||
ResolveStatus resolve_status : 3;
|
ResolveStatus resolve_status : 4;
|
||||||
bool failable : 1;
|
|
||||||
bool pure : 1;
|
|
||||||
SourceSpan span;
|
SourceSpan span;
|
||||||
Type *type;
|
Type *type;
|
||||||
Type *original_type;
|
|
||||||
union {
|
union {
|
||||||
Expr *group_expr;
|
Expr *group_expr;
|
||||||
ExprLen len_expr;
|
ExprLen len_expr;
|
||||||
@@ -943,7 +930,6 @@ struct Expr_
|
|||||||
ExprTernary ternary_expr;
|
ExprTernary ternary_expr;
|
||||||
ExprUnary unary_expr;
|
ExprUnary unary_expr;
|
||||||
Expr** try_unwrap_chain_expr;
|
Expr** try_unwrap_chain_expr;
|
||||||
ExprPostUnary post_expr;
|
|
||||||
ExprTryUnwrap try_unwrap_expr;
|
ExprTryUnwrap try_unwrap_expr;
|
||||||
ExprCall call_expr;
|
ExprCall call_expr;
|
||||||
ExprSlice slice_expr;
|
ExprSlice slice_expr;
|
||||||
@@ -1329,7 +1315,7 @@ typedef union
|
|||||||
const char *string;
|
const char *string;
|
||||||
size_t strlen;
|
size_t strlen;
|
||||||
};
|
};
|
||||||
Real value;
|
Float value;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
bool is_base64 : 1;
|
bool is_base64 : 1;
|
||||||
@@ -1412,7 +1398,6 @@ typedef struct Context_
|
|||||||
Ast **returns_cache;
|
Ast **returns_cache;
|
||||||
};
|
};
|
||||||
Type *rtype;
|
Type *rtype;
|
||||||
bool failable_return;
|
|
||||||
int in_volatile_section;
|
int in_volatile_section;
|
||||||
MacroScope macro_scope;
|
MacroScope macro_scope;
|
||||||
struct {
|
struct {
|
||||||
@@ -1550,10 +1535,10 @@ extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isize;
|
|||||||
extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
||||||
extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff;
|
extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff;
|
||||||
extern Type *type_u128, *type_i128;
|
extern Type *type_u128, *type_i128;
|
||||||
extern Type *type_compint, *type_compfloat;
|
|
||||||
extern Type *type_typeid, *type_anyerr, *type_typeinfo;
|
extern Type *type_typeid, *type_anyerr, *type_typeinfo;
|
||||||
extern Type *type_virtual, *type_virtual_generic;
|
extern Type *type_virtual, *type_virtual_generic;
|
||||||
extern Type *type_complist;
|
extern Type *type_complist;
|
||||||
|
extern Type *type_anyfail;
|
||||||
|
|
||||||
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
|
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
|
||||||
|
|
||||||
@@ -1624,64 +1609,131 @@ static inline Ast *extend_ast_with_prev_token(Context *context, Ast *ast)
|
|||||||
|
|
||||||
typedef enum CmpRes_
|
typedef enum CmpRes_
|
||||||
{
|
{
|
||||||
CMP_LT,
|
CMP_LT = -1,
|
||||||
CMP_GT,
|
CMP_EQ = 0,
|
||||||
CMP_EQ,
|
CMP_GT = 1,
|
||||||
} CmpRes;
|
} CmpRes;
|
||||||
|
|
||||||
void bigint_init_unsigned(BigInt *big_int, uint64_t value);
|
typedef enum
|
||||||
void bigint_init_signed(BigInt *big_int, int64_t value);
|
{
|
||||||
void bigint_init_bigint(BigInt *dest, const BigInt *src);
|
FLOAT_NAN,
|
||||||
void bigint_init_data(BigInt *dest, const uint64_t *digits, unsigned int digit_count, bool is_negative);
|
FLOAT_INFINITY,
|
||||||
void bigint_negate(BigInt *dest, const BigInt *source);
|
FLOAT_NORMAL,
|
||||||
size_t bigint_clz(const BigInt *big_int, size_t bit_count);
|
FLOAT_ZERO
|
||||||
size_t bigint_ctz(const BigInt *big_int, size_t bit_count);
|
} FloatCategory;
|
||||||
bool bigint_fits_in_bits(const BigInt *big_int, size_t bit_count, bool is_signed);
|
|
||||||
void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian);
|
typedef enum
|
||||||
void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, bool is_signed);
|
{
|
||||||
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
ROUNDING_TOWARD_ZERO,
|
||||||
void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
ROUNDING_NEAREST_TIES_TO_EVEN,
|
||||||
void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
ROUNDING_TOWARD_POSITIVE,
|
||||||
void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
ROUNDING_TOWARD_NEGATIVE,
|
||||||
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
ROUNDING_NEAREST_TIES_TO_AWAY
|
||||||
void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
} FloatRounding;
|
||||||
void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
|
||||||
void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
typedef struct FloatXX
|
||||||
void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
{
|
||||||
void bigint_shl_int(BigInt *dest, const BigInt *op1, uint64_t shift);
|
union
|
||||||
void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
{
|
||||||
void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
double f64;
|
||||||
void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
float f32;
|
||||||
void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
};
|
||||||
void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
TypeKind type;
|
||||||
void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
} FloatXX;
|
||||||
void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count);
|
|
||||||
void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
|
|
||||||
bool bigint_eql(BigInt a, BigInt b);
|
|
||||||
CmpRes bigint_cmp(const BigInt *op1, const BigInt *op2);
|
|
||||||
CmpRes bigint_cmp_zero(const BigInt *op);
|
|
||||||
uint32_t bigint_hash(BigInt x);
|
|
||||||
const char *bigint_to_error_string(const BigInt *bigint, uint64_t base);
|
|
||||||
void bigint_print(BigInt *bigint, uint64_t base);
|
|
||||||
void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base);
|
|
||||||
uint64_t bigint_as_unsigned(const BigInt *bigint);
|
|
||||||
int64_t bigint_as_signed(const BigInt *bigint);
|
|
||||||
Real bigint_as_float(const BigInt *bigint);
|
|
||||||
void bigint_truncate(BigInt *dst, const BigInt *op, size_t bit_count, bool is_signed);
|
|
||||||
void bigint_incr(BigInt *x);
|
|
||||||
size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count);
|
|
||||||
size_t bigint_popcount_unsigned(const BigInt *big_int);
|
|
||||||
void type_setup(PlatformTarget *target);
|
void type_setup(PlatformTarget *target);
|
||||||
|
Float float_add(Float op1, Float op2);
|
||||||
|
Float float_sub(Float op1, Float op2);
|
||||||
|
Float float_mul(Float op1, Float op2);
|
||||||
|
Float float_div(Float op1, Float op2);
|
||||||
|
Float float_neg(Float op);
|
||||||
|
Float float_from_string(const char *string, char **error);
|
||||||
|
Float float_from_hex(const char *string, char **error);
|
||||||
|
Int128 i128_from_double(double x);
|
||||||
|
bool int_ucomp(Int op1, uint64_t op2, BinaryOp op);
|
||||||
|
bool int_icomp(Int op1, int64_t op2, BinaryOp op);
|
||||||
|
bool int_comp(Int op1, Int op2, BinaryOp op);
|
||||||
|
uint64_t int_to_u64(Int op);
|
||||||
|
int64_t int_to_i64(Int op);
|
||||||
|
bool int_is_zero(Int op);
|
||||||
|
bool int_fits(Int op1, TypeKind kind);
|
||||||
|
Int int_conv(Int op, TypeKind to_type);
|
||||||
|
Int int_div(Int op1, Int op2);
|
||||||
|
Int int_mul(Int op1, Int op2);
|
||||||
|
Int int_sub(Int op1, Int op2);
|
||||||
|
Int int_sub64(Int op1, uint64_t op2);
|
||||||
|
Int int_add(Int op1, Int op2);
|
||||||
|
Int int_add64(Int op1, uint64_t op2);
|
||||||
|
Int int_rem(Int op1, Int op2);
|
||||||
|
Int int_and(Int op1, Int op2);
|
||||||
|
Int int_or(Int op1, Int op2);
|
||||||
|
Int int_xor(Int op1, Int op2);
|
||||||
|
Int int_neg(Int op);
|
||||||
|
Int int_not(Int op);
|
||||||
|
bool int_is_neg(Int op);
|
||||||
|
Int int_shr64(Int op, uint64_t);
|
||||||
|
Int int_shl64(Int op, uint64_t);
|
||||||
|
Real int_to_real(Int op);
|
||||||
|
Int int_from_real(Real d, TypeKind type);
|
||||||
|
char *int_to_str(Int i, int radix);
|
||||||
|
bool i128_can_convert_from_double(double x);
|
||||||
|
bool i128_can_convert_from_double_signed(double x);
|
||||||
|
Int128 i128_from_double(double x);
|
||||||
|
Int128 i128_from_double_signed(double x);
|
||||||
|
Int128 i128_extend(Int128 op, TypeKind type);
|
||||||
|
Int128 i128_add(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_add64(Int128 op1, uint64_t op2);
|
||||||
|
Int128 i128_add_swrap64(Int128 op1, int64_t op2, bool *wrapped);
|
||||||
|
Int128 i128_add_uwrap64(Int128 op1, uint64_t op2, bool *wrapped);
|
||||||
|
Int128 i128_sub(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_sub64(Int128 op1, uint64_t op2);
|
||||||
|
Int128 i128_and(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_or(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_xor(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_neg(Int128 op1);
|
||||||
|
Int128 i128_not(Int128 op1);
|
||||||
|
Int128 i128_mult(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_mult64(Int128 op1, uint64_t op2);
|
||||||
|
Int128 i128_from_str(const char *str);
|
||||||
|
char *i128_to_string(Int128 op, uint64_t base, bool is_signed);
|
||||||
|
bool i128_is_neg(Int128 op);
|
||||||
|
CmpRes i128_ucomp(Int128 op1, Int128 op2);
|
||||||
|
CmpRes i128_scomp(Int128 op1, Int128 op2);
|
||||||
|
CmpRes i128_comp(Int128 op1, Int128 op2, Type *type);
|
||||||
|
Int128 i128_shl64(Int128 op1, uint64_t amount);
|
||||||
|
Int128 i128_shl(Int128 op1, Int128 op);
|
||||||
|
Int128 i128_ashr64(Int128 op1, uint64_t amount);
|
||||||
|
Int128 i128_ashr(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_lshr64(Int128 op1, uint64_t amount);
|
||||||
|
Int128 i128_lshr(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_udiv(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_sdiv(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_urem(Int128 op1, Int128 op2);
|
||||||
|
Int128 i128_srem(Int128 op1, Int128 op2);
|
||||||
|
void i128_udivrem(Int128 op1, Int128 op2, Int128 *div, Int128 *rem);
|
||||||
|
Real i128_to_float(Int128 op);
|
||||||
|
Real i128_to_float_signed(Int128 op);
|
||||||
|
bool i128_is_zero(Int128 op);
|
||||||
|
uint32_t i128_clz(const Int128 *op);
|
||||||
|
uint32_t i128_ctz(const Int128 *op);
|
||||||
|
int i128_lsb(const Int128 *op);
|
||||||
|
int i128_msb(const Int128 *op);
|
||||||
|
Int128 i128_from_float_signed(Real d);
|
||||||
|
Int128 i128_from_float_unsigned(Real d);
|
||||||
|
Int128 i128_from_signed(int64_t i);
|
||||||
|
Int128 i128_from_unsigned(uint64_t i);
|
||||||
|
bool i128_get_bit(const Int128 *op, int bit);
|
||||||
|
|
||||||
static inline bool type_may_negate(Type *type)
|
static inline bool type_may_negate(Type *type)
|
||||||
{
|
{
|
||||||
RETRY:
|
RETRY:
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
case ALL_FLOATS:
|
|
||||||
case ALL_SIGNED_INTS:
|
|
||||||
case TYPE_VECTOR:
|
case TYPE_VECTOR:
|
||||||
case TYPE_IXX:
|
type = type->vector.base;
|
||||||
|
goto RETRY;
|
||||||
|
case ALL_FLOATS:
|
||||||
|
case ALL_INTS:
|
||||||
return true;
|
return true;
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
type = type->decl->distinct_decl.base_type;
|
type = type->decl->distinct_decl.base_type;
|
||||||
@@ -1689,12 +1741,16 @@ static inline bool type_may_negate(Type *type)
|
|||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
type = type->canonical;
|
type = type->canonical;
|
||||||
goto RETRY;
|
goto RETRY;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
type = type->failable;
|
||||||
|
goto RETRY;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool cast_implicit_ignore_failable(Expr *expr, Type *to_type);
|
||||||
bool cast_implicit(Expr *expr, Type *to_type);
|
bool cast_implicit(Expr *expr, Type *to_type);
|
||||||
bool cast(Expr *expr, Type *to_type);
|
bool cast(Expr *expr, Type *to_type);
|
||||||
|
|
||||||
@@ -1704,8 +1760,6 @@ bool cast_implicit_bit_width(Expr *expr, Type *to_type);
|
|||||||
|
|
||||||
CastKind cast_to_bool_kind(Type *type);
|
CastKind cast_to_bool_kind(Type *type);
|
||||||
|
|
||||||
bool cast_implicitly_to_runtime(Expr *expr);
|
|
||||||
|
|
||||||
const char *llvm_codegen(void *context);
|
const char *llvm_codegen(void *context);
|
||||||
void *llvm_gen(Module *module);
|
void *llvm_gen(Module *module);
|
||||||
void llvm_codegen_setup();
|
void llvm_codegen_setup();
|
||||||
@@ -1792,14 +1846,12 @@ static inline void expr_replace(Expr *expr, Expr *replacement)
|
|||||||
*expr = *replacement;
|
*expr = *replacement;
|
||||||
expr->span = loc;
|
expr->span = loc;
|
||||||
}
|
}
|
||||||
void expr_copy_types(Expr *to, Expr *from);
|
|
||||||
void expr_copy_properties(Expr *to, Expr *from);
|
|
||||||
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind);
|
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind);
|
||||||
void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind);
|
void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind);
|
||||||
void expr_const_set_bool(ExprConst *expr, bool b);
|
void expr_const_set_bool(ExprConst *expr, bool b);
|
||||||
void expr_const_set_null(ExprConst *expr);
|
void expr_const_set_null(ExprConst *expr);
|
||||||
|
|
||||||
bool expr_const_int_overflowed(const ExprConst *expr);
|
|
||||||
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
|
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
|
||||||
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
|
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
|
||||||
ByteSize expr_const_list_size(const ConstInitializer *list);
|
ByteSize expr_const_list_size(const ConstInitializer *list);
|
||||||
@@ -1820,12 +1872,6 @@ static inline bool expr_is_init_list(Expr *expr)
|
|||||||
ExprKind kind = expr->expr_kind;
|
ExprKind kind = expr->expr_kind;
|
||||||
return kind == EXPR_DESIGNATED_INITIALIZER_LIST || kind == EXPR_INITIALIZER_LIST;
|
return kind == EXPR_DESIGNATED_INITIALIZER_LIST || kind == EXPR_INITIALIZER_LIST;
|
||||||
}
|
}
|
||||||
static inline void expr_set_type(Expr *expr, Type *type)
|
|
||||||
{
|
|
||||||
assert(type);
|
|
||||||
expr->type = type;
|
|
||||||
expr->original_type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark --- Lexer functions
|
#pragma mark --- Lexer functions
|
||||||
@@ -1883,15 +1929,20 @@ bool sema_unwrap_var(Context *context, Decl *decl);
|
|||||||
bool sema_rewrap_var(Context *context, Decl *decl);
|
bool sema_rewrap_var(Context *context, Decl *decl);
|
||||||
bool sema_erase_var(Context *context, Decl *decl);
|
bool sema_erase_var(Context *context, Decl *decl);
|
||||||
bool sema_erase_unwrapped(Context *context, Decl *decl);
|
bool sema_erase_unwrapped(Context *context, Decl *decl);
|
||||||
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr, bool may_be_failable);
|
bool sema_analyse_cond_expr(Context *context, Expr *expr);
|
||||||
|
bool sema_analyse_assigned_expr(Context *context, Type *to, Expr *expr, bool may_be_failable);
|
||||||
|
|
||||||
|
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr);
|
||||||
ArrayIndex sema_get_initializer_const_array_size(Context *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
|
ArrayIndex sema_get_initializer_const_array_size(Context *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
|
||||||
bool sema_analyse_expr(Context *context, Type *to, Expr *expr);
|
bool sema_analyse_expr(Context *context, Expr *expr);
|
||||||
|
bool sema_analyse_inferred_expr(Context *context, Type *to, Expr *expr);
|
||||||
bool sema_analyse_decl(Context *context, Decl *decl);
|
bool sema_analyse_decl(Context *context, Decl *decl);
|
||||||
bool sema_analyse_var_decl(Context *context, Decl *decl);
|
bool sema_analyse_var_decl(Context *context, Decl *decl);
|
||||||
bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement);
|
bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement);
|
||||||
bool sema_analyse_statement(Context *context, Ast *statement);
|
bool sema_analyse_statement(Context *context, Ast *statement);
|
||||||
bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, ExprFailableStatus lhs_is_failable);
|
bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped_var);
|
||||||
bool sema_expr_analyse_general_call(Context *context, Type *to, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro);
|
|
||||||
|
bool sema_expr_analyse_general_call(Context *context, Expr *expr, Decl *decl, Expr *struct_var, bool is_macro, bool failable);
|
||||||
Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol);
|
Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol);
|
||||||
Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path);
|
Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path);
|
||||||
Decl *sema_resolve_method(Context *context, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
|
Decl *sema_resolve_method(Context *context, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
|
||||||
@@ -1980,9 +2031,10 @@ bool type_is_valid_for_vector(Type *type);
|
|||||||
Type *type_get_array(Type *arr_type, ByteSize len);
|
Type *type_get_array(Type *arr_type, ByteSize len);
|
||||||
Type *type_get_indexed_type(Type *type);
|
Type *type_get_indexed_type(Type *type);
|
||||||
Type *type_get_ptr(Type *ptr_type);
|
Type *type_get_ptr(Type *ptr_type);
|
||||||
|
Type *type_get_ptr_recurse(Type *ptr_type);
|
||||||
Type *type_get_subarray(Type *arr_type);
|
Type *type_get_subarray(Type *arr_type);
|
||||||
Type *type_get_inferred_array(Type *arr_type);
|
Type *type_get_inferred_array(Type *arr_type);
|
||||||
|
Type *type_get_failable(Type *failable_type);
|
||||||
Type *type_get_vector(Type *vector_type, unsigned len);
|
Type *type_get_vector(Type *vector_type, unsigned len);
|
||||||
Type *type_get_vector_bool(Type *original_type);
|
Type *type_get_vector_bool(Type *original_type);
|
||||||
Type *type_cint(void);
|
Type *type_cint(void);
|
||||||
@@ -1990,9 +2042,7 @@ Type *type_cuint(void);
|
|||||||
Type *type_int_signed_by_bitsize(unsigned bitsize);
|
Type *type_int_signed_by_bitsize(unsigned bitsize);
|
||||||
Type *type_int_unsigned_by_bitsize(unsigned bytesize);
|
Type *type_int_unsigned_by_bitsize(unsigned bytesize);
|
||||||
bool type_is_abi_aggregate(Type *type);
|
bool type_is_abi_aggregate(Type *type);
|
||||||
static inline bool type_is_any_integer(Type *type);
|
|
||||||
static inline bool type_is_builtin(TypeKind kind);
|
static inline bool type_is_builtin(TypeKind kind);
|
||||||
static inline bool type_is_ct(Type *type);
|
|
||||||
bool type_is_empty_record(Type *type, bool allow_array);
|
bool type_is_empty_record(Type *type, bool allow_array);
|
||||||
bool type_is_empty_field(Type *type, bool allow_array);
|
bool type_is_empty_field(Type *type, bool allow_array);
|
||||||
static inline bool type_is_float(Type *type);
|
static inline bool type_is_float(Type *type);
|
||||||
@@ -2002,7 +2052,7 @@ Type *type_find_function_type(FunctionSignature *signature);
|
|||||||
static inline bool type_is_integer(Type *type);
|
static inline bool type_is_integer(Type *type);
|
||||||
static inline bool type_is_integer_unsigned(Type *type);
|
static inline bool type_is_integer_unsigned(Type *type);
|
||||||
static inline bool type_is_integer_signed(Type *type);
|
static inline bool type_is_integer_signed(Type *type);
|
||||||
static inline bool type_is_integer_kind(Type *type);
|
static inline bool type_is_integer_or_bool_kind(Type *type);
|
||||||
static inline bool type_is_numeric(Type *type);
|
static inline bool type_is_numeric(Type *type);
|
||||||
static inline bool type_underlying_is_numeric(Type *type);
|
static inline bool type_underlying_is_numeric(Type *type);
|
||||||
static inline bool type_is_pointer(Type *type);
|
static inline bool type_is_pointer(Type *type);
|
||||||
@@ -2024,7 +2074,6 @@ static inline Type *type_reduced_from_expr(Expr *expr);
|
|||||||
ByteSize type_size(Type *type);
|
ByteSize type_size(Type *type);
|
||||||
const char *type_to_error_string(Type *type);
|
const char *type_to_error_string(Type *type);
|
||||||
const char *type_quoted_error_string(Type *type);
|
const char *type_quoted_error_string(Type *type);
|
||||||
bool type_may_convert_to_boolean(Type *type);
|
|
||||||
|
|
||||||
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
|
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
|
||||||
static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span);
|
static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span);
|
||||||
@@ -2043,6 +2092,10 @@ static inline Type *type_reduced_from_expr(Expr *expr)
|
|||||||
return type_lowering(expr->type);
|
return type_lowering(expr->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Type *type_no_fail(Type *type)
|
||||||
|
{
|
||||||
|
return type && type->type_kind == TYPE_FAILABLE ? type->failable : type;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool type_is_pointer_sized_or_more(Type *type)
|
static inline bool type_is_pointer_sized_or_more(Type *type)
|
||||||
{
|
{
|
||||||
@@ -2054,35 +2107,48 @@ static inline bool type_is_pointer_sized(Type *type)
|
|||||||
return type_is_integer(type) && type_size(type) == type_size(type_iptr);
|
return type_is_integer(type) && type_size(type) == type_size(type_iptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DECL_TYPE_KIND_REAL(k_, t_) \
|
||||||
|
TypeKind k_ = (t_)->type_kind; \
|
||||||
|
if (k_ == TYPE_TYPEDEF) k_ = (t_)->canonical->type_kind;
|
||||||
|
|
||||||
|
#define IS_FAILABLE(element_) ((element_)->type->type_kind == TYPE_FAILABLE)
|
||||||
|
#define TYPE_IS_FAILABLE(type_) (type_->type_kind == TYPE_FAILABLE)
|
||||||
|
|
||||||
|
static inline Type *type_with_added_failability(Expr *expr, bool add_failable)
|
||||||
|
{
|
||||||
|
Type *type = expr->type;
|
||||||
|
if (!add_failable || type->type_kind == TYPE_FAILABLE) return type;
|
||||||
|
return type_get_failable(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Type *type_get_opt_fail(Type *type, bool add_failable)
|
||||||
|
{
|
||||||
|
if (!add_failable || type->type_kind == TYPE_FAILABLE) return type;
|
||||||
|
return type_get_failable(type);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool type_is_integer(Type *type)
|
static inline bool type_is_integer(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
DECL_TYPE_KIND_REAL(kind, type);
|
||||||
return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_IXX;
|
return kind >= TYPE_INTEGER_FIRST && type->type_kind <= TYPE_INTEGER_LAST;
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool type_is_any_integer(Type *type)
|
|
||||||
{
|
|
||||||
assert(type == type->canonical);
|
|
||||||
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_integer_signed(Type *type)
|
static inline bool type_is_integer_signed(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
DECL_TYPE_KIND_REAL(kind, type);
|
||||||
return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8;
|
return kind >= TYPE_INT_FIRST && type->type_kind <= TYPE_INT_LAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_integer_kind(Type *type)
|
static inline bool type_is_integer_or_bool_kind(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
DECL_TYPE_KIND_REAL(kind, type);
|
||||||
return type->type_kind >= TYPE_BOOL && type->type_kind < TYPE_IXX;
|
return kind >= TYPE_BOOL && kind <= TYPE_U128;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_integer_unsigned(Type *type)
|
static inline bool type_is_integer_unsigned(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
DECL_TYPE_KIND_REAL(kind, type);
|
||||||
return type->type_kind >= TYPE_U8 && type->type_kind < TYPE_IXX;
|
return kind >= TYPE_UINT_FIRST && type->type_kind <= TYPE_UINT_LAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_info_poison(TypeInfo *type)
|
static inline bool type_info_poison(TypeInfo *type)
|
||||||
@@ -2092,26 +2158,11 @@ static inline bool type_info_poison(TypeInfo *type)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_ct(Type *type)
|
|
||||||
{
|
|
||||||
RETRY:
|
|
||||||
switch (type->type_kind)
|
|
||||||
{
|
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_IXX:
|
|
||||||
return true;
|
|
||||||
case TYPE_TYPEDEF:
|
|
||||||
type = type->canonical;
|
|
||||||
goto RETRY;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool type_is_pointer(Type *type)
|
static inline bool type_is_pointer(Type *type)
|
||||||
{
|
{
|
||||||
type = type->canonical;
|
DECL_TYPE_KIND_REAL(kind, type);
|
||||||
return type->type_kind == TYPE_POINTER;
|
return kind == TYPE_POINTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t aligned_offset(uint64_t offset, uint64_t alignment)
|
static inline uint64_t aligned_offset(uint64_t offset, uint64_t alignment)
|
||||||
@@ -2121,14 +2172,14 @@ static inline uint64_t aligned_offset(uint64_t offset, uint64_t alignment)
|
|||||||
|
|
||||||
static inline bool type_is_substruct(Type *type)
|
static inline bool type_is_substruct(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
DECL_TYPE_KIND_REAL(kind, type);
|
||||||
return type->type_kind == TYPE_STRUCT && type->decl->is_substruct;
|
return kind == TYPE_STRUCT && type->decl->is_substruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_float(Type *type)
|
static inline bool type_is_float(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
DECL_TYPE_KIND_REAL(kind, type);
|
||||||
return type->type_kind >= TYPE_F16 && type->type_kind <= TYPE_FXX;
|
return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span)
|
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span)
|
||||||
@@ -2171,7 +2222,6 @@ static inline bool type_convert_will_trunc(Type *destination, Type *source)
|
|||||||
|
|
||||||
|
|
||||||
UnaryOp unaryop_from_token(TokenType type);
|
UnaryOp unaryop_from_token(TokenType type);
|
||||||
PostUnaryOp post_unaryop_from_token(TokenType type);
|
|
||||||
BinaryOp binaryop_from_token(TokenType type);
|
BinaryOp binaryop_from_token(TokenType type);
|
||||||
BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op);
|
BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op);
|
||||||
TokenType binaryop_to_token(BinaryOp type);
|
TokenType binaryop_to_token(BinaryOp type);
|
||||||
@@ -2233,6 +2283,12 @@ static inline Type *type_flatten(Type *type)
|
|||||||
type = type->decl->enums.type_info->type;
|
type = type->decl->enums.type_info->type;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (type->type_kind == TYPE_FAILABLE)
|
||||||
|
{
|
||||||
|
type = type->failable;
|
||||||
|
if (!type) type = type_void;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2245,19 +2301,19 @@ static Type *type_vector_type(Type *type)
|
|||||||
|
|
||||||
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
|
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
|
||||||
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind < TYPE_U8; }
|
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind < TYPE_U8; }
|
||||||
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind < TYPE_IXX; }
|
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U128; }
|
||||||
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; }
|
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_U128; }
|
||||||
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; }
|
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; }
|
||||||
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind < TYPE_IXX; }
|
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U128; }
|
||||||
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
||||||
static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
|
static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
|
||||||
|
int type_kind_bitsize(TypeKind kind);
|
||||||
bool type_is_scalar(Type *type);
|
bool type_is_scalar(Type *type);
|
||||||
|
|
||||||
static inline bool type_is_numeric(Type *type)
|
static inline bool type_is_numeric(Type *type)
|
||||||
{
|
{
|
||||||
TypeKind kind = type->type_kind;
|
TypeKind kind = type->type_kind;
|
||||||
return (kind >= TYPE_I8 && kind <= TYPE_FXX) || kind == TYPE_VECTOR;
|
return (kind >= TYPE_I8 && kind <= TYPE_FLOAT_LAST) || kind == TYPE_VECTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_underlying_is_numeric(Type *type)
|
static inline bool type_underlying_is_numeric(Type *type)
|
||||||
@@ -2305,6 +2361,10 @@ static inline Type *type_lowering(Type *type)
|
|||||||
|
|
||||||
static inline Decl *decl_raw(Decl *decl)
|
static inline Decl *decl_raw(Decl *decl)
|
||||||
{
|
{
|
||||||
|
while (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind == DEFINE_IDENT_ALIAS)
|
||||||
|
{
|
||||||
|
decl = decl->define_decl.alias;
|
||||||
|
}
|
||||||
if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED) return decl;
|
if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED) return decl;
|
||||||
decl = decl->var.alias;
|
decl = decl->var.alias;
|
||||||
assert(decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED);
|
assert(decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED);
|
||||||
@@ -2346,7 +2406,7 @@ static inline DeclKind decl_from_token(TokenType type)
|
|||||||
static inline bool type_is_promotable_integer(Type *type)
|
static inline bool type_is_promotable_integer(Type *type)
|
||||||
{
|
{
|
||||||
// If we support other architectures, update this.
|
// If we support other architectures, update this.
|
||||||
return type_is_integer_kind(type) && type->builtin.bitsize < platform_target.width_c_int;
|
return type_is_integer_or_bool_kind(type) && type->builtin.bitsize < platform_target.width_c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_promotable_float(Type *type)
|
static inline bool type_is_promotable_float(Type *type)
|
||||||
@@ -2394,3 +2454,15 @@ void platform_linker(const char *output_file, const char **files, unsigned file_
|
|||||||
#define ASSIGN_TYPE_ELSE(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = TEMP(_type)
|
#define ASSIGN_TYPE_ELSE(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = TEMP(_type)
|
||||||
#define ASSIGN_DECL_ELSE(_assign, _decl_stmt, _res) Decl* TEMP(_decl) = (_decl_stmt); if (!decl_ok(TEMP(_decl))) return _res; _assign = TEMP(_decl)
|
#define ASSIGN_DECL_ELSE(_assign, _decl_stmt, _res) Decl* TEMP(_decl) = (_decl_stmt); if (!decl_ok(TEMP(_decl))) return _res; _assign = TEMP(_decl)
|
||||||
|
|
||||||
|
static inline Type *abi_rtype(FunctionSignature *signature)
|
||||||
|
{
|
||||||
|
Type *type = signature->rtype->type;
|
||||||
|
if (type->type_kind == TYPE_FAILABLE) return type->failable;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Type *abi_returntype(FunctionSignature *signature)
|
||||||
|
{
|
||||||
|
Type *type = signature->rtype->type;
|
||||||
|
return type->type_kind == TYPE_FAILABLE ? type_anyerr : type;
|
||||||
|
}
|
||||||
|
|||||||
@@ -162,10 +162,6 @@ Expr *copy_expr(Expr *source_expr)
|
|||||||
MACRO_COPY_EXPR(expr->guard_expr.inner);
|
MACRO_COPY_EXPR(expr->guard_expr.inner);
|
||||||
return expr;
|
return expr;
|
||||||
case EXPR_CONST:
|
case EXPR_CONST:
|
||||||
if (expr->const_expr.const_kind == CONST_INTEGER && expr->const_expr.i.digit_count > 1)
|
|
||||||
{
|
|
||||||
bigint_init_bigint(&expr->const_expr.i, &source_expr->const_expr.i);
|
|
||||||
}
|
|
||||||
return expr;
|
return expr;
|
||||||
case EXPR_BINARY:
|
case EXPR_BINARY:
|
||||||
MACRO_COPY_EXPR(expr->binary_expr.left);
|
MACRO_COPY_EXPR(expr->binary_expr.left);
|
||||||
@@ -177,10 +173,8 @@ Expr *copy_expr(Expr *source_expr)
|
|||||||
MACRO_COPY_EXPR(expr->ternary_expr.else_expr);
|
MACRO_COPY_EXPR(expr->ternary_expr.else_expr);
|
||||||
return expr;
|
return expr;
|
||||||
case EXPR_UNARY:
|
case EXPR_UNARY:
|
||||||
MACRO_COPY_EXPR(expr->unary_expr.expr);
|
|
||||||
return expr;
|
|
||||||
case EXPR_POST_UNARY:
|
case EXPR_POST_UNARY:
|
||||||
MACRO_COPY_EXPR(expr->post_expr.expr);
|
MACRO_COPY_EXPR(expr->unary_expr.expr);
|
||||||
return expr;
|
return expr;
|
||||||
case EXPR_TYPEID:
|
case EXPR_TYPEID:
|
||||||
MACRO_COPY_TYPE(expr->typeid_expr);
|
MACRO_COPY_TYPE(expr->typeid_expr);
|
||||||
@@ -301,7 +295,7 @@ Ast *copy_ast(Ast *source)
|
|||||||
case AST_DEFAULT_STMT:
|
case AST_DEFAULT_STMT:
|
||||||
MACRO_COPY_AST(ast->case_stmt.body);
|
MACRO_COPY_AST(ast->case_stmt.body);
|
||||||
return ast;
|
return ast;
|
||||||
case AST_DEFINE_STMT:
|
case AST_VAR_STMT:
|
||||||
ast->var_stmt = copy_decl(ast->var_stmt);
|
ast->var_stmt = copy_decl(ast->var_stmt);
|
||||||
return ast;
|
return ast;
|
||||||
case AST_DEFER_STMT:
|
case AST_DEFER_STMT:
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ typedef enum
|
|||||||
AST_CASE_STMT,
|
AST_CASE_STMT,
|
||||||
AST_COMPOUND_STMT,
|
AST_COMPOUND_STMT,
|
||||||
AST_CONTINUE_STMT,
|
AST_CONTINUE_STMT,
|
||||||
AST_DEFINE_STMT,
|
AST_VAR_STMT,
|
||||||
AST_CT_ASSERT,
|
AST_CT_ASSERT,
|
||||||
AST_CT_COMPOUND_STMT,
|
AST_CT_COMPOUND_STMT,
|
||||||
AST_CT_IF_STMT,
|
AST_CT_IF_STMT,
|
||||||
@@ -245,12 +245,6 @@ typedef enum
|
|||||||
DESIGNATOR_RANGE
|
DESIGNATOR_RANGE
|
||||||
} DesignatorType;
|
} DesignatorType;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
FAILABLE_NO,
|
|
||||||
FAILABLE_YES,
|
|
||||||
FAILABLE_UNWRAPPED
|
|
||||||
} ExprFailableStatus;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -523,21 +517,27 @@ typedef enum
|
|||||||
TYPE_VOID,
|
TYPE_VOID,
|
||||||
TYPE_BOOL,
|
TYPE_BOOL,
|
||||||
TYPE_I8,
|
TYPE_I8,
|
||||||
|
TYPE_INTEGER_FIRST = TYPE_I8,
|
||||||
|
TYPE_INT_FIRST = TYPE_I8,
|
||||||
TYPE_I16,
|
TYPE_I16,
|
||||||
TYPE_I32,
|
TYPE_I32,
|
||||||
TYPE_I64,
|
TYPE_I64,
|
||||||
TYPE_I128,
|
TYPE_I128,
|
||||||
|
TYPE_INT_LAST = TYPE_I128,
|
||||||
TYPE_U8,
|
TYPE_U8,
|
||||||
|
TYPE_UINT_FIRST = TYPE_U8,
|
||||||
TYPE_U16,
|
TYPE_U16,
|
||||||
TYPE_U32,
|
TYPE_U32,
|
||||||
TYPE_U64,
|
TYPE_U64,
|
||||||
TYPE_U128,
|
TYPE_U128,
|
||||||
TYPE_IXX,
|
TYPE_UINT_LAST = TYPE_U128,
|
||||||
|
TYPE_INTEGER_LAST = TYPE_U128,
|
||||||
TYPE_F16,
|
TYPE_F16,
|
||||||
|
TYPE_FLOAT_FIRST = TYPE_F16,
|
||||||
TYPE_F32,
|
TYPE_F32,
|
||||||
TYPE_F64,
|
TYPE_F64,
|
||||||
TYPE_F128,
|
TYPE_F128,
|
||||||
TYPE_FXX,
|
TYPE_FLOAT_LAST = TYPE_F128,
|
||||||
TYPE_TYPEID,
|
TYPE_TYPEID,
|
||||||
TYPE_POINTER,
|
TYPE_POINTER,
|
||||||
TYPE_ENUM,
|
TYPE_ENUM,
|
||||||
@@ -554,6 +554,7 @@ typedef enum
|
|||||||
TYPE_SUBARRAY,
|
TYPE_SUBARRAY,
|
||||||
TYPE_INFERRED_ARRAY,
|
TYPE_INFERRED_ARRAY,
|
||||||
TYPE_UNTYPED_LIST,
|
TYPE_UNTYPED_LIST,
|
||||||
|
TYPE_FAILABLE,
|
||||||
TYPE_TYPEINFO,
|
TYPE_TYPEINFO,
|
||||||
TYPE_VECTOR,
|
TYPE_VECTOR,
|
||||||
TYPE_VIRTUAL,
|
TYPE_VIRTUAL,
|
||||||
@@ -563,11 +564,10 @@ typedef enum
|
|||||||
|
|
||||||
#define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_UNTYPED_LIST: case TYPE_POISONED
|
#define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_UNTYPED_LIST: case TYPE_POISONED
|
||||||
#define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: \
|
#define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: \
|
||||||
case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128: case TYPE_IXX
|
case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128
|
||||||
#define ALL_SIGNED_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128
|
#define ALL_SIGNED_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128
|
||||||
#define ALL_UNSIGNED_INTS TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128
|
#define ALL_UNSIGNED_INTS TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128
|
||||||
#define ALL_REAL_FLOATS TYPE_F16: case TYPE_F32: case TYPE_F64: case TYPE_F128
|
#define ALL_FLOATS TYPE_F16: case TYPE_F32: case TYPE_F64: case TYPE_F128
|
||||||
#define ALL_FLOATS ALL_REAL_FLOATS: case TYPE_FXX
|
|
||||||
|
|
||||||
#define TYPE_KINDS (TYPE_LAST + 1)
|
#define TYPE_KINDS (TYPE_LAST + 1)
|
||||||
|
|
||||||
@@ -585,12 +585,6 @@ typedef enum
|
|||||||
UNARYOP_LAST = UNARYOP_DEC
|
UNARYOP_LAST = UNARYOP_DEC
|
||||||
} UnaryOp;
|
} UnaryOp;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
POSTUNARYOP_INC,
|
|
||||||
POSTUNARYOP_DEC,
|
|
||||||
} PostUnaryOp;
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
VARDECL_CONST = 0,
|
VARDECL_CONST = 0,
|
||||||
|
|||||||
266
src/compiler/float.c
Normal file
266
src/compiler/float.c
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#include "compiler_internal.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static int precision_bits(TypeKind kind)
|
||||||
|
{
|
||||||
|
switch (kind)
|
||||||
|
{
|
||||||
|
case TYPE_F16:
|
||||||
|
return 11;
|
||||||
|
/*case TYPE_BF16:
|
||||||
|
return 8;*/
|
||||||
|
case TYPE_F32:
|
||||||
|
return 24;
|
||||||
|
case TYPE_F64:
|
||||||
|
return 53;
|
||||||
|
case TYPE_F128:
|
||||||
|
return 113;
|
||||||
|
default:
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max_exponent(TypeKind kind)
|
||||||
|
{
|
||||||
|
switch (kind)
|
||||||
|
{
|
||||||
|
case TYPE_F16:
|
||||||
|
return 15;
|
||||||
|
/*case TYPE_BF16:
|
||||||
|
return 127;*/
|
||||||
|
case TYPE_F32:
|
||||||
|
return 127;
|
||||||
|
case TYPE_F64:
|
||||||
|
return 1023;
|
||||||
|
case TYPE_F128:
|
||||||
|
return 16383;
|
||||||
|
default:
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int min_exponent(TypeKind kind)
|
||||||
|
{
|
||||||
|
switch (kind)
|
||||||
|
{
|
||||||
|
case TYPE_F16:
|
||||||
|
return -14;
|
||||||
|
/*case TYPE_BF16:
|
||||||
|
return -126;*/
|
||||||
|
case TYPE_F32:
|
||||||
|
return -126;
|
||||||
|
case TYPE_F64:
|
||||||
|
return -1022;
|
||||||
|
case TYPE_F128:
|
||||||
|
return -16382;
|
||||||
|
default:
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Float float_add(Float op1, Float op2)
|
||||||
|
{
|
||||||
|
assert(op1.type == op2.type);
|
||||||
|
return (Float){ op1.f + op2.f, op1.type };
|
||||||
|
}
|
||||||
|
|
||||||
|
Float float_sub(Float op1, Float op2)
|
||||||
|
{
|
||||||
|
assert(op1.type == op2.type);
|
||||||
|
return (Float){ op1.f - op2.f, op1.type };
|
||||||
|
}
|
||||||
|
|
||||||
|
Float float_mul(Float op1, Float op2)
|
||||||
|
{
|
||||||
|
assert(op1.type == op2.type);
|
||||||
|
return (Float){ op1.f * op2.f, op1.type };
|
||||||
|
}
|
||||||
|
|
||||||
|
Float float_div(Float op1, Float op2)
|
||||||
|
{
|
||||||
|
assert(op1.type == op2.type);
|
||||||
|
return (Float){ op1.f / op2.f, op1.type };
|
||||||
|
}
|
||||||
|
|
||||||
|
Float float_neg(Float op)
|
||||||
|
{
|
||||||
|
op.f = -op.f;
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *err_invalid_float_width = "The float width is not valid, it must be one of 16, 32, 64 and 128.";
|
||||||
|
static char *err_float_out_of_range = "The float value is out of range.";
|
||||||
|
static char *err_float_format_invalid = "The float format is invalid.";
|
||||||
|
|
||||||
|
Float float_from_string(const char *string, char **error)
|
||||||
|
{
|
||||||
|
const char *index = string;
|
||||||
|
char c;
|
||||||
|
scratch_buffer_clear();
|
||||||
|
while ((c = *(index++)) && (c == '_' || (c >= '0' && c <= '9')))
|
||||||
|
{
|
||||||
|
if (c == '_') continue;
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
}
|
||||||
|
if (c == '.')
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
while ((c = *(index++)) && (c == '_' || (c >= '0' && c <= '9')))
|
||||||
|
{
|
||||||
|
if (c == '_') continue;
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == 'e' || c == 'E')
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
if (*index == '-')
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char('-');
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else if (*index == '+') index++;
|
||||||
|
while ((c = *(index++)) && (c >= '0' && c <= '9'))
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeKind kind = TYPE_F64;
|
||||||
|
if (c == 'f')
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while ((c = *(index++)) && (c >= '0' && c <= '9'))
|
||||||
|
{
|
||||||
|
if (i > 100)
|
||||||
|
{
|
||||||
|
if (error) *error = err_invalid_float_width;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
i = i * 10 + c - '0';
|
||||||
|
}
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 32:
|
||||||
|
kind = TYPE_F32;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
kind = TYPE_F16;
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
case 0:
|
||||||
|
kind = TYPE_F64;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
kind = TYPE_F128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (error) *error = err_invalid_float_width;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *str = scratch_buffer_to_string();
|
||||||
|
char *end = NULL;
|
||||||
|
errno = 0;
|
||||||
|
double d = strtod(str, &end);
|
||||||
|
if (d == HUGE_VAL && errno == ERANGE)
|
||||||
|
{
|
||||||
|
if (error) *error = err_float_out_of_range;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
char *expected_end = global_context.scratch_buffer + global_context.scratch_buffer_len;
|
||||||
|
if (d == 0 && end != expected_end)
|
||||||
|
{
|
||||||
|
if (error) *error = err_float_format_invalid;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
return (Float){ d, kind };
|
||||||
|
}
|
||||||
|
|
||||||
|
Float float_from_hex(const char *string, char **error)
|
||||||
|
{
|
||||||
|
const char *index = string + 2;
|
||||||
|
char c;
|
||||||
|
scratch_buffer_clear();
|
||||||
|
scratch_buffer_append("0x");
|
||||||
|
while ((c = *(index++)) && (c == '_' || is_hex(c)))
|
||||||
|
{
|
||||||
|
if (c == '_') continue;
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
}
|
||||||
|
if (c == '.')
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
while ((c = *(index++)) && (c == '_' || is_hex(c)))
|
||||||
|
{
|
||||||
|
if (c == '_') continue;
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == 'p' || c == 'P')
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
if (*index == '-')
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char('-');
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else if (*index == '+') index++;
|
||||||
|
while ((c = *(index++)) && (c >= '0' && c <= '9'))
|
||||||
|
{
|
||||||
|
scratch_buffer_append_char(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeKind kind = TYPE_F64;
|
||||||
|
if (c == 'f')
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while ((c = *(index++)) && (c >= '0' && c <= '9'))
|
||||||
|
{
|
||||||
|
if (i > 100)
|
||||||
|
{
|
||||||
|
if (error) *error = err_invalid_float_width;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
i = i * 10 + c - '0';
|
||||||
|
}
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 32:
|
||||||
|
kind = TYPE_F32;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
kind = TYPE_F16;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
case 64:
|
||||||
|
kind = TYPE_F64;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
kind = TYPE_F128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (error) *error = err_invalid_float_width;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *str = scratch_buffer_to_string();
|
||||||
|
char *end = NULL;
|
||||||
|
errno = 0;
|
||||||
|
double d = strtod(str, &end);
|
||||||
|
if (d == HUGE_VAL && errno == ERANGE)
|
||||||
|
{
|
||||||
|
if (error) *error = err_float_out_of_range;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
if (d == 0 && end != global_context.scratch_buffer + global_context.scratch_buffer_len)
|
||||||
|
{
|
||||||
|
if (error) *error = err_float_format_invalid;
|
||||||
|
return (Float){ .type = TYPE_POISONED };
|
||||||
|
}
|
||||||
|
return (Float){ d, kind };
|
||||||
|
}
|
||||||
@@ -34,6 +34,9 @@ static void header_print_type(FILE *file, Type *type)
|
|||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
TODO
|
TODO
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
// If this is reachable then we are not doing the proper lowering.
|
||||||
|
UNREACHABLE
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
OUTPUT("void");
|
OUTPUT("void");
|
||||||
return;
|
return;
|
||||||
@@ -50,7 +53,6 @@ static void header_print_type(FILE *file, Type *type)
|
|||||||
OUTPUT("int32_t");
|
OUTPUT("int32_t");
|
||||||
return;
|
return;
|
||||||
case TYPE_I64:
|
case TYPE_I64:
|
||||||
case TYPE_IXX:
|
|
||||||
OUTPUT("int64_t");
|
OUTPUT("int64_t");
|
||||||
return;
|
return;
|
||||||
case TYPE_I128:
|
case TYPE_I128:
|
||||||
@@ -78,7 +80,6 @@ static void header_print_type(FILE *file, Type *type)
|
|||||||
OUTPUT("float");
|
OUTPUT("float");
|
||||||
return;
|
return;
|
||||||
case TYPE_F64:
|
case TYPE_F64:
|
||||||
case TYPE_FXX:
|
|
||||||
OUTPUT("double");
|
OUTPUT("double");
|
||||||
return;
|
return;
|
||||||
case TYPE_F128:
|
case TYPE_F128:
|
||||||
|
|||||||
@@ -352,6 +352,36 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to
|
|||||||
|
|
||||||
#pragma mark --- Number scanning
|
#pragma mark --- Number scanning
|
||||||
|
|
||||||
|
static bool scan_number_suffix(Lexer *lexer, bool *is_float)
|
||||||
|
{
|
||||||
|
if (!is_alphanum_(peek(lexer))) return true;
|
||||||
|
switch (peek(lexer))
|
||||||
|
{
|
||||||
|
case 'u':
|
||||||
|
case 'U':
|
||||||
|
case 'I':
|
||||||
|
case 'i':
|
||||||
|
if (*is_float)
|
||||||
|
{
|
||||||
|
return add_error_token(lexer, "Integer suffix '%x' is not valid for a floating point literal.", peek(lexer));
|
||||||
|
}
|
||||||
|
next(lexer);
|
||||||
|
while (is_number(peek(lexer))) next(lexer);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
*is_float = true;
|
||||||
|
next(lexer);
|
||||||
|
while (is_number(peek(lexer))) next(lexer);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (is_alphanum_(peek(lexer)))
|
||||||
|
{
|
||||||
|
return add_error_token(lexer, "This doesn't seem to be a valid literal.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Parsing octals. Here we depart from the (error prone) C style octals with initial zero e.g. 0231
|
* Parsing octals. Here we depart from the (error prone) C style octals with initial zero e.g. 0231
|
||||||
* Instead we only support 0o prefix like 0o231. Note that lexing here doesn't actually parse the
|
* Instead we only support 0o prefix like 0o231. Note that lexing here doesn't actually parse the
|
||||||
@@ -362,6 +392,12 @@ static bool scan_oct(Lexer *lexer)
|
|||||||
char o = next(lexer); // Skip the o
|
char o = next(lexer); // Skip the o
|
||||||
if (!is_oct(next(lexer))) return add_error_token(lexer, "An expression starting with '0%c' would expect to be followed by octal numbers (0-7).", o);
|
if (!is_oct(next(lexer))) return add_error_token(lexer, "An expression starting with '0%c' would expect to be followed by octal numbers (0-7).", o);
|
||||||
while (is_oct_or_(peek(lexer))) next(lexer);
|
while (is_oct_or_(peek(lexer))) next(lexer);
|
||||||
|
bool is_float = false;
|
||||||
|
if (!scan_number_suffix(lexer, &is_float)) return false;
|
||||||
|
if (is_float)
|
||||||
|
{
|
||||||
|
return add_error_token(lexer, "Octal literals cannot have a floating point suffix.");
|
||||||
|
}
|
||||||
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
|
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +413,12 @@ static bool scan_binary(Lexer *lexer)
|
|||||||
"did you try to write a hex value but forgot the '0x'?");
|
"did you try to write a hex value but forgot the '0x'?");
|
||||||
}
|
}
|
||||||
while (is_binary_or_(peek(lexer))) next(lexer);
|
while (is_binary_or_(peek(lexer))) next(lexer);
|
||||||
|
bool is_float = false;
|
||||||
|
if (!scan_number_suffix(lexer, &is_float)) return false;
|
||||||
|
if (is_float)
|
||||||
|
{
|
||||||
|
return add_error_token(lexer, "Binary literals cannot have a floating point suffix.");
|
||||||
|
}
|
||||||
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
|
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,6 +476,8 @@ static inline bool scan_hex(Lexer *lexer)
|
|||||||
if (!scan_exponent(lexer)) return false;
|
if (!scan_exponent(lexer)) return false;
|
||||||
}
|
}
|
||||||
if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits.");
|
if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits.");
|
||||||
|
// TODO this does not currently work.
|
||||||
|
if (!scan_number_suffix(lexer, &is_float)) return false;
|
||||||
if (is_float)
|
if (is_float)
|
||||||
{
|
{
|
||||||
// IMPROVE
|
// IMPROVE
|
||||||
@@ -441,26 +485,17 @@ static inline bool scan_hex(Lexer *lexer)
|
|||||||
// this is not ideal, we should try to use f128 if possible for example.
|
// this is not ideal, we should try to use f128 if possible for example.
|
||||||
// Possibly we should move to a BigDecimal implementation or at least a soft float 256
|
// Possibly we should move to a BigDecimal implementation or at least a soft float 256
|
||||||
// implementation for the constants.
|
// implementation for the constants.
|
||||||
char *end = NULL;
|
char *err = NULL;
|
||||||
errno = 0;
|
Float f = float_from_hex(lexer->lexing_start, &err);
|
||||||
#if LONG_DOUBLE
|
if (f.type == TYPE_POISONED)
|
||||||
Real fval = strtold(lexer->lexing_start, &end);
|
|
||||||
#else
|
|
||||||
Real fval = strtod(lexer->lexing_start, &end);
|
|
||||||
#endif
|
|
||||||
if (errno == ERANGE)
|
|
||||||
{
|
{
|
||||||
return add_error_token(lexer, "The float value is out of range.");
|
return add_error_token(lexer, err);
|
||||||
}
|
|
||||||
if (end != lexer->current)
|
|
||||||
{
|
|
||||||
return add_error_token(lexer, "Invalid float value.");
|
|
||||||
}
|
}
|
||||||
add_generic_token(lexer, TOKEN_REAL);
|
add_generic_token(lexer, TOKEN_REAL);
|
||||||
lexer->latest_token_data->value = fval;
|
lexer->latest_token_data->value = f;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return add_token(lexer, is_float ? TOKEN_REAL : TOKEN_INTEGER, lexer->lexing_start);
|
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -502,7 +537,8 @@ static inline bool scan_dec(Lexer *lexer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits.");
|
if (prev(lexer) == '_') return add_error_token(lexer, "The number ended with '_', but that character needs to be between, not after, digits.");
|
||||||
|
// TODO this does not currently work.
|
||||||
|
if (!scan_number_suffix(lexer, &is_float)) return false;
|
||||||
if (is_float)
|
if (is_float)
|
||||||
{
|
{
|
||||||
// IMPROVE
|
// IMPROVE
|
||||||
@@ -510,18 +546,14 @@ static inline bool scan_dec(Lexer *lexer)
|
|||||||
// this is not ideal, we should try to use f128 if possible for example.
|
// this is not ideal, we should try to use f128 if possible for example.
|
||||||
// Possibly we should move to a BigDecimal implementation or at least a soft float 256
|
// Possibly we should move to a BigDecimal implementation or at least a soft float 256
|
||||||
// implementation for the constants.
|
// implementation for the constants.
|
||||||
char *end = NULL;
|
char *err = NULL;
|
||||||
#if LONG_DOUBLE
|
Float f = float_from_string(lexer->lexing_start, &err);
|
||||||
Real fval = strtold(lexer->lexing_start, &end);
|
if (f.type == TYPE_POISONED)
|
||||||
#else
|
|
||||||
Real fval = strtod(lexer->lexing_start, &end);
|
|
||||||
#endif
|
|
||||||
if (end != lexer->current)
|
|
||||||
{
|
{
|
||||||
return add_error_token(lexer, "Invalid float value.");
|
return add_error_token(lexer, err);
|
||||||
}
|
}
|
||||||
add_generic_token(lexer, TOKEN_REAL);
|
add_generic_token(lexer, TOKEN_REAL);
|
||||||
lexer->latest_token_data->value = fval;
|
lexer->latest_token_data->value = f;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
|
return add_token(lexer, TOKEN_INTEGER, lexer->lexing_start);
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ static void gencontext_emit_global_variable_definition(GenContext *c, Decl *decl
|
|||||||
{
|
{
|
||||||
decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal");
|
decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal");
|
||||||
}
|
}
|
||||||
if (decl->var.failable)
|
if (IS_FAILABLE(decl))
|
||||||
{
|
{
|
||||||
scratch_buffer_clear();
|
scratch_buffer_clear();
|
||||||
scratch_buffer_append(decl->external_name);
|
scratch_buffer_append(decl->external_name);
|
||||||
@@ -312,7 +312,8 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
|
|||||||
|
|
||||||
LLVMValueRef init_value;
|
LLVMValueRef init_value;
|
||||||
|
|
||||||
ByteSize alignment = type_alloca_alignment(decl->type);
|
Type *var_type = type_lowering(decl->type);
|
||||||
|
ByteSize alignment = type_alloca_alignment(var_type);
|
||||||
|
|
||||||
Expr *init_expr = decl->var.init_expr;
|
Expr *init_expr = decl->var.init_expr;
|
||||||
if (init_expr)
|
if (init_expr)
|
||||||
@@ -341,7 +342,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
init_value = LLVMConstNull(llvm_get_type(c, decl->type));
|
init_value = LLVMConstNull(llvm_get_type(c, var_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -359,7 +360,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
|
|||||||
{
|
{
|
||||||
llvm_set_alignment(failable_ref, type_alloca_alignment(type_anyerr));
|
llvm_set_alignment(failable_ref, type_alloca_alignment(type_anyerr));
|
||||||
}
|
}
|
||||||
if (decl->var.init_expr && decl->var.init_expr->failable)
|
if (init_expr && IS_FAILABLE(init_expr) && init_expr->expr_kind == EXPR_FAILABLE)
|
||||||
{
|
{
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
}
|
}
|
||||||
@@ -395,9 +396,9 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_value && LLVMTypeOf(init_value) != llvm_get_type(c, decl->type))
|
if (init_value && LLVMTypeOf(init_value) != llvm_get_type(c, var_type))
|
||||||
{
|
{
|
||||||
decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, decl->type));
|
decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, var_type));
|
||||||
}
|
}
|
||||||
LLVMReplaceAllUsesWith(old, decl->backend_ref);
|
LLVMReplaceAllUsesWith(old, decl->backend_ref);
|
||||||
LLVMDeleteGlobal(old);
|
LLVMDeleteGlobal(old);
|
||||||
@@ -467,12 +468,9 @@ LLVMValueRef llvm_emit_alloca_aligned(GenContext *c, Type *type, const char *nam
|
|||||||
|
|
||||||
void llvm_emit_and_set_decl_alloca(GenContext *c, Decl *decl)
|
void llvm_emit_and_set_decl_alloca(GenContext *c, Decl *decl)
|
||||||
{
|
{
|
||||||
if (decl->type == type_void)
|
Type *type = type_lowering(decl->type);
|
||||||
{
|
if (type == type_void) return;
|
||||||
return;
|
decl->backend_ref = llvm_emit_alloca(c, llvm_get_type(c, type), decl->alignment, decl->name ? decl->name : "anon");
|
||||||
}
|
|
||||||
LLVMTypeRef type = llvm_get_type(c, decl->type);
|
|
||||||
decl->backend_ref = llvm_emit_alloca(c, type, decl->alignment, decl->name ? decl->name : "anon");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void llvm_emit_local_var_alloca(GenContext *c, Decl *decl)
|
void llvm_emit_local_var_alloca(GenContext *c, Decl *decl)
|
||||||
@@ -789,7 +787,7 @@ void llvm_value_set_decl_address(BEValue *value, Decl *decl)
|
|||||||
llvm_value_set_address(value, decl_ref(decl), decl->type);
|
llvm_value_set_address(value, decl_ref(decl), decl->type);
|
||||||
value->alignment = decl->alignment;
|
value->alignment = decl->alignment;
|
||||||
|
|
||||||
if (decl->decl_kind == DECL_VAR && decl->var.failable)
|
if (decl->decl_kind == DECL_VAR && IS_FAILABLE(decl))
|
||||||
{
|
{
|
||||||
value->kind = BE_ADDRESS_FAILABLE;
|
value->kind = BE_ADDRESS_FAILABLE;
|
||||||
value->failable = decl->var.failable_ref;
|
value->failable = decl->var.failable_ref;
|
||||||
|
|||||||
@@ -237,3 +237,4 @@ ABIArgInfo *c_abi_classify_argument_type_default(Type *type)
|
|||||||
// No, then do a direct pass.
|
// No, then do a direct pass.
|
||||||
return abi_arg_new_direct();
|
return abi_arg_new_direct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,17 +140,18 @@ ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic)
|
|||||||
|
|
||||||
void c_abi_func_create_aarch64(FunctionSignature *signature)
|
void c_abi_func_create_aarch64(FunctionSignature *signature)
|
||||||
{
|
{
|
||||||
if (signature->failable)
|
Type *rtype = abi_rtype(signature);
|
||||||
|
if (IS_FAILABLE(signature->rtype))
|
||||||
{
|
{
|
||||||
signature->failable_abi_info = aarch64_classify_return_type(signature->rtype->type, signature->variadic == VARIADIC_RAW);
|
signature->failable_abi_info = aarch64_classify_return_type(rtype, signature->variadic == VARIADIC_RAW);
|
||||||
if (signature->rtype->type->type_kind != TYPE_VOID)
|
if (rtype->type_kind != TYPE_VOID)
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = aarch64_classify_argument_type(type_get_ptr(type_lowering(signature->rtype->type)));
|
signature->ret_abi_info = aarch64_classify_argument_type(type_get_ptr(type_lowering(rtype)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = aarch64_classify_return_type(signature->rtype->type, signature->variadic == VARIADIC_RAW);
|
signature->ret_abi_info = aarch64_classify_return_type(rtype, signature->variadic == VARIADIC_RAW);
|
||||||
}
|
}
|
||||||
Decl **params = signature->params;
|
Decl **params = signature->params;
|
||||||
VECEACH(params, i)
|
VECEACH(params, i)
|
||||||
|
|||||||
@@ -259,10 +259,12 @@ void c_abi_func_create_riscv(FunctionSignature *signature)
|
|||||||
unsigned gpr = 8;
|
unsigned gpr = 8;
|
||||||
unsigned fpr = 8;
|
unsigned fpr = 8;
|
||||||
|
|
||||||
Type *return_type = signature->failable ? type_anyerr : signature->rtype->type;
|
bool failable = IS_FAILABLE(signature->rtype);
|
||||||
|
Type *rtype = abi_rtype(signature);
|
||||||
|
Type *return_type = abi_returntype(signature);
|
||||||
return_type = type_lowering(return_type);
|
return_type = type_lowering(return_type);
|
||||||
ABIArgInfo *return_abi = riscv_classify_return(return_type);
|
ABIArgInfo *return_abi = riscv_classify_return(return_type);
|
||||||
if (signature->failable)
|
if (failable)
|
||||||
{
|
{
|
||||||
signature->failable_abi_info = return_abi;
|
signature->failable_abi_info = return_abi;
|
||||||
}
|
}
|
||||||
@@ -291,9 +293,9 @@ void c_abi_func_create_riscv(FunctionSignature *signature)
|
|||||||
unsigned arg_fprs_left = platform_target.riscv.flen ? fpr : 0;
|
unsigned arg_fprs_left = platform_target.riscv.flen ? fpr : 0;
|
||||||
|
|
||||||
// If we have a failable, then the return type is a parameter.
|
// If we have a failable, then the return type is a parameter.
|
||||||
if (signature->failable && signature->rtype->type->type_kind != TYPE_VOID)
|
if (IS_FAILABLE(signature->rtype) && rtype != type_void)
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = riscv_classify_argument_type(type_get_ptr(type_lowering(signature->rtype->type)),
|
signature->ret_abi_info = riscv_classify_argument_type(type_get_ptr(type_lowering(rtype)),
|
||||||
true, &arg_gprs_left, &arg_fprs_left);
|
true, &arg_gprs_left, &arg_fprs_left);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,19 +58,21 @@ static ABIArgInfo *wasm_classify_return(Type *type)
|
|||||||
|
|
||||||
void c_abi_func_create_wasm(FunctionSignature *signature)
|
void c_abi_func_create_wasm(FunctionSignature *signature)
|
||||||
{
|
{
|
||||||
if (signature->failable)
|
Type *rtype = abi_rtype(signature);
|
||||||
|
Type *return_type = abi_returntype(signature);
|
||||||
|
if (IS_FAILABLE(signature->rtype))
|
||||||
{
|
{
|
||||||
signature->failable_abi_info = wasm_classify_return(type_lowering(type_anyerr));
|
signature->failable_abi_info = wasm_classify_return(type_lowering(type_anyerr));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = wasm_classify_return(type_lowering(signature->rtype->type));
|
signature->ret_abi_info = wasm_classify_return(type_lowering(rtype));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a failable, then the return type is a parameter.
|
// If we have a failable, then the return type is a parameter.
|
||||||
if (signature->failable && signature->rtype->type->type_kind != TYPE_VOID)
|
if (IS_FAILABLE(signature->rtype) && rtype->type_kind != TYPE_VOID)
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = wasm_classify_argument_type(type_get_ptr(type_lowering(signature->rtype->type)));
|
signature->ret_abi_info = wasm_classify_argument_type(type_get_ptr(type_lowering(rtype)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl **params = signature->params;
|
Decl **params = signature->params;
|
||||||
|
|||||||
@@ -160,17 +160,18 @@ void c_abi_func_create_win64(FunctionSignature *signature)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature->failable)
|
Type *rtype = abi_rtype(signature);
|
||||||
|
if (IS_FAILABLE(signature->rtype))
|
||||||
{
|
{
|
||||||
signature->failable_abi_info = win64_classify(®s, type_anyerr, true, is_vector_call, is_reg_call);
|
signature->failable_abi_info = win64_classify(®s, type_anyerr, true, is_vector_call, is_reg_call);
|
||||||
if (signature->rtype->type->type_kind != TYPE_VOID)
|
if (rtype->type_kind != TYPE_VOID)
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = win64_classify(®s, type_get_ptr(type_lowering(signature->rtype->type)), false, is_vector_call, is_reg_call);
|
signature->ret_abi_info = win64_classify(®s, type_get_ptr(type_lowering(rtype)), false, is_vector_call, is_reg_call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = win64_classify(®s, signature->rtype->type, true, is_vector_call, is_reg_call);
|
signature->ret_abi_info = win64_classify(®s, rtype, true, is_vector_call, is_reg_call);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up parameter registers.
|
// Set up parameter registers.
|
||||||
|
|||||||
@@ -395,8 +395,6 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
|
|||||||
{
|
{
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_IXX:
|
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
@@ -404,6 +402,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
|
|||||||
case TYPE_ANYERR:
|
case TYPE_ANYERR:
|
||||||
case TYPE_ERRTYPE:
|
case TYPE_ERRTYPE:
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
|
case TYPE_FAILABLE:
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
@@ -589,8 +588,6 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
|
|||||||
return x64_get_int_type_at_offset(element, offset - element_offset, source_type, source_offset);
|
return x64_get_int_type_at_offset(element, offset - element_offset, source_type, source_offset);
|
||||||
}
|
}
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_IXX:
|
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
@@ -600,6 +597,7 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
|
|||||||
case TYPE_ANYERR:
|
case TYPE_ANYERR:
|
||||||
case TYPE_ERRTYPE:
|
case TYPE_ERRTYPE:
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
|
case TYPE_FAILABLE:
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_I128:
|
case TYPE_I128:
|
||||||
@@ -914,21 +912,22 @@ void c_abi_func_create_x64(FunctionSignature *signature)
|
|||||||
.sse_registers = is_regcall ? 16 : 8
|
.sse_registers = is_regcall ? 16 : 8
|
||||||
};
|
};
|
||||||
|
|
||||||
if (signature->failable)
|
Type *rtype = abi_rtype(signature);
|
||||||
|
if (IS_FAILABLE(signature->rtype))
|
||||||
{
|
{
|
||||||
signature->failable_abi_info = x64_classify_return_type(type_anyerr, &available_registers, is_regcall);
|
signature->failable_abi_info = x64_classify_return_type(type_anyerr, &available_registers, is_regcall);
|
||||||
if (abi_arg_is_indirect(signature->failable_abi_info))
|
if (abi_arg_is_indirect(signature->failable_abi_info))
|
||||||
{
|
{
|
||||||
available_registers.int_registers--;
|
available_registers.int_registers--;
|
||||||
}
|
}
|
||||||
if (signature->rtype->type->type_kind != TYPE_VOID)
|
if (rtype->type_kind != TYPE_VOID)
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = x64_classify_parameter(type_get_ptr(type_lowering(signature->rtype->type)), &available_registers, is_regcall, NAMED);
|
signature->ret_abi_info = x64_classify_parameter(type_get_ptr(type_lowering(rtype)), &available_registers, is_regcall, NAMED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = x64_classify_return_type(signature->rtype->type, &available_registers, is_regcall);
|
signature->ret_abi_info = x64_classify_return_type(rtype, &available_registers, is_regcall);
|
||||||
if (abi_arg_is_indirect(signature->ret_abi_info))
|
if (abi_arg_is_indirect(signature->ret_abi_info))
|
||||||
{
|
{
|
||||||
available_registers.int_registers--;
|
available_registers.int_registers--;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ static ABIArgInfo *create_indirect_return_x86(Type *type, Regs *regs)
|
|||||||
|
|
||||||
static bool x86_should_return_type_in_reg(Type *type)
|
static bool x86_should_return_type_in_reg(Type *type)
|
||||||
{
|
{
|
||||||
type = type->canonical;
|
assert(type->canonical == type);
|
||||||
unsigned size = type_size(type);
|
unsigned size = type_size(type);
|
||||||
if (size > 8) return false;
|
if (size > 8) return false;
|
||||||
|
|
||||||
@@ -119,6 +119,7 @@ static bool x86_should_return_type_in_reg(Type *type)
|
|||||||
case TYPE_ANYERR:
|
case TYPE_ANYERR:
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
|
case TYPE_FAILABLE:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case ALL_INTS:
|
case ALL_INTS:
|
||||||
case ALL_FLOATS:
|
case ALL_FLOATS:
|
||||||
@@ -384,7 +385,7 @@ static bool x86_try_put_primitive_in_reg(CallABI call, Regs *regs, Type *type)
|
|||||||
case CALL_X86_VECTOR:
|
case CALL_X86_VECTOR:
|
||||||
case CALL_X86_REG:
|
case CALL_X86_REG:
|
||||||
if (type_size(type) > 4) return false;
|
if (type_size(type) > 4) return false;
|
||||||
return type_is_integer_kind(type) || type_is_pointer(type);
|
return type_is_integer_or_bool_kind(type) || type_is_pointer(type);
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -594,6 +595,7 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type)
|
|||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
case TYPE_STRLIT:
|
case TYPE_STRLIT:
|
||||||
|
case TYPE_FAILABLE:
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case ALL_FLOATS:
|
case ALL_FLOATS:
|
||||||
@@ -655,17 +657,18 @@ void c_abi_func_create_x86(FunctionSignature *signature)
|
|||||||
|
|
||||||
// 4. Classify the return type. In the case of failable, we need to classify the failable itself as the
|
// 4. Classify the return type. In the case of failable, we need to classify the failable itself as the
|
||||||
// return type.
|
// return type.
|
||||||
if (signature->failable)
|
Type *rtype = abi_rtype(signature);
|
||||||
|
if (IS_FAILABLE(signature->rtype))
|
||||||
{
|
{
|
||||||
signature->failable_abi_info = x86_classify_return(signature->call_abi, ®s, type_anyerr);
|
signature->failable_abi_info = x86_classify_return(signature->call_abi, ®s, type_anyerr);
|
||||||
if (signature->rtype->type->type_kind != TYPE_VOID)
|
if (rtype->type_kind != TYPE_VOID)
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = x86_classify_argument(signature->call_abi, ®s, type_get_ptr(type_lowering(signature->rtype->type)));
|
signature->ret_abi_info = x86_classify_argument(signature->call_abi, ®s, type_get_ptr(type_lowering(rtype)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
signature->ret_abi_info = x86_classify_return(signature->call_abi, ®s, signature->rtype->type);
|
signature->ret_abi_info = x86_classify_return(signature->call_abi, ®s, rtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -289,9 +289,7 @@ static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetad
|
|||||||
VECEACH(enums, i)
|
VECEACH(enums, i)
|
||||||
{
|
{
|
||||||
Decl *enum_constant = enums[i];
|
Decl *enum_constant = enums[i];
|
||||||
uint64_t val = is_unsigned
|
uint64_t val = int_to_u64(enum_constant->enum_constant.expr->const_expr.ixx);
|
||||||
? bigint_as_unsigned(&enum_constant->enum_constant.expr->const_expr.i)
|
|
||||||
: (uint64_t)bigint_as_signed(&enum_constant->enum_constant.expr->const_expr.i);
|
|
||||||
LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator(
|
LLVMMetadataRef debug_info = LLVMDIBuilderCreateEnumerator(
|
||||||
c->debug.builder,
|
c->debug.builder,
|
||||||
enum_constant->name, TOKLEN(enum_constant->name_token),
|
enum_constant->name, TOKLEN(enum_constant->name_token),
|
||||||
@@ -481,12 +479,13 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
|
|||||||
// Consider special handling of UTF8 arrays.
|
// Consider special handling of UTF8 arrays.
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
case TYPE_IXX:
|
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_STRLIT:
|
case TYPE_STRLIT:
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
// If this is reachable then we're not doing the proper lowering.
|
||||||
|
UNREACHABLE
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
return llvm_debug_simple_type(c, type, DW_ATE_boolean);
|
return llvm_debug_simple_type(c, type, DW_ATE_boolean);
|
||||||
case TYPE_I8:
|
case TYPE_I8:
|
||||||
|
|||||||
@@ -1342,9 +1342,9 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
|
|||||||
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator);
|
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator);
|
||||||
case UNARYOP_NOT:
|
case UNARYOP_NOT:
|
||||||
llvm_emit_expr(c, value, inner);
|
llvm_emit_expr(c, value, inner);
|
||||||
llvm_value_rvalue(c, value);
|
|
||||||
if (type_is_vector(type))
|
if (type_is_vector(type))
|
||||||
{
|
{
|
||||||
|
llvm_value_rvalue(c, value);
|
||||||
Type *vec_type = type_vector_type(type);
|
Type *vec_type = type_vector_type(type);
|
||||||
if (type_is_float(vec_type))
|
if (type_is_float(vec_type))
|
||||||
{
|
{
|
||||||
@@ -1359,17 +1359,37 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
|
|||||||
llvm_value_set(value, llvm_value, res_type);
|
llvm_value_set(value, llvm_value, res_type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type_is_float(type))
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
llvm_value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, type), "not");
|
case ALL_FLOATS:
|
||||||
}
|
llvm_value_rvalue(c, value);
|
||||||
else if (type->type_kind == TYPE_BOOL)
|
llvm_value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, type), "not");
|
||||||
{
|
break;
|
||||||
llvm_value = LLVMBuildNot(c->builder, value->value, "not");
|
case TYPE_BOOL:
|
||||||
}
|
llvm_value_rvalue(c, value);
|
||||||
else
|
llvm_value = LLVMBuildNot(c->builder, value->value, "not");
|
||||||
{
|
break;
|
||||||
llvm_value = LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, type), "not");
|
case TYPE_SUBARRAY:
|
||||||
|
if (value->kind != BE_VALUE)
|
||||||
|
{
|
||||||
|
llvm_emit_len_for_expr(c, value, value);
|
||||||
|
llvm_value_rvalue(c, value);
|
||||||
|
llvm_value = value->value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
llvm_value = LLVMBuildExtractValue(c->builder, value->value, 1, "len");
|
||||||
|
}
|
||||||
|
llvm_value = LLVMBuildIsNull(c->builder, llvm_value, "not");
|
||||||
|
break;
|
||||||
|
case ALL_INTS:
|
||||||
|
case TYPE_POINTER:
|
||||||
|
llvm_value_rvalue(c, value);
|
||||||
|
llvm_value = LLVMBuildIsNull(c->builder, value->value, "not");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG_LOG("Unexpectedly tried to not %s", type_quoted_error_string(inner->type));
|
||||||
|
UNREACHABLE
|
||||||
}
|
}
|
||||||
llvm_value_set_bool(value, llvm_value);
|
llvm_value_set_bool(value, llvm_value);
|
||||||
return;
|
return;
|
||||||
@@ -1474,7 +1494,7 @@ static void llvm_emit_trap_zero(GenContext *c, Type *type, LLVMValueRef value, c
|
|||||||
if (!active_target.feature.safe_mode) return;
|
if (!active_target.feature.safe_mode) return;
|
||||||
|
|
||||||
LLVMValueRef zero = llvm_get_zero(c, type);
|
LLVMValueRef zero = llvm_get_zero(c, type);
|
||||||
LLVMValueRef ok = type_is_any_integer(type) ? LLVMBuildICmp(c->builder, LLVMIntEQ, value, zero, "zero") : LLVMBuildFCmp(c->builder, LLVMRealUEQ, value, zero, "zero");
|
LLVMValueRef ok = type_is_integer(type) ? LLVMBuildICmp(c->builder, LLVMIntEQ, value, zero, "zero") : LLVMBuildFCmp(c->builder, LLVMRealUEQ, value, zero, "zero");
|
||||||
llvm_emit_panic_on_true(c, ok, error, loc);
|
llvm_emit_panic_on_true(c, ok, error, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1809,6 +1829,8 @@ void llvm_emit_int_comp_zero(GenContext *c, BEValue *result, BEValue *lhs, Binar
|
|||||||
|
|
||||||
void llvm_emit_int_comparison(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op)
|
void llvm_emit_int_comparison(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op)
|
||||||
{
|
{
|
||||||
|
llvm_value_rvalue(c, lhs);
|
||||||
|
llvm_value_rvalue(c, rhs);
|
||||||
llvm_emit_int_comp(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op);
|
llvm_emit_int_comp(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op);
|
||||||
}
|
}
|
||||||
void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rhs_type, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op)
|
void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rhs_type, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op)
|
||||||
@@ -1858,6 +1880,30 @@ void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rh
|
|||||||
rhs_signed = false;
|
rhs_signed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (lhs_signed && !rhs_signed && !vector_type && LLVMIsConstant(lhs_value) && type_size(lhs_type) <= 64)
|
||||||
|
{
|
||||||
|
long long val = LLVMConstIntGetSExtValue(lhs_value);
|
||||||
|
if (val < 0)
|
||||||
|
{
|
||||||
|
switch (binary_op)
|
||||||
|
{
|
||||||
|
case BINARYOP_EQ:
|
||||||
|
case BINARYOP_GE:
|
||||||
|
case BINARYOP_GT:
|
||||||
|
llvm_value_set(result, llvm_const_int(c, type_bool, 0), type_bool);
|
||||||
|
return;
|
||||||
|
case BINARYOP_NE:
|
||||||
|
case BINARYOP_LE:
|
||||||
|
case BINARYOP_LT:
|
||||||
|
llvm_value_set(result, llvm_const_int(c, type_bool, 1), type_bool);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lhs_signed = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!lhs_signed)
|
if (!lhs_signed)
|
||||||
{
|
{
|
||||||
assert(lhs_signed == rhs_signed);
|
assert(lhs_signed == rhs_signed);
|
||||||
@@ -1895,9 +1941,11 @@ void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rh
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Left side is signed.
|
// Left side is signed.
|
||||||
LLVMValueRef comp_value;
|
LLVMValueRef comp_value;
|
||||||
LLVMValueRef check_value;
|
LLVMValueRef check_value;
|
||||||
|
|
||||||
switch (binary_op)
|
switch (binary_op)
|
||||||
{
|
{
|
||||||
case BINARYOP_EQ:
|
case BINARYOP_EQ:
|
||||||
@@ -2378,8 +2426,8 @@ static void llvm_emit_post_unary_expr(GenContext *context, BEValue *be_value, Ex
|
|||||||
|
|
||||||
llvm_emit_post_inc_dec(context,
|
llvm_emit_post_inc_dec(context,
|
||||||
be_value,
|
be_value,
|
||||||
expr->post_expr.expr,
|
expr->unary_expr.expr,
|
||||||
expr->post_expr.operator == POSTUNARYOP_INC ? 1 : -1,
|
expr->unary_expr.operator == UNARYOP_INC ? 1 : -1,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2474,9 +2522,39 @@ void llvm_emit_try_assign_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void llvm_emit_catch_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||||
|
{
|
||||||
|
LLVMBasicBlockRef end_block = llvm_basic_block_new(c, "noerr_block");
|
||||||
|
|
||||||
|
// Store catch/error var
|
||||||
|
PUSH_ERROR();
|
||||||
|
|
||||||
|
LLVMValueRef error_var = llvm_emit_alloca_aligned(c, type_anyerr, "error_var");
|
||||||
|
llvm_value_set_address(value, error_var, type_anyerr);
|
||||||
|
llvm_store_bevalue_raw(c, value, llvm_get_zero(c, type_anyerr));
|
||||||
|
c->error_var = error_var;
|
||||||
|
c->catch_block = end_block;
|
||||||
|
|
||||||
|
BEValue expr_value;
|
||||||
|
llvm_emit_expr(c, &expr_value, expr->try_expr.expr);
|
||||||
|
llvm_value_fold_failable(c, &expr_value);
|
||||||
|
|
||||||
|
// Restore.
|
||||||
|
POP_ERROR();
|
||||||
|
|
||||||
|
// Emit success and jump to end block.
|
||||||
|
llvm_emit_br(c, end_block);
|
||||||
|
|
||||||
|
llvm_emit_block(c, end_block);
|
||||||
|
|
||||||
|
}
|
||||||
void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
|
void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||||
{
|
{
|
||||||
|
if (!expr->try_expr.is_try)
|
||||||
|
{
|
||||||
|
llvm_emit_catch_expr(c, value, expr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block");
|
LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block");
|
||||||
LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block");
|
LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block");
|
||||||
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_trycatch_block");
|
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_trycatch_block");
|
||||||
@@ -2505,9 +2583,9 @@ void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
|
|||||||
|
|
||||||
llvm_emit_block(c, phi_block);
|
llvm_emit_block(c, phi_block);
|
||||||
|
|
||||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
|
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
|
||||||
LLVMValueRef lhs = llvm_const_int(c, type_bool, expr->try_expr.is_try ? 1 : 0);
|
LLVMValueRef lhs = llvm_const_int(c, type_bool, 1);
|
||||||
LLVMValueRef rhs = llvm_const_int(c, type_bool, expr->try_expr.is_try ? 0 : 1);
|
LLVMValueRef rhs = llvm_const_int(c, type_bool, 0);
|
||||||
|
|
||||||
LLVMValueRef logic_values[2] = { lhs, rhs };
|
LLVMValueRef logic_values[2] = { lhs, rhs };
|
||||||
LLVMBasicBlockRef blocks[2] = { no_err_block, error_block };
|
LLVMBasicBlockRef blocks[2] = { no_err_block, error_block };
|
||||||
@@ -2832,21 +2910,21 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
|
|||||||
|
|
||||||
llvm_value_set(value, phi, expr->type);
|
llvm_value_set(value, phi, expr->type);
|
||||||
}
|
}
|
||||||
static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Real f)
|
static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Float f)
|
||||||
{
|
{
|
||||||
if (isnan(f))
|
if (isnan(f.f))
|
||||||
{
|
{
|
||||||
return LLVMConstRealOfString(type, "nan");
|
return LLVMConstRealOfString(type, "nan");
|
||||||
}
|
}
|
||||||
if (isinf(f))
|
if (isinf(f.f))
|
||||||
{
|
{
|
||||||
return LLVMConstRealOfString(type, f < 0 ? "-inf" : "inf");
|
return LLVMConstRealOfString(type, f.f < 0 ? "-inf" : "inf");
|
||||||
}
|
}
|
||||||
scratch_buffer_clear();
|
scratch_buffer_clear();
|
||||||
#if LONG_DOUBLE
|
#if LONG_DOUBLE
|
||||||
global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%La", f);
|
global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%La", f.f);
|
||||||
#else
|
#else
|
||||||
global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%a", f);
|
global_context.scratch_buffer_len = sprintf(global_context.scratch_buffer, "%a", f.f);
|
||||||
#endif
|
#endif
|
||||||
return LLVMConstRealOfStringAndSize(type, global_context.scratch_buffer, global_context.scratch_buffer_len);
|
return LLVMConstRealOfStringAndSize(type, global_context.scratch_buffer, global_context.scratch_buffer_len);
|
||||||
}
|
}
|
||||||
@@ -2884,20 +2962,30 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case CONST_INTEGER:
|
case CONST_INTEGER:
|
||||||
if (type_is_unsigned(type))
|
{
|
||||||
|
LLVMValueRef value;
|
||||||
|
Int128 i = expr->const_expr.ixx.i;
|
||||||
|
switch (expr->const_expr.ixx.type)
|
||||||
{
|
{
|
||||||
llvm_value_set(be_value, llvm_const_int(c, type, bigint_as_unsigned(&expr->const_expr.i)), type);
|
case TYPE_I128:
|
||||||
}
|
case TYPE_U128:
|
||||||
else
|
{
|
||||||
{
|
uint64_t words[2] = { i.low, i.high };
|
||||||
llvm_value_set(be_value, llvm_const_int(c, type, bigint_as_signed(&expr->const_expr.i)), type);
|
value = LLVMConstIntOfArbitraryPrecision(llvm_get_type(c, type), 2, words);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
value = llvm_const_int(c, type, i.low);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
llvm_value_set(be_value, value, type);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
case CONST_LIST:
|
case CONST_LIST:
|
||||||
llvm_emit_const_initializer_list_expr(c, be_value, expr);
|
llvm_emit_const_initializer_list_expr(c, be_value, expr);
|
||||||
return;
|
return;
|
||||||
case CONST_FLOAT:
|
case CONST_FLOAT:
|
||||||
llvm_value_set(be_value, llvm_emit_real(llvm_get_type(c, type), expr->const_expr.f), type);
|
llvm_value_set(be_value, llvm_emit_real(llvm_get_type(c, type), expr->const_expr.fxx), type);
|
||||||
return;
|
return;
|
||||||
case CONST_POINTER:
|
case CONST_POINTER:
|
||||||
llvm_value_set(be_value, LLVMConstNull(llvm_get_type(c, type)), type);
|
llvm_value_set(be_value, LLVMConstNull(llvm_get_type(c, type)), type);
|
||||||
@@ -2987,8 +3075,6 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
|
|||||||
switch (type_lowering(param_type)->type_kind)
|
switch (type_lowering(param_type)->type_kind)
|
||||||
{
|
{
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
case TYPE_IXX:
|
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
@@ -2997,13 +3083,13 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
|
|||||||
case TYPE_ERRTYPE:
|
case TYPE_ERRTYPE:
|
||||||
case TYPE_ANYERR:
|
case TYPE_ANYERR:
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
|
case TYPE_FAILABLE:
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
break;
|
break;
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
case ALL_SIGNED_INTS:
|
case ALL_INTS:
|
||||||
case ALL_UNSIGNED_INTS:
|
case ALL_FLOATS:
|
||||||
case ALL_REAL_FLOATS:
|
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
vec_add(*values, LLVMBuildLoad2(context->builder, llvm_get_type(context, param_type), expand_ptr, "loadexpanded"));
|
vec_add(*values, LLVMBuildLoad2(context->builder, llvm_get_type(context, param_type), expand_ptr, "loadexpanded"));
|
||||||
return;
|
return;
|
||||||
@@ -3312,14 +3398,14 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
|||||||
|
|
||||||
// 4. Prepare the return abi data.
|
// 4. Prepare the return abi data.
|
||||||
ABIArgInfo *ret_info = signature->ret_abi_info;
|
ABIArgInfo *ret_info = signature->ret_abi_info;
|
||||||
Type *return_type = signature->rtype->type->canonical;
|
Type *return_type = abi_returntype(signature);
|
||||||
|
bool is_failable = IS_FAILABLE(signature->rtype);
|
||||||
|
|
||||||
// 5. In the case of a failable, the error is replacing the regular return abi.
|
// 5. In the case of a failable, the error is replacing the regular return abi.
|
||||||
LLVMValueRef error_var = NULL;
|
LLVMValueRef error_var = NULL;
|
||||||
if (signature->failable)
|
if (is_failable)
|
||||||
{
|
{
|
||||||
ret_info = signature->failable_abi_info;
|
ret_info = signature->failable_abi_info;
|
||||||
return_type = type_anyerr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*result_value = (BEValue){ .kind = BE_VALUE, .value = NULL };
|
*result_value = (BEValue){ .kind = BE_VALUE, .value = NULL };
|
||||||
@@ -3328,7 +3414,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
|||||||
{
|
{
|
||||||
case ABI_ARG_INDIRECT:
|
case ABI_ARG_INDIRECT:
|
||||||
// 6a. We can use the stored error var if there is no redirect.
|
// 6a. We can use the stored error var if there is no redirect.
|
||||||
if (signature->failable && c->error_var && !ret_info->attributes.realign)
|
if (is_failable && c->error_var && !ret_info->attributes.realign)
|
||||||
{
|
{
|
||||||
error_var = c->error_var;
|
error_var = c->error_var;
|
||||||
vec_add(values, error_var);
|
vec_add(values, error_var);
|
||||||
@@ -3355,7 +3441,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
|||||||
// 7. We might have a failable indirect return and a normal return.
|
// 7. We might have a failable indirect return and a normal return.
|
||||||
// In this case we need to add it by hand.
|
// In this case we need to add it by hand.
|
||||||
BEValue synthetic_return_param = { 0 };
|
BEValue synthetic_return_param = { 0 };
|
||||||
if (signature->failable && signature->ret_abi_info)
|
if (is_failable && signature->ret_abi_info)
|
||||||
{
|
{
|
||||||
// 7b. Create the address to hold the return.
|
// 7b. Create the address to hold the return.
|
||||||
Type *actual_return_type = type_lowering(signature->rtype->type);
|
Type *actual_return_type = type_lowering(signature->rtype->type);
|
||||||
@@ -3494,7 +3580,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
|||||||
case ABI_ARG_IGNORE:
|
case ABI_ARG_IGNORE:
|
||||||
// 12. Basically void returns or empty structs.
|
// 12. Basically void returns or empty structs.
|
||||||
// Here we know we don't have a failable or any return value that can be used.
|
// Here we know we don't have a failable or any return value that can be used.
|
||||||
assert(!signature->failable && "Failable should have produced a return value.");
|
assert(!is_failable && "Failable should have produced a return value.");
|
||||||
*result_value = (BEValue) { .type = type_void, .kind = BE_VALUE };
|
*result_value = (BEValue) { .type = type_void, .kind = BE_VALUE };
|
||||||
return;
|
return;
|
||||||
case ABI_ARG_INDIRECT:
|
case ABI_ARG_INDIRECT:
|
||||||
@@ -3602,7 +3688,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 17. Handle failables.
|
// 17. Handle failables.
|
||||||
if (signature->failable)
|
if (is_failable)
|
||||||
{
|
{
|
||||||
BEValue no_err;
|
BEValue no_err;
|
||||||
|
|
||||||
@@ -3668,7 +3754,7 @@ static inline void gencontext_emit_expression_list_expr(GenContext *context, BEV
|
|||||||
|
|
||||||
static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value, Type *type, Ast **stmts)
|
static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value, Type *type, Ast **stmts)
|
||||||
{
|
{
|
||||||
|
Type *type_lowered = type_lowering(type);
|
||||||
LLVMValueRef old_ret_out = context->return_out;
|
LLVMValueRef old_ret_out = context->return_out;
|
||||||
LLVMBasicBlockRef saved_block_return_exit = context->block_return_exit;
|
LLVMBasicBlockRef saved_block_return_exit = context->block_return_exit;
|
||||||
LLVMBasicBlockRef saved_block_failable_exit = context->block_failable_exit;
|
LLVMBasicBlockRef saved_block_failable_exit = context->block_failable_exit;
|
||||||
@@ -3682,9 +3768,9 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
|||||||
LLVMValueRef error_out = context->error_var;
|
LLVMValueRef error_out = context->error_var;
|
||||||
LLVMBasicBlockRef error_block = context->catch_block;
|
LLVMBasicBlockRef error_block = context->catch_block;
|
||||||
|
|
||||||
if (type != type_void)
|
if (type_lowered != type_void)
|
||||||
{
|
{
|
||||||
return_out = llvm_emit_alloca_aligned(context, type, "blockret");
|
return_out = llvm_emit_alloca_aligned(context, type_lowered, "blockret");
|
||||||
}
|
}
|
||||||
context->block_error_var = error_out;
|
context->block_error_var = error_out;
|
||||||
context->block_failable_exit = error_block;
|
context->block_failable_exit = error_block;
|
||||||
@@ -3711,7 +3797,7 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value
|
|||||||
|
|
||||||
if (return_out)
|
if (return_out)
|
||||||
{
|
{
|
||||||
llvm_value_set_address(be_value, return_out, type);
|
llvm_value_set_address(be_value, return_out, type_lowered);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -3783,7 +3869,7 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
|
|||||||
|
|
||||||
if (failable)
|
if (failable)
|
||||||
{
|
{
|
||||||
if (expr->failable)
|
if (IS_FAILABLE(expr))
|
||||||
{
|
{
|
||||||
assign_block = llvm_basic_block_new(c, "after_assign");
|
assign_block = llvm_basic_block_new(c, "after_assign");
|
||||||
c->error_var = failable;
|
c->error_var = failable;
|
||||||
@@ -3823,7 +3909,7 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
|
|||||||
}
|
}
|
||||||
POP_ERROR();
|
POP_ERROR();
|
||||||
|
|
||||||
if (failable && expr->failable)
|
if (failable && IS_FAILABLE(expr))
|
||||||
{
|
{
|
||||||
llvm_emit_br(c, assign_block);
|
llvm_emit_br(c, assign_block);
|
||||||
llvm_emit_block(c, assign_block);
|
llvm_emit_block(c, assign_block);
|
||||||
@@ -3848,12 +3934,13 @@ static inline void gencontext_emit_failable(GenContext *context, BEValue *be_val
|
|||||||
llvm_emit_br(context, context->catch_block);
|
llvm_emit_br(context, context->catch_block);
|
||||||
LLVMBasicBlockRef ignored_block = llvm_basic_block_new(context, "postfailed");
|
LLVMBasicBlockRef ignored_block = llvm_basic_block_new(context, "postfailed");
|
||||||
llvm_emit_block(context, ignored_block);
|
llvm_emit_block(context, ignored_block);
|
||||||
if (expr->type->canonical == type_void)
|
Type *type = type_no_fail(expr->type);
|
||||||
|
if (type->canonical == type_void)
|
||||||
{
|
{
|
||||||
llvm_value_set(be_value, NULL, type_void);
|
llvm_value_set(be_value, NULL, type_void);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(context, expr->type)), expr->type);
|
llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(context, type)), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, ArrayIndex index, bool *is_const)
|
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, ArrayIndex index, bool *is_const)
|
||||||
@@ -3931,12 +4018,14 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
|
|||||||
|
|
||||||
static inline void llvm_emit_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr)
|
static inline void llvm_emit_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||||
{
|
{
|
||||||
if (type_is_vector(expr->type))
|
Type *type = type_lowering(expr->type);
|
||||||
|
if (type_is_vector(type))
|
||||||
{
|
{
|
||||||
llvm_emit_vector_initializer_list(c, value, expr);
|
llvm_emit_vector_initializer_list(c, value, expr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
llvm_value_set_address(value, llvm_emit_alloca_aligned(c, expr->type, "literal"), expr->type);
|
assert(!IS_FAILABLE(expr) || c->catch_block);
|
||||||
|
llvm_value_set_address(value, llvm_emit_alloca_aligned(c, type, "literal"), type);
|
||||||
llvm_emit_initialize_reference(c, value, expr);
|
llvm_emit_initialize_reference(c, value, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4127,6 +4216,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
|||||||
llvm_emit_try_assign_expr(c, value, expr);
|
llvm_emit_try_assign_expr(c, value, expr);
|
||||||
return;
|
return;
|
||||||
case EXPR_NOP:
|
case EXPR_NOP:
|
||||||
|
llvm_value_set(value, NULL, type_void);
|
||||||
return;
|
return;
|
||||||
case EXPR_ELSE:
|
case EXPR_ELSE:
|
||||||
gencontext_emit_else_expr(c, value, expr);
|
gencontext_emit_else_expr(c, value, expr);
|
||||||
|
|||||||
@@ -250,12 +250,14 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl
|
|||||||
// If we have a failable it's always the return argument, so we need to copy
|
// If we have a failable it's always the return argument, so we need to copy
|
||||||
// the return value into the return value holder.
|
// the return value into the return value holder.
|
||||||
LLVMValueRef return_out = c->return_out;
|
LLVMValueRef return_out = c->return_out;
|
||||||
|
bool is_failable = IS_FAILABLE(signature->rtype);
|
||||||
Type *return_type = signature->rtype->type;
|
Type *return_type = signature->rtype->type;
|
||||||
|
if (is_failable) return_type = return_type->failable;
|
||||||
|
|
||||||
BEValue no_fail;
|
BEValue no_fail;
|
||||||
|
|
||||||
// In this case we use the failable as the actual return.
|
// In this case we use the failable as the actual return.
|
||||||
if (signature->failable)
|
if (is_failable)
|
||||||
{
|
{
|
||||||
if (return_value && return_value->value)
|
if (return_value && return_value->value)
|
||||||
{
|
{
|
||||||
@@ -346,18 +348,19 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl
|
|||||||
|
|
||||||
void llvm_emit_return_implicit(GenContext *c)
|
void llvm_emit_return_implicit(GenContext *c)
|
||||||
{
|
{
|
||||||
if (c->cur_func_decl->func_decl.function_signature.rtype->type != type_void)
|
Type *rtype_real = c->cur_func_decl->func_decl.function_signature.rtype->type;
|
||||||
|
if (type_lowering(type_no_fail(rtype_real)) != type_void)
|
||||||
{
|
{
|
||||||
LLVMBuildUnreachable(c->builder);
|
LLVMBuildUnreachable(c->builder);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!c->cur_func_decl->func_decl.function_signature.failable)
|
if (rtype_real->type_kind == TYPE_FAILABLE)
|
||||||
{
|
{
|
||||||
llvm_emit_return_abi(c, NULL, NULL);
|
llvm_emit_return_abi(c, NULL, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BEValue value;
|
BEValue value;
|
||||||
llvm_value_set(&value, LLVMConstNull(llvm_get_type(c, type_anyerr)), type_anyerr);
|
llvm_value_set(&value, llvm_get_zero(c, type_anyerr), type_anyerr);
|
||||||
llvm_emit_return_abi(c, NULL, &value);
|
llvm_emit_return_abi(c, NULL, &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +403,8 @@ void llvm_emit_function_body(GenContext *context, Decl *decl)
|
|||||||
llvm_debug_scope_push(context, context->debug.function);
|
llvm_debug_scope_push(context, context->debug.function);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature->failable && signature->failable_abi_info->kind == ABI_ARG_INDIRECT)
|
bool is_failable = IS_FAILABLE(signature->rtype);
|
||||||
|
if (is_failable && signature->failable_abi_info->kind == ABI_ARG_INDIRECT)
|
||||||
{
|
{
|
||||||
context->failable_out = LLVMGetParam(context->function, arg++);
|
context->failable_out = LLVMGetParam(context->function, arg++);
|
||||||
}
|
}
|
||||||
@@ -415,7 +419,7 @@ void llvm_emit_function_body(GenContext *context, Decl *decl)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
context->return_out = NULL;
|
context->return_out = NULL;
|
||||||
if (signature->ret_abi_info && signature->failable)
|
if (signature->ret_abi_info && is_failable)
|
||||||
{
|
{
|
||||||
context->return_out = LLVMGetParam(context->function, arg++);
|
context->return_out = LLVMGetParam(context->function, arg++);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ static inline LLVMValueRef decl_failable_ref(Decl *decl)
|
|||||||
{
|
{
|
||||||
assert(decl->decl_kind == DECL_VAR);
|
assert(decl->decl_kind == DECL_VAR);
|
||||||
if (decl->var.kind == VARDECL_UNWRAPPED) return decl_failable_ref(decl->var.alias);
|
if (decl->var.kind == VARDECL_UNWRAPPED) return decl_failable_ref(decl->var.alias);
|
||||||
if (!decl->var.failable) return NULL;
|
if (decl->type->type_kind != TYPE_FAILABLE) return NULL;
|
||||||
return decl->var.failable_ref;
|
return decl->var.failable_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,7 +411,7 @@ static inline LLVMValueRef llvm_get_zero(GenContext *c, Type *type)
|
|||||||
static inline LLVMValueRef llvm_const_int(GenContext *c, Type *type, uint64_t val)
|
static inline LLVMValueRef llvm_const_int(GenContext *c, Type *type, uint64_t val)
|
||||||
{
|
{
|
||||||
type = type_lowering(type);
|
type = type_lowering(type);
|
||||||
assert(type_is_any_integer(type) || type->type_kind == TYPE_BOOL);
|
assert(type_is_integer(type) || type->type_kind == TYPE_BOOL);
|
||||||
return LLVMConstInt(llvm_get_type(c, type), val, type_is_integer_signed(type));
|
return LLVMConstInt(llvm_get_type(c, type), val, type_is_integer_signed(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,3 +438,4 @@ static inline bool abi_info_should_flatten(ABIArgInfo *info)
|
|||||||
{
|
{
|
||||||
return info->kind == ABI_ARG_DIRECT_COERCE && info->direct_coerce.elements > 1U && !info->direct_coerce.prevent_flatten;
|
return info->kind == ABI_ARG_DIRECT_COERCE && info->direct_coerce.elements > 1U && !info->direct_coerce.prevent_flatten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ void gencontext_emit_ct_compound_stmt(GenContext *context, Ast *ast)
|
|||||||
LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
|
LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
|
||||||
{
|
{
|
||||||
// 1. Get the declaration and the LLVM type.
|
// 1. Get the declaration and the LLVM type.
|
||||||
LLVMTypeRef alloc_type = llvm_get_type(c, type_lowering(decl->type));
|
Type *var_type = type_lowering(type_no_fail(decl->type));
|
||||||
|
LLVMTypeRef alloc_type = llvm_get_type(c, var_type);
|
||||||
|
|
||||||
// 2. In the case we have a static variable,
|
// 2. In the case we have a static variable,
|
||||||
// then we essentially treat this as a global.
|
// then we essentially treat this as a global.
|
||||||
@@ -56,8 +57,8 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
|
|||||||
{
|
{
|
||||||
void *builder = c->builder;
|
void *builder = c->builder;
|
||||||
c->builder = NULL;
|
c->builder = NULL;
|
||||||
decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal");
|
decl->backend_ref = LLVMAddGlobal(c->module, alloc_type, "tempglobal");
|
||||||
if (decl->var.failable)
|
if (IS_FAILABLE(decl))
|
||||||
{
|
{
|
||||||
scratch_buffer_clear();
|
scratch_buffer_clear();
|
||||||
scratch_buffer_append(decl->external_name);
|
scratch_buffer_append(decl->external_name);
|
||||||
@@ -69,14 +70,14 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
|
|||||||
return decl->backend_ref;
|
return decl->backend_ref;
|
||||||
}
|
}
|
||||||
llvm_emit_local_var_alloca(c, decl);
|
llvm_emit_local_var_alloca(c, decl);
|
||||||
if (decl->var.failable)
|
if (IS_FAILABLE(decl))
|
||||||
{
|
{
|
||||||
scratch_buffer_clear();
|
scratch_buffer_clear();
|
||||||
scratch_buffer_append(decl->name);
|
scratch_buffer_append(decl->name);
|
||||||
scratch_buffer_append(".f");
|
scratch_buffer_append(".f");
|
||||||
decl->var.failable_ref = llvm_emit_alloca_aligned(c, type_anyerr, scratch_buffer_to_string());
|
decl->var.failable_ref = llvm_emit_alloca_aligned(c, type_anyerr, scratch_buffer_to_string());
|
||||||
// Only clear out the result if the assignment isn't a failable.
|
// Only clear out the result if the assignment isn't a failable.
|
||||||
if (!decl->var.init_expr || !decl->var.init_expr->failable)
|
if (!decl->var.init_expr || !IS_FAILABLE(decl->var.init_expr))
|
||||||
{
|
{
|
||||||
LLVMBuildStore(c->builder, LLVMConstNull(llvm_get_type(c, type_anyerr)), decl->var.failable_ref);
|
LLVMBuildStore(c->builder, LLVMConstNull(llvm_get_type(c, type_anyerr)), decl->var.failable_ref);
|
||||||
}
|
}
|
||||||
@@ -178,7 +179,7 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast)
|
|||||||
c->error_var = c->block_error_var;
|
c->error_var = c->block_error_var;
|
||||||
c->catch_block = c->block_failable_exit;
|
c->catch_block = c->block_failable_exit;
|
||||||
}
|
}
|
||||||
else if (c->cur_func_decl->func_decl.function_signature.failable)
|
else if (IS_FAILABLE(c->cur_func_decl->func_decl.function_signature.rtype))
|
||||||
{
|
{
|
||||||
error_return_block = llvm_basic_block_new(c, "err_retblock");
|
error_return_block = llvm_basic_block_new(c, "err_retblock");
|
||||||
error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr");
|
error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr");
|
||||||
@@ -962,6 +963,96 @@ void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast)
|
|||||||
llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end);
|
llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool expr_is_pure(Expr *expr)
|
||||||
|
{
|
||||||
|
if (!expr) return true;
|
||||||
|
switch (expr->expr_kind)
|
||||||
|
{
|
||||||
|
case EXPR_CONST:
|
||||||
|
case EXPR_CONST_IDENTIFIER:
|
||||||
|
case EXPR_IDENTIFIER:
|
||||||
|
case EXPR_NOP:
|
||||||
|
return true;
|
||||||
|
case EXPR_BINARY:
|
||||||
|
if (expr->binary_expr.operator >= BINARYOP_ASSIGN) return false;
|
||||||
|
return expr_is_pure(expr->binary_expr.right) && expr_is_pure(expr->binary_expr.left);
|
||||||
|
case EXPR_UNARY:
|
||||||
|
switch (expr->unary_expr.operator)
|
||||||
|
{
|
||||||
|
case UNARYOP_INC:
|
||||||
|
case UNARYOP_DEC:
|
||||||
|
case UNARYOP_TADDR:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return expr_is_pure(expr->unary_expr.expr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXPR_ACCESS:
|
||||||
|
return expr_is_pure(expr->access_expr.parent);
|
||||||
|
case EXPR_POISONED:
|
||||||
|
case EXPR_CT_IDENT:
|
||||||
|
case EXPR_TYPEID:
|
||||||
|
case EXPR_CT_CALL:
|
||||||
|
case EXPR_TYPEOF:
|
||||||
|
UNREACHABLE
|
||||||
|
case EXPR_MACRO_BODY_EXPANSION:
|
||||||
|
case EXPR_CALL:
|
||||||
|
case EXPR_CATCH_UNWRAP:
|
||||||
|
case EXPR_COMPOUND_LITERAL:
|
||||||
|
case EXPR_COND:
|
||||||
|
case EXPR_DESIGNATOR:
|
||||||
|
case EXPR_DECL:
|
||||||
|
case EXPR_ELSE:
|
||||||
|
case EXPR_EXPR_BLOCK:
|
||||||
|
case EXPR_FAILABLE:
|
||||||
|
case EXPR_GUARD:
|
||||||
|
case EXPR_HASH_IDENT:
|
||||||
|
case EXPR_MACRO_BLOCK:
|
||||||
|
case EXPR_MACRO_EXPANSION:
|
||||||
|
case EXPR_FLATPATH:
|
||||||
|
case EXPR_INITIALIZER_LIST:
|
||||||
|
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||||
|
case EXPR_PLACEHOLDER:
|
||||||
|
case EXPR_POST_UNARY:
|
||||||
|
case EXPR_SCOPED_EXPR:
|
||||||
|
case EXPR_SLICE_ASSIGN:
|
||||||
|
case EXPR_TRY_UNWRAP:
|
||||||
|
case EXPR_TRY_UNWRAP_CHAIN:
|
||||||
|
case EXPR_TRY_ASSIGN:
|
||||||
|
case EXPR_UNDEF:
|
||||||
|
case EXPR_TYPEINFO:
|
||||||
|
return false;
|
||||||
|
case EXPR_CAST:
|
||||||
|
return expr_is_pure(expr->cast_expr.expr);
|
||||||
|
case EXPR_EXPRESSION_LIST:
|
||||||
|
{
|
||||||
|
VECEACH(expr->expression_list, i)
|
||||||
|
{
|
||||||
|
if (!expr_is_pure(expr->expression_list[i])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXPR_GROUP:
|
||||||
|
return expr_is_pure(expr->group_expr);
|
||||||
|
case EXPR_LEN:
|
||||||
|
return expr_is_pure(expr->len_expr.inner);
|
||||||
|
case EXPR_SLICE:
|
||||||
|
return expr_is_pure(expr->slice_expr.expr)
|
||||||
|
&& expr_is_pure(expr->slice_expr.start)
|
||||||
|
&& expr_is_pure(expr->slice_expr.end);
|
||||||
|
case EXPR_SUBSCRIPT:
|
||||||
|
return expr_is_pure(expr->subscript_expr.expr)
|
||||||
|
&& expr_is_pure(expr->subscript_expr.index);
|
||||||
|
case EXPR_TERNARY:
|
||||||
|
return expr_is_pure(expr->ternary_expr.cond)
|
||||||
|
&& expr_is_pure(expr->ternary_expr.else_expr)
|
||||||
|
&& expr_is_pure(expr->ternary_expr.then_expr);
|
||||||
|
case EXPR_TRY:
|
||||||
|
return expr_is_pure(expr->try_expr.expr);
|
||||||
|
}
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
|
|
||||||
static inline void llvm_emit_assume(GenContext *c, Expr *expr)
|
static inline void llvm_emit_assume(GenContext *c, Expr *expr)
|
||||||
{
|
{
|
||||||
@@ -994,7 +1085,7 @@ static inline void llvm_emit_assume(GenContext *c, Expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. Check if pure, if so we emit the assume.
|
// 3. Check if pure, if so we emit the assume.
|
||||||
if (expr->pure)
|
if (expr_is_pure(expr))
|
||||||
{
|
{
|
||||||
BEValue value;
|
BEValue value;
|
||||||
llvm_emit_expr(c, &value, expr);
|
llvm_emit_expr(c, &value, expr);
|
||||||
@@ -1092,7 +1183,7 @@ static inline void gencontext_emit_unreachable_stmt(GenContext *context, Ast *as
|
|||||||
void gencontext_emit_expr_stmt(GenContext *c, Ast *ast)
|
void gencontext_emit_expr_stmt(GenContext *c, Ast *ast)
|
||||||
{
|
{
|
||||||
BEValue value;
|
BEValue value;
|
||||||
if (ast->expr_stmt->failable)
|
if (IS_FAILABLE(ast->expr_stmt))
|
||||||
{
|
{
|
||||||
PUSH_ERROR();
|
PUSH_ERROR();
|
||||||
LLVMBasicBlockRef discard_fail = llvm_basic_block_new(c, "voiderr");
|
LLVMBasicBlockRef discard_fail = llvm_basic_block_new(c, "voiderr");
|
||||||
@@ -1279,7 +1370,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
|
|||||||
case AST_DOCS:
|
case AST_DOCS:
|
||||||
case AST_DOC_DIRECTIVE:
|
case AST_DOC_DIRECTIVE:
|
||||||
case AST_POISONED:
|
case AST_POISONED:
|
||||||
case AST_DEFINE_STMT:
|
case AST_VAR_STMT:
|
||||||
case AST_IF_CATCH_SWITCH_STMT:
|
case AST_IF_CATCH_SWITCH_STMT:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case AST_SCOPED_STMT:
|
case AST_SCOPED_STMT:
|
||||||
|
|||||||
@@ -232,8 +232,11 @@ LLVMTypeRef llvm_func_type(GenContext *context, Type *type)
|
|||||||
|
|
||||||
LLVMTypeRef return_type = NULL;
|
LLVMTypeRef return_type = NULL;
|
||||||
|
|
||||||
Type *real_return_type = signature->failable ? type_anyerr : signature->rtype->type->canonical;
|
Type *rtype = signature->rtype->type;
|
||||||
ABIArgInfo *ret_arg_info = signature->failable ? signature->failable_abi_info : signature->ret_abi_info;
|
bool is_failable = rtype->type_kind == TYPE_FAILABLE;
|
||||||
|
if (is_failable) rtype = rtype->failable;
|
||||||
|
Type *real_return_type = is_failable ? type_anyerr : rtype;
|
||||||
|
ABIArgInfo *ret_arg_info = is_failable ? signature->failable_abi_info : signature->ret_abi_info;
|
||||||
|
|
||||||
ret_arg_info->param_index_end = 0;
|
ret_arg_info->param_index_end = 0;
|
||||||
ret_arg_info->param_index_start = 0;
|
ret_arg_info->param_index_start = 0;
|
||||||
@@ -276,9 +279,9 @@ LLVMTypeRef llvm_func_type(GenContext *context, Type *type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If it's failable and it's not void (meaning ret_abi_info will be NULL)
|
// If it's failable and it's not void (meaning ret_abi_info will be NULL)
|
||||||
if (signature->failable && signature->ret_abi_info)
|
if (is_failable && signature->ret_abi_info)
|
||||||
{
|
{
|
||||||
add_func_type_param(context, type_get_ptr(signature->rtype->type), signature->ret_abi_info, ¶ms);
|
add_func_type_param(context, type_get_ptr(rtype), signature->ret_abi_info, ¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add in all of the required arguments.
|
// Add in all of the required arguments.
|
||||||
@@ -310,6 +313,9 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
|
|||||||
{
|
{
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
// If this is reachable, then we're not doing the proper lowering.
|
||||||
|
UNREACHABLE
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_ANYERR:
|
case TYPE_ANYERR:
|
||||||
case TYPE_ERRTYPE:
|
case TYPE_ERRTYPE:
|
||||||
@@ -329,7 +335,6 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
|
|||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
return any_type->backend_type = LLVMVoidTypeInContext(c->context);
|
return any_type->backend_type = LLVMVoidTypeInContext(c->context);
|
||||||
case TYPE_F64:
|
case TYPE_F64:
|
||||||
case TYPE_FXX:
|
|
||||||
return any_type->backend_type = LLVMDoubleTypeInContext(c->context);
|
return any_type->backend_type = LLVMDoubleTypeInContext(c->context);
|
||||||
case TYPE_F16:
|
case TYPE_F16:
|
||||||
return any_type->backend_type = LLVMHalfTypeInContext(c->context);
|
return any_type->backend_type = LLVMHalfTypeInContext(c->context);
|
||||||
@@ -340,8 +345,6 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
|
|||||||
case ALL_SIGNED_INTS:
|
case ALL_SIGNED_INTS:
|
||||||
case ALL_UNSIGNED_INTS:
|
case ALL_UNSIGNED_INTS:
|
||||||
return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize);
|
return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize);
|
||||||
case TYPE_IXX:
|
|
||||||
return any_type->backend_type = LLVMIntTypeInContext(c->context, 32U);
|
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U);
|
return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U);
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
|
|||||||
@@ -7,16 +7,14 @@
|
|||||||
|
|
||||||
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind)
|
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind)
|
||||||
{
|
{
|
||||||
|
expr->ixx.i.high = 0;
|
||||||
if (type_kind_is_signed(kind))
|
if (type_kind_is_signed(kind))
|
||||||
{
|
{
|
||||||
bigint_init_signed(&expr->i, (int64_t)v);
|
if (v > (uint64_t)INT64_MAX) expr->ixx.i.high = UINT64_MAX;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bigint_init_unsigned(&expr->i, v);
|
|
||||||
}
|
}
|
||||||
|
expr->ixx.i.low = v;
|
||||||
|
expr->ixx.type = kind;
|
||||||
expr->const_kind = CONST_INTEGER;
|
expr->const_kind = CONST_INTEGER;
|
||||||
expr->int_type = kind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_const_set_bool(ExprConst *expr, bool b)
|
void expr_const_set_bool(ExprConst *expr, bool b)
|
||||||
@@ -27,8 +25,7 @@ void expr_const_set_bool(ExprConst *expr, bool b)
|
|||||||
|
|
||||||
void expr_const_set_null(ExprConst *expr)
|
void expr_const_set_null(ExprConst *expr)
|
||||||
{
|
{
|
||||||
expr->i.digit_count = 0;
|
expr->ixx = (Int) { .i = (Int128) { 0, 0 }, .type = type_iptr->canonical->type_kind };
|
||||||
expr->i.digit = 0;
|
|
||||||
expr->const_kind = CONST_POINTER;
|
expr->const_kind = CONST_POINTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,29 +49,6 @@ static inline bool compare_bool(bool left, bool right, BinaryOp op)
|
|||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool compare_ints(const BigInt *left, const BigInt *right, BinaryOp op)
|
|
||||||
{
|
|
||||||
CmpRes res = bigint_cmp(left, right);
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case BINARYOP_GE:
|
|
||||||
return res != CMP_LT;
|
|
||||||
case BINARYOP_LE:
|
|
||||||
return res != CMP_GT;
|
|
||||||
case BINARYOP_NE:
|
|
||||||
return res != CMP_EQ;
|
|
||||||
case BINARYOP_GT:
|
|
||||||
return res == CMP_GT;
|
|
||||||
case BINARYOP_LT:
|
|
||||||
return res == CMP_LT;
|
|
||||||
case BINARYOP_EQ:
|
|
||||||
return res == CMP_EQ;
|
|
||||||
default:
|
|
||||||
UNREACHABLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool compare_fps(Real left, Real right, BinaryOp op)
|
static inline bool compare_fps(Real left, Real right, BinaryOp op)
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
@@ -104,9 +78,9 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
|
|||||||
case CONST_BOOL:
|
case CONST_BOOL:
|
||||||
return compare_bool(left->b, right->b, op);
|
return compare_bool(left->b, right->b, op);
|
||||||
case CONST_INTEGER:
|
case CONST_INTEGER:
|
||||||
return compare_ints(&left->i, &right->i, op);
|
return int_comp(left->ixx, right->ixx, op);
|
||||||
case CONST_FLOAT:
|
case CONST_FLOAT:
|
||||||
return compare_fps(left->f, right->f, op);
|
return compare_fps(left->fxx.f, right->fxx.f, op);
|
||||||
case CONST_POINTER:
|
case CONST_POINTER:
|
||||||
return true;
|
return true;
|
||||||
case CONST_STRING:
|
case CONST_STRING:
|
||||||
@@ -190,29 +164,14 @@ bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind)
|
|||||||
{
|
{
|
||||||
switch (kind)
|
switch (kind)
|
||||||
{
|
{
|
||||||
case TYPE_I8:
|
case ALL_INTS:
|
||||||
return !bigint_fits_in_bits(&expr->i, 8, true);
|
return !int_fits(expr->ixx, kind);
|
||||||
case TYPE_I16:
|
|
||||||
return !bigint_fits_in_bits(&expr->i, 16, true);
|
|
||||||
case TYPE_I32:
|
|
||||||
return !bigint_fits_in_bits(&expr->i, 32, true);
|
|
||||||
case TYPE_I64:
|
|
||||||
return !bigint_fits_in_bits(&expr->i, 64, true);
|
|
||||||
case TYPE_U8:
|
|
||||||
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 8, false);
|
|
||||||
case TYPE_U16:
|
|
||||||
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 16, false);
|
|
||||||
case TYPE_U32:
|
|
||||||
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 32, false);
|
|
||||||
case TYPE_U64:
|
|
||||||
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 64, false);
|
|
||||||
case TYPE_F16:
|
case TYPE_F16:
|
||||||
return !bigint_fits_in_bits(&expr->i, 17, false);
|
REMINDER("Check f16 narrowing");
|
||||||
case TYPE_IXX:
|
FALLTHROUGH;
|
||||||
case TYPE_F32:
|
case TYPE_F32:
|
||||||
case TYPE_F64:
|
case TYPE_F64:
|
||||||
case TYPE_F128:
|
case TYPE_F128:
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
@@ -220,10 +179,6 @@ bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expr_const_int_overflowed(const ExprConst *expr)
|
|
||||||
{
|
|
||||||
return expr_const_will_overflow(expr, expr->int_type);
|
|
||||||
}
|
|
||||||
const char *expr_const_to_error_string(const ExprConst *expr)
|
const char *expr_const_to_error_string(const ExprConst *expr)
|
||||||
{
|
{
|
||||||
char *buff = NULL;
|
char *buff = NULL;
|
||||||
@@ -234,12 +189,12 @@ const char *expr_const_to_error_string(const ExprConst *expr)
|
|||||||
case CONST_BOOL:
|
case CONST_BOOL:
|
||||||
return expr->b ? "true" : "false";
|
return expr->b ? "true" : "false";
|
||||||
case CONST_INTEGER:
|
case CONST_INTEGER:
|
||||||
return bigint_to_error_string(&expr->i, 10);
|
return int_to_str(expr->ixx, 10);
|
||||||
case CONST_FLOAT:
|
case CONST_FLOAT:
|
||||||
#if LONG_DOUBLE
|
#if LONG_DOUBLE
|
||||||
asprintf(&buff, "%Lg", expr->f);
|
asprintf(&buff, "%Lg", expr->fxx.f);
|
||||||
#else
|
#else
|
||||||
asprintf(&buff, "%g", expr->f);
|
asprintf(&buff, "%g", expr->fxx.f);
|
||||||
#endif
|
#endif
|
||||||
return buff;
|
return buff;
|
||||||
case CONST_STRING:
|
case CONST_STRING:
|
||||||
@@ -265,16 +220,16 @@ void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind)
|
|||||||
switch (kind)
|
switch (kind)
|
||||||
{
|
{
|
||||||
case TYPE_F32:
|
case TYPE_F32:
|
||||||
expr->f = (float)d;
|
expr->fxx = (Float) { (float)d, TYPE_F32 };
|
||||||
break;
|
break;
|
||||||
case TYPE_F64:
|
case TYPE_F64:
|
||||||
expr->f = (double)d;
|
expr->fxx = (Float) { (double)d, TYPE_F64 };
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
expr->f = d;
|
expr->fxx = (Float) { d, kind };
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
expr->const_kind = CONST_FLOAT;
|
expr->const_kind = CONST_FLOAT;
|
||||||
expr->float_type = kind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteSize expr_const_list_size(const ConstInitializer *list)
|
ByteSize expr_const_list_size(const ConstInitializer *list)
|
||||||
|
|||||||
@@ -410,8 +410,8 @@ static Expr *parse_post_unary(Context *context, Expr *left)
|
|||||||
{
|
{
|
||||||
assert(expr_ok(left));
|
assert(expr_ok(left));
|
||||||
Expr *unary = EXPR_NEW_TOKEN(EXPR_POST_UNARY, context->tok);
|
Expr *unary = EXPR_NEW_TOKEN(EXPR_POST_UNARY, context->tok);
|
||||||
unary->post_expr.expr = left;
|
unary->unary_expr.expr = left;
|
||||||
unary->post_expr.operator = post_unaryop_from_token(context->tok.type);
|
unary->unary_expr.operator = unaryop_from_token(context->tok.type);
|
||||||
unary->span.loc = left->span.loc;
|
unary->span.loc = left->span.loc;
|
||||||
advance(context);
|
advance(context);
|
||||||
return unary;
|
return unary;
|
||||||
@@ -666,7 +666,7 @@ static Expr *parse_subscript_expr(Context *context, Expr *left)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
expr_set_type(index, type_uint);
|
index->type = type_uint;
|
||||||
index->resolve_status = RESOLVE_DONE;
|
index->resolve_status = RESOLVE_DONE;
|
||||||
expr_const_set_int(&index->const_expr, 0, type_uint->type_kind);
|
expr_const_set_int(&index->const_expr, 0, type_uint->type_kind);
|
||||||
}
|
}
|
||||||
@@ -759,22 +759,20 @@ static Expr *parse_ct_call(Context *context, Expr *left)
|
|||||||
SEMA_TOKEN_ERROR(context->tok, "Expected an integer index.");
|
SEMA_TOKEN_ERROR(context->tok, "Expected an integer index.");
|
||||||
return poisoned_expr;
|
return poisoned_expr;
|
||||||
}
|
}
|
||||||
BigInt *value = &int_expr->const_expr.i;
|
Int value = int_expr->const_expr.ixx;
|
||||||
BigInt limit;
|
if (!int_fits(value, TYPE_I64))
|
||||||
bigint_init_unsigned(&limit, MAX_ARRAYINDEX);
|
|
||||||
if (bigint_cmp(value, &limit) == CMP_GT)
|
|
||||||
{
|
{
|
||||||
SEMA_ERROR(int_expr, "Array index out of range.");
|
SEMA_ERROR(int_expr, "Array index out of range.");
|
||||||
return poisoned_expr;
|
return poisoned_expr;
|
||||||
}
|
}
|
||||||
if (bigint_cmp_zero(value) == CMP_LT)
|
if (int_is_neg(value))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(int_expr, "Array index must be zero or greater.");
|
SEMA_ERROR(int_expr, "Array index must be zero or greater.");
|
||||||
return poisoned_expr;
|
return poisoned_expr;
|
||||||
}
|
}
|
||||||
TRY_CONSUME_OR(TOKEN_RBRACKET, "Expected a ']' after the number.", poisoned_expr);
|
TRY_CONSUME_OR(TOKEN_RBRACKET, "Expected a ']' after the number.", poisoned_expr);
|
||||||
flat_element.array = true;
|
flat_element.array = true;
|
||||||
flat_element.index = (ArrayIndex)bigint_as_unsigned(value);
|
flat_element.index = value.i.low;
|
||||||
}
|
}
|
||||||
else if (try_consume(context, TOKEN_DOT))
|
else if (try_consume(context, TOKEN_DOT))
|
||||||
{
|
{
|
||||||
@@ -922,6 +920,18 @@ static Expr *parse_placeholder(Context *context, Expr *left)
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_num_type(const char *string, const char *end)
|
||||||
|
{
|
||||||
|
REMINDER("Limit num type reader");
|
||||||
|
int i = 0;
|
||||||
|
while (string < end)
|
||||||
|
{
|
||||||
|
i *= 10;
|
||||||
|
i += *(string++) - '0';
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
static Expr *parse_integer(Context *context, Expr *left)
|
static Expr *parse_integer(Context *context, Expr *left)
|
||||||
{
|
{
|
||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
@@ -929,73 +939,178 @@ static Expr *parse_integer(Context *context, Expr *left)
|
|||||||
const char *string = TOKSTR(context->tok);
|
const char *string = TOKSTR(context->tok);
|
||||||
const char *end = string + TOKLEN(context->tok);
|
const char *end = string + TOKLEN(context->tok);
|
||||||
|
|
||||||
BigInt *i = &expr_int->const_expr.i;
|
Int128 i = { 0, 0 };
|
||||||
bigint_init_unsigned(i, 0);
|
bool is_unsigned = false;
|
||||||
BigInt diff;
|
uint64_t type_bits = 0;
|
||||||
bigint_init_unsigned(&diff, 0);
|
int hex_characters = 0;
|
||||||
BigInt ten;
|
int oct_characters = 0;
|
||||||
bigint_init_unsigned(&ten, 10);
|
int binary_characters = 0;
|
||||||
BigInt res;
|
bool wrapped = false;
|
||||||
|
uint64_t max;
|
||||||
switch (TOKLEN(context->tok) > 2 ? string[1] : '0')
|
switch (TOKLEN(context->tok) > 2 ? string[1] : '0')
|
||||||
{
|
{
|
||||||
case 'x':
|
case 'x':
|
||||||
string += 2;
|
string += 2;
|
||||||
|
is_unsigned = true;
|
||||||
|
max = UINT64_MAX >> 4;
|
||||||
while (string < end)
|
while (string < end)
|
||||||
{
|
{
|
||||||
char c = *(string++);
|
char c = *(string++);
|
||||||
|
if (c == 'u' || c == 'U')
|
||||||
|
{
|
||||||
|
type_bits = read_num_type(string, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == 'i' || c == 'I')
|
||||||
|
{
|
||||||
|
is_unsigned = false;
|
||||||
|
type_bits = read_num_type(string, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (c == '_') continue;
|
if (c == '_') continue;
|
||||||
bigint_shl_int(&res, i, 4);
|
if (i.high > max) wrapped = true;
|
||||||
if (c < 'A')
|
i = i128_shl64(i, 4);
|
||||||
{
|
i = i128_add64(i, hex_nibble(c));
|
||||||
bigint_init_unsigned(&diff, c - '0');
|
hex_characters++;
|
||||||
}
|
|
||||||
else if (c < 'a')
|
|
||||||
{
|
|
||||||
bigint_init_unsigned(&diff, c - 'A' + 10);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bigint_init_unsigned(&diff, c - 'a' + 10);
|
|
||||||
}
|
|
||||||
bigint_add(i, &res, &diff);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
string += 2;
|
string += 2;
|
||||||
|
is_unsigned = true;
|
||||||
|
max = UINT64_MAX >> 3;
|
||||||
while (string < end)
|
while (string < end)
|
||||||
{
|
{
|
||||||
char c = *(string++);
|
char c = *(string++);
|
||||||
|
if (c == 'i' || c == 'I')
|
||||||
|
{
|
||||||
|
is_unsigned = false;
|
||||||
|
type_bits = read_num_type(string, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == 'u' || c == 'U')
|
||||||
|
{
|
||||||
|
type_bits = read_num_type(string, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (c == '_') continue;
|
if (c == '_') continue;
|
||||||
bigint_shl_int(&res, i, 4);
|
if (i.high > max) wrapped = true;
|
||||||
bigint_init_unsigned(&diff, c - '0');
|
i = i128_shl64(i, 3);
|
||||||
bigint_add(i, &res, &diff);
|
i = i128_add64(i, c - '0');
|
||||||
|
oct_characters++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
string += 2;
|
string += 2;
|
||||||
|
max = UINT64_MAX >> 1;
|
||||||
while (string < end)
|
while (string < end)
|
||||||
{
|
{
|
||||||
char c = *(string++);
|
char c = *(string++);
|
||||||
if (c == '_') continue;
|
if (c == '_') continue;
|
||||||
bigint_shl_int(&res, i, 1);
|
binary_characters++;
|
||||||
bigint_init_unsigned(&diff, c - '0');
|
if (i.high > max) wrapped = true;
|
||||||
bigint_add(i, &res, &diff);
|
i = i128_shl64(i, 1);
|
||||||
|
i = i128_add64(i, c - '0');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
while (string < end)
|
while (string < end)
|
||||||
{
|
{
|
||||||
char c = *(string++);
|
char c = *(string++);
|
||||||
|
if (c == 'i' || c == 'I')
|
||||||
|
{
|
||||||
|
is_unsigned = false;
|
||||||
|
type_bits = read_num_type(string, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == 'u' || c == 'U')
|
||||||
|
{
|
||||||
|
is_unsigned = true;
|
||||||
|
type_bits = read_num_type(string, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (c == '_') continue;
|
if (c == '_') continue;
|
||||||
bigint_mul(&res, i, &ten);
|
uint64_t old_top = i.high;
|
||||||
bigint_init_unsigned(&diff, c - '0');
|
i = i128_mult64(i, 10);
|
||||||
bigint_add(i, &res, &diff);
|
i = i128_add64(i, c - '0');
|
||||||
|
if (!wrapped && old_top > i.high) wrapped = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (wrapped)
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "Integer size exceeded 128 bits, max 128 bits are supported.");
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
expr_int->const_expr.const_kind = CONST_INTEGER;
|
expr_int->const_expr.const_kind = CONST_INTEGER;
|
||||||
expr_int->const_expr.int_type = TYPE_IXX;
|
Type *type = is_unsigned ? type_cuint() : type_cint();
|
||||||
expr_set_type(expr_int, type_compint);
|
expr_int->const_expr.narrowable = !type_bits;
|
||||||
|
if (type_bits)
|
||||||
|
{
|
||||||
|
if (!is_power_of_two(type_bits) || type_bits > 128)
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "Integer width should be 8, 16, 32, 64 or 128.");
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (hex_characters)
|
||||||
|
{
|
||||||
|
type_bits = 4 * hex_characters;
|
||||||
|
if (type_bits > 128)
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "%d hex digits indicates a bit width over 128, which is not supported.", hex_characters);
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oct_characters)
|
||||||
|
{
|
||||||
|
type_bits = 3 * oct_characters;
|
||||||
|
if (type_bits > 128)
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "%d octal digits indicates a bit width over 128, which is not supported.", oct_characters);
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (binary_characters)
|
||||||
|
{
|
||||||
|
type_bits = binary_characters;
|
||||||
|
if (type_bits > 128)
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "%d binary digits indicates a bit width over 128, which is not supported.", binary_characters);
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type_bits && !is_power_of_two(type_bits)) type_bits = next_highest_power_of_2(type_bits);
|
||||||
|
}
|
||||||
|
if (!type_bits)
|
||||||
|
{
|
||||||
|
type_bits = type_size(type) * 8;
|
||||||
|
}
|
||||||
|
if (type_bits)
|
||||||
|
{
|
||||||
|
type = is_unsigned ? type_int_unsigned_by_bitsize(type_bits) : type_int_signed_by_bitsize(type_bits);
|
||||||
|
}
|
||||||
|
expr_int->const_expr.ixx = (Int) { i, type->type_kind };
|
||||||
|
if (!int_fits(expr_int->const_expr.ixx, type->type_kind))
|
||||||
|
{
|
||||||
|
int radix = 10;
|
||||||
|
if (hex_characters) radix = 16;
|
||||||
|
if (oct_characters) radix = 8;
|
||||||
|
if (binary_characters) radix = 2;
|
||||||
|
if (type_bits)
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "'%s' does not fit in a '%c%d' literal.",
|
||||||
|
i128_to_string(i, radix, true), is_unsigned ? 'u' : 'i', type_bits);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "'%s' does not fit in an %s literal.",
|
||||||
|
i128_to_string(i, radix, true), is_unsigned ? "unsigned int" : "int");
|
||||||
|
}
|
||||||
|
return poisoned_expr;
|
||||||
|
}
|
||||||
|
expr_int->type = type;
|
||||||
advance(context);
|
advance(context);
|
||||||
return expr_int;
|
return expr_int;
|
||||||
}
|
}
|
||||||
@@ -1100,7 +1215,8 @@ static Expr *parse_bytes_expr(Context *context, Expr *left)
|
|||||||
expr_bytes->const_expr.bytes.ptr = data;
|
expr_bytes->const_expr.bytes.ptr = data;
|
||||||
expr_bytes->const_expr.bytes.len = len;
|
expr_bytes->const_expr.bytes.len = len;
|
||||||
expr_bytes->const_expr.const_kind = CONST_BYTES;
|
expr_bytes->const_expr.const_kind = CONST_BYTES;
|
||||||
expr_set_type(expr_bytes, type_get_array(type_char, len));
|
Type *type = type_get_array(type_char, len);
|
||||||
|
expr_bytes->type = type;
|
||||||
assert(data + len == data_current);
|
assert(data + len == data_current);
|
||||||
return expr_bytes;
|
return expr_bytes;
|
||||||
}
|
}
|
||||||
@@ -1109,24 +1225,25 @@ static Expr *parse_char_lit(Context *context, Expr *left)
|
|||||||
{
|
{
|
||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
|
expr_int->const_expr.narrowable = true;
|
||||||
TokenData *data = tokendata_from_id(context->tok.id);
|
TokenData *data = tokendata_from_id(context->tok.id);
|
||||||
switch (data->width)
|
switch (data->width)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u8, TYPE_IXX);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u8, TYPE_U8);
|
||||||
expr_set_type(expr_int, type_compint);
|
expr_int->type = type_char;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u16, TYPE_IXX);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u16, TYPE_U16);
|
||||||
expr_set_type(expr_int, type_compint);
|
expr_int->type = type_ushort;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u32, TYPE_IXX);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u32, TYPE_U32);
|
||||||
expr_set_type(expr_int, type_compint);
|
expr_int->type = type_uint;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u64, TYPE_U64);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u64, TYPE_U64);
|
||||||
expr_set_type(expr_int, type_compint);
|
expr_int->type = type_ulong;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
@@ -1141,10 +1258,26 @@ static Expr *parse_double(Context *context, Expr *left)
|
|||||||
{
|
{
|
||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
number->const_expr.f = TOKREAL(context->tok.id);
|
number->const_expr.fxx = TOKREAL(context->tok.id);
|
||||||
expr_set_type(number, type_compfloat);
|
switch (number->const_expr.fxx.type)
|
||||||
number->const_expr.float_type = TYPE_FXX;
|
{
|
||||||
|
case TYPE_F128:
|
||||||
|
number->type = type_quad;
|
||||||
|
break;
|
||||||
|
case TYPE_F64:
|
||||||
|
number->type = type_double;
|
||||||
|
break;
|
||||||
|
case TYPE_F32:
|
||||||
|
number->type = type_float;
|
||||||
|
break;
|
||||||
|
case TYPE_F16:
|
||||||
|
number->type = type_half;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
number->const_expr.const_kind = CONST_FLOAT;
|
number->const_expr.const_kind = CONST_FLOAT;
|
||||||
|
number->const_expr.narrowable = true;
|
||||||
advance(context);
|
advance(context);
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
@@ -1226,7 +1359,7 @@ static Expr *parse_string_literal(Context *context, Expr *left)
|
|||||||
{
|
{
|
||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
expr_set_type(expr_string, type_compstr);
|
expr_string->type = type_compstr;
|
||||||
|
|
||||||
TokenData *data = TOKDATA(context->tok);
|
TokenData *data = TOKDATA(context->tok);
|
||||||
const char *str = data->string;
|
const char *str = data->string;
|
||||||
@@ -1255,7 +1388,7 @@ static Expr *parse_string_literal(Context *context, Expr *left)
|
|||||||
assert(str);
|
assert(str);
|
||||||
expr_string->const_expr.string.chars = str;
|
expr_string->const_expr.string.chars = str;
|
||||||
expr_string->const_expr.string.len = (uint32_t)len;
|
expr_string->const_expr.string.len = (uint32_t)len;
|
||||||
expr_set_type(expr_string, type_compstr);
|
expr_string->type = type_compstr;
|
||||||
expr_string->const_expr.const_kind = CONST_STRING;
|
expr_string->const_expr.const_kind = CONST_STRING;
|
||||||
return expr_string;
|
return expr_string;
|
||||||
}
|
}
|
||||||
@@ -1265,7 +1398,7 @@ static Expr *parse_bool(Context *context, Expr *left)
|
|||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .const_kind = CONST_BOOL };
|
number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .const_kind = CONST_BOOL };
|
||||||
expr_set_type(number, type_bool);
|
number->type = type_bool;
|
||||||
advance(context);
|
advance(context);
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
@@ -1275,7 +1408,7 @@ static Expr *parse_null(Context *context, Expr *left)
|
|||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
number->const_expr.const_kind = CONST_POINTER;
|
number->const_expr.const_kind = CONST_POINTER;
|
||||||
expr_set_type(number, type_voidptr);
|
number->type = type_voidptr;
|
||||||
advance(context);
|
advance(context);
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
@@ -1309,10 +1442,11 @@ Expr *parse_type_expression_with_path(Context *context, Path *path)
|
|||||||
advance_and_verify(context, TOKEN_TYPE_IDENT);
|
advance_and_verify(context, TOKEN_TYPE_IDENT);
|
||||||
RANGE_EXTEND_PREV(type);
|
RANGE_EXTEND_PREV(type);
|
||||||
ASSIGN_TYPE_ELSE(type, parse_type_with_base(context, type), poisoned_expr);
|
ASSIGN_TYPE_ELSE(type, parse_type_with_base(context, type), poisoned_expr);
|
||||||
|
type->failable = try_consume(context, TOKEN_BANG);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ASSIGN_TYPE_ELSE(type, parse_type(context), poisoned_expr);
|
ASSIGN_TYPE_ELSE(type, parse_failable_type(context), poisoned_expr);
|
||||||
}
|
}
|
||||||
if (!type->virtual_type && TOKEN_IS(TOKEN_LBRACE))
|
if (!type->virtual_type && TOKEN_IS(TOKEN_LBRACE))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -737,6 +737,23 @@ TypeInfo *parse_type(Context *context)
|
|||||||
return parse_type_with_base(context, base);
|
return parse_type_with_base(context, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeInfo *parse_failable_type(Context *context)
|
||||||
|
{
|
||||||
|
ASSIGN_TYPE_ELSE(TypeInfo *info, parse_base_type(context), poisoned_type_info);
|
||||||
|
ASSIGN_TYPE_ELSE(info, parse_type_with_base(context, info), poisoned_type_info);
|
||||||
|
if (try_consume(context, TOKEN_BANG))
|
||||||
|
{
|
||||||
|
assert(!info->failable);
|
||||||
|
info->failable = true;
|
||||||
|
if (info->resolve_status == RESOLVE_DONE)
|
||||||
|
{
|
||||||
|
info->type = type_get_failable(info->type);
|
||||||
|
}
|
||||||
|
RANGE_EXTEND_PREV(info);
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark --- Decl parsing
|
#pragma mark --- Decl parsing
|
||||||
|
|
||||||
@@ -754,13 +771,13 @@ Decl *parse_decl_after_type(Context *context, TypeInfo *type)
|
|||||||
return poisoned_decl;
|
return poisoned_decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EXPECT_IDENT_FOR_OR("variable name", poisoned_decl);
|
EXPECT_IDENT_FOR_OR("variable name", poisoned_decl);
|
||||||
|
|
||||||
TokenId name = context->tok.id;
|
TokenId name = context->tok.id;
|
||||||
advance(context);
|
advance(context);
|
||||||
|
|
||||||
Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, VISIBLE_LOCAL);
|
Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, VISIBLE_LOCAL);
|
||||||
|
if (!parse_attributes(context, &decl->attributes)) return poisoned_decl;
|
||||||
if (TOKEN_IS(TOKEN_EQ))
|
if (TOKEN_IS(TOKEN_EQ))
|
||||||
{
|
{
|
||||||
if (!decl)
|
if (!decl)
|
||||||
@@ -789,17 +806,14 @@ Decl *parse_decl(Context *context)
|
|||||||
|
|
||||||
bool is_static = try_consume(context, TOKEN_STATIC);
|
bool is_static = try_consume(context, TOKEN_STATIC);
|
||||||
|
|
||||||
ASSIGN_TYPE_ELSE(TypeInfo *type, parse_type(context), poisoned_decl);
|
ASSIGN_TYPE_ELSE(TypeInfo *type, parse_failable_type(context), poisoned_decl);
|
||||||
|
|
||||||
bool failable = try_consume(context, TOKEN_BANG);
|
|
||||||
|
|
||||||
ASSIGN_DECL_ELSE(Decl *decl, parse_decl_after_type(context, type), poisoned_decl);
|
ASSIGN_DECL_ELSE(Decl *decl, parse_decl_after_type(context, type), poisoned_decl);
|
||||||
if (failable && decl->var.unwrap)
|
if (type->failable && decl->var.unwrap)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(decl, "You cannot use unwrap with a failable variable.");
|
SEMA_ERROR(decl, "You cannot use unwrap with a failable variable.");
|
||||||
return poisoned_decl;
|
return poisoned_decl;
|
||||||
}
|
}
|
||||||
decl->var.failable = failable;
|
|
||||||
decl->var.is_static = is_static;
|
decl->var.is_static = is_static;
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
@@ -1004,14 +1018,10 @@ bool parse_attributes(Context *context, Attr ***attributes_ref)
|
|||||||
*/
|
*/
|
||||||
static inline Decl *parse_global_declaration(Context *context, Visibility visibility)
|
static inline Decl *parse_global_declaration(Context *context, Visibility visibility)
|
||||||
{
|
{
|
||||||
ASSIGN_TYPE_ELSE(TypeInfo *type, parse_type(context), poisoned_decl);
|
ASSIGN_TYPE_ELSE(TypeInfo *type, parse_failable_type(context), poisoned_decl);
|
||||||
|
|
||||||
bool failable = try_consume(context, TOKEN_BANG);
|
|
||||||
|
|
||||||
Decl *decl = decl_new_var(context->tok.id, type, VARDECL_GLOBAL, visibility);
|
Decl *decl = decl_new_var(context->tok.id, type, VARDECL_GLOBAL, visibility);
|
||||||
|
|
||||||
decl->var.failable = failable;
|
|
||||||
|
|
||||||
if (TOKEN_IS(TOKEN_CONST_IDENT))
|
if (TOKEN_IS(TOKEN_CONST_IDENT))
|
||||||
{
|
{
|
||||||
SEMA_TOKEN_ERROR(context->tok, "This looks like a constant variable, did you forget 'const'?");
|
SEMA_TOKEN_ERROR(context->tok, "This looks like a constant variable, did you forget 'const'?");
|
||||||
@@ -1533,12 +1543,8 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility)
|
|||||||
decl->span.loc = start;
|
decl->span.loc = start;
|
||||||
decl->typedef_decl.is_func = true;
|
decl->typedef_decl.is_func = true;
|
||||||
decl->typedef_decl.is_distinct = distinct;
|
decl->typedef_decl.is_distinct = distinct;
|
||||||
ASSIGN_TYPE_ELSE(TypeInfo *type_info, parse_type(context), poisoned_decl);
|
ASSIGN_TYPE_ELSE(TypeInfo *type_info, parse_failable_type(context), poisoned_decl);
|
||||||
decl->typedef_decl.function_signature.rtype = type_info;
|
decl->typedef_decl.function_signature.rtype = type_info;
|
||||||
if (try_consume(context, TOKEN_BANG))
|
|
||||||
{
|
|
||||||
decl->typedef_decl.function_signature.failable = true;
|
|
||||||
}
|
|
||||||
if (!parse_parameter_list(context, decl->visibility, &(decl->typedef_decl.function_signature), true))
|
if (!parse_parameter_list(context, decl->visibility, &(decl->typedef_decl.function_signature), true))
|
||||||
{
|
{
|
||||||
return poisoned_decl;
|
return poisoned_decl;
|
||||||
@@ -1684,11 +1690,12 @@ static inline Decl *parse_define(Context *context, Visibility visibility)
|
|||||||
* func_header ::= type '!'? (type '.')? IDENT
|
* func_header ::= type '!'? (type '.')? IDENT
|
||||||
* macro_header ::= (type '!'?)? (type '.')? IDENT
|
* macro_header ::= (type '!'?)? (type '.')? IDENT
|
||||||
*/
|
*/
|
||||||
static inline bool parse_func_macro_header(Context *context, bool rtype_is_optional, TypeInfo **rtype_ref, bool *failable_ref, TypeInfo **method_type_ref, TokenId *name_ref)
|
static inline bool
|
||||||
|
parse_func_macro_header(Context *context, bool rtype_is_optional, TypeInfo **rtype_ref, TypeInfo **method_type_ref,
|
||||||
|
TokenId *name_ref)
|
||||||
{
|
{
|
||||||
TypeInfo *rtype = NULL;
|
TypeInfo *rtype = NULL;
|
||||||
TypeInfo *method_type = NULL;
|
TypeInfo *method_type = NULL;
|
||||||
bool failable = false;
|
|
||||||
|
|
||||||
// 1. We have a macro with just a name, if so, then we set the name and we're done.
|
// 1. We have a macro with just a name, if so, then we set the name and we're done.
|
||||||
if (rtype_is_optional && !context_next_is_type_and_not_ident(context))
|
if (rtype_is_optional && !context_next_is_type_and_not_ident(context))
|
||||||
@@ -1697,10 +1704,7 @@ static inline bool parse_func_macro_header(Context *context, bool rtype_is_optio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Now we must have a type - either that is the return type or the method type.
|
// 2. Now we must have a type - either that is the return type or the method type.
|
||||||
ASSIGN_TYPE_ELSE(rtype, parse_type(context), false);
|
ASSIGN_TYPE_ELSE(rtype, parse_failable_type(context), false);
|
||||||
|
|
||||||
// 3. We possibly have a failable return at this point.
|
|
||||||
failable = try_consume(context, TOKEN_BANG);
|
|
||||||
|
|
||||||
// 4. We might have a type here, if so then we read it.
|
// 4. We might have a type here, if so then we read it.
|
||||||
if (!TOKEN_IS(TOKEN_DOT) && context_next_is_type_and_not_ident(context))
|
if (!TOKEN_IS(TOKEN_DOT) && context_next_is_type_and_not_ident(context))
|
||||||
@@ -1715,7 +1719,7 @@ static inline bool parse_func_macro_header(Context *context, bool rtype_is_optio
|
|||||||
if (!method_type)
|
if (!method_type)
|
||||||
{
|
{
|
||||||
// 5b. If the rtype is not optional or the return type was a failable, then this is an error.
|
// 5b. If the rtype is not optional or the return type was a failable, then this is an error.
|
||||||
if (!rtype_is_optional || failable)
|
if (!rtype_is_optional || rtype->failable)
|
||||||
{
|
{
|
||||||
SEMA_TOKID_ERROR(context->prev_tok,
|
SEMA_TOKID_ERROR(context->prev_tok,
|
||||||
"This looks like you are declaring a method without a return type?");
|
"This looks like you are declaring a method without a return type?");
|
||||||
@@ -1733,7 +1737,6 @@ static inline bool parse_func_macro_header(Context *context, bool rtype_is_optio
|
|||||||
}
|
}
|
||||||
RESULT:
|
RESULT:
|
||||||
TRY_CONSUME_OR(TOKEN_IDENT, "Expected a name here.", false);
|
TRY_CONSUME_OR(TOKEN_IDENT, "Expected a name here.", false);
|
||||||
*failable_ref = failable;
|
|
||||||
*name_ref = context->prev_tok;
|
*name_ref = context->prev_tok;
|
||||||
*rtype_ref = rtype;
|
*rtype_ref = rtype;
|
||||||
*method_type_ref = method_type;
|
*method_type_ref = method_type;
|
||||||
@@ -1752,11 +1755,9 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil
|
|||||||
Decl *decl = decl_new(kind, context->tok.id, visibility);
|
Decl *decl = decl_new(kind, context->tok.id, visibility);
|
||||||
TypeInfo **rtype_ref = &decl->macro_decl.rtype;
|
TypeInfo **rtype_ref = &decl->macro_decl.rtype;
|
||||||
TypeInfo **method_type_ref = &decl->macro_decl.type_parent;
|
TypeInfo **method_type_ref = &decl->macro_decl.type_parent;
|
||||||
bool failable;
|
|
||||||
TokenId name;
|
TokenId name;
|
||||||
if (!parse_func_macro_header(context, true, rtype_ref, &failable, method_type_ref, &name)) return poisoned_decl;
|
if (!parse_func_macro_header(context, true, rtype_ref, method_type_ref, &name)) return poisoned_decl;
|
||||||
|
|
||||||
decl->macro_decl.failable = failable;
|
|
||||||
decl->name = TOKSTR(name);
|
decl->name = TOKSTR(name);
|
||||||
decl->name_token = name;
|
decl->name_token = name;
|
||||||
|
|
||||||
@@ -1965,10 +1966,8 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit
|
|||||||
advance_and_verify(context, TOKEN_FUNC);
|
advance_and_verify(context, TOKEN_FUNC);
|
||||||
TypeInfo **rtype_ref = &func->func_decl.function_signature.rtype;
|
TypeInfo **rtype_ref = &func->func_decl.function_signature.rtype;
|
||||||
TypeInfo **method_type_ref = &func->func_decl.type_parent;
|
TypeInfo **method_type_ref = &func->func_decl.type_parent;
|
||||||
bool failable;
|
|
||||||
TokenId name;
|
TokenId name;
|
||||||
if (!parse_func_macro_header(context, false, rtype_ref, &failable, method_type_ref, &name)) return poisoned_decl;
|
if (!parse_func_macro_header(context, false, rtype_ref, method_type_ref, &name)) return poisoned_decl;
|
||||||
func->func_decl.function_signature.failable = failable;
|
|
||||||
func->name = TOKSTR(name);
|
func->name = TOKSTR(name);
|
||||||
func->name_token = name;
|
func->name_token = name;
|
||||||
RANGE_EXTEND_PREV(func);
|
RANGE_EXTEND_PREV(func);
|
||||||
@@ -2396,4 +2395,5 @@ Decl *parse_top_level_statement(Context *context)
|
|||||||
assert(decl);
|
assert(decl);
|
||||||
decl->docs = docs;
|
decl->docs = docs;
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -439,9 +439,8 @@ static inline bool parse_foreach_var(Context *context, Ast *foreach)
|
|||||||
// If we don't get foreach (foo ... or foreach (*foo ... then a type is expected.
|
// If we don't get foreach (foo ... or foreach (*foo ... then a type is expected.
|
||||||
if (!TOKEN_IS(TOKEN_IDENT) && !TOKEN_IS(TOKEN_AMP))
|
if (!TOKEN_IS(TOKEN_IDENT) && !TOKEN_IS(TOKEN_AMP))
|
||||||
{
|
{
|
||||||
ASSIGN_TYPE_ELSE(type, parse_type(context), false);
|
ASSIGN_TYPE_ELSE(type, parse_failable_type(context), false);
|
||||||
|
|
||||||
failable = try_consume(context, TOKEN_BANG);
|
|
||||||
// Add the failable to the type for nicer error reporting.
|
// Add the failable to the type for nicer error reporting.
|
||||||
RANGE_EXTEND_PREV(type);
|
RANGE_EXTEND_PREV(type);
|
||||||
}
|
}
|
||||||
@@ -460,7 +459,6 @@ static inline bool parse_foreach_var(Context *context, Ast *foreach)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Decl *var = decl_new_var(context->prev_tok, type, VARDECL_LOCAL, VISIBLE_LOCAL);
|
Decl *var = decl_new_var(context->prev_tok, type, VARDECL_LOCAL, VISIBLE_LOCAL);
|
||||||
var->var.failable = failable;
|
|
||||||
foreach->foreach_stmt.variable = var;
|
foreach->foreach_stmt.variable = var;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -586,14 +584,13 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context)
|
|||||||
// If so we need to unwrap this.
|
// If so we need to unwrap this.
|
||||||
if (expr->expr_kind == EXPR_FAILABLE && expr->failable_expr->expr_kind == EXPR_TYPEINFO)
|
if (expr->expr_kind == EXPR_FAILABLE && expr->failable_expr->expr_kind == EXPR_TYPEINFO)
|
||||||
{
|
{
|
||||||
failable = true;
|
UNREACHABLE
|
||||||
expr_replace(expr, expr->failable_expr);
|
expr_replace(expr, expr->failable_expr);
|
||||||
}
|
}
|
||||||
if (expr->expr_kind == EXPR_TYPEINFO)
|
if (expr->expr_kind == EXPR_TYPEINFO)
|
||||||
{
|
{
|
||||||
ast->ast_kind = AST_DECLARE_STMT;
|
ast->ast_kind = AST_DECLARE_STMT;
|
||||||
ASSIGN_DECL_ELSE(ast->declare_stmt, parse_decl_after_type(context, expr->type_expr), poisoned_ast);
|
ASSIGN_DECL_ELSE(ast->declare_stmt, parse_decl_after_type(context, expr->type_expr), poisoned_ast);
|
||||||
ast->declare_stmt->var.failable = failable;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -612,7 +609,7 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context)
|
|||||||
*/
|
*/
|
||||||
static inline Ast *parse_var_stmt(Context *context)
|
static inline Ast *parse_var_stmt(Context *context)
|
||||||
{
|
{
|
||||||
Ast *ast = AST_NEW_TOKEN(AST_DEFINE_STMT, context->tok);
|
Ast *ast = AST_NEW_TOKEN(AST_VAR_STMT, context->tok);
|
||||||
TokenId start = context->tok.id;
|
TokenId start = context->tok.id;
|
||||||
advance_and_verify(context, TOKEN_VAR);
|
advance_and_verify(context, TOKEN_VAR);
|
||||||
Decl *decl;
|
Decl *decl;
|
||||||
@@ -631,7 +628,7 @@ static inline Ast *parse_var_stmt(Context *context)
|
|||||||
advance(context);
|
advance(context);
|
||||||
if (try_consume(context, TOKEN_EQ))
|
if (try_consume(context, TOKEN_EQ))
|
||||||
{
|
{
|
||||||
ASSIGN_TYPE_ELSE(decl->var.type_info, parse_type(context), poisoned_ast);
|
ASSIGN_EXPR_ELSE(decl->var.init_expr, parse_expr(context), poisoned_ast);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ Expr *parse_expr(Context *context);
|
|||||||
bool consume_ident(Context *context, const char* name);
|
bool consume_ident(Context *context, const char* name);
|
||||||
Expr *parse_try_expr_after_try(Context *context, bool is_try);
|
Expr *parse_try_expr_after_try(Context *context, bool is_try);
|
||||||
TypeInfo *parse_type(Context *context);
|
TypeInfo *parse_type(Context *context);
|
||||||
|
TypeInfo *parse_failable_type(Context *context);
|
||||||
TypeInfo *parse_type_with_base(Context *context, TypeInfo *type_info);
|
TypeInfo *parse_type_with_base(Context *context, TypeInfo *type_info);
|
||||||
Expr* parse_constant_expr(Context *context);
|
Expr* parse_constant_expr(Context *context);
|
||||||
Expr *parse_initializer(Context *context);
|
Expr *parse_initializer(Context *context);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -497,7 +497,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
|
|||||||
if (param->var.init_expr)
|
if (param->var.init_expr)
|
||||||
{
|
{
|
||||||
Expr *expr = param->var.init_expr;
|
Expr *expr = param->var.init_expr;
|
||||||
if (!sema_analyse_expr_of_required_type(context, param->type, expr, false)) return false;
|
if (!sema_analyse_assigned_expr(context, param->type, expr, false)) return false;
|
||||||
Expr *inner = expr;
|
Expr *inner = expr;
|
||||||
while (inner->expr_kind == EXPR_CAST) inner = expr->cast_expr.expr;
|
while (inner->expr_kind == EXPR_CAST) inner = expr->cast_expr.expr;
|
||||||
if (inner->expr_kind != EXPR_CONST)
|
if (inner->expr_kind != EXPR_CONST)
|
||||||
@@ -587,14 +587,15 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
|
|||||||
switch (base->type_kind)
|
switch (base->type_kind)
|
||||||
{
|
{
|
||||||
case TYPE_STRLIT:
|
case TYPE_STRLIT:
|
||||||
case TYPE_IXX:
|
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
return false;
|
return false;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
SEMA_ERROR(decl, "You cannot create a distinct type from a failable.");
|
||||||
|
return false;
|
||||||
case TYPE_VIRTUAL_ANY:
|
case TYPE_VIRTUAL_ANY:
|
||||||
case TYPE_VIRTUAL:
|
case TYPE_VIRTUAL:
|
||||||
SEMA_ERROR(decl, "You cannot create a distinct type from a virtual type.");
|
SEMA_ERROR(decl, "You cannot create a distinct type from a virtual type.");
|
||||||
@@ -609,9 +610,8 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
|
|||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
SEMA_ERROR(decl, "Cannot create a distinct type from %s.", type_quoted_error_string(base));
|
SEMA_ERROR(decl, "Cannot create a distinct type from %s.", type_quoted_error_string(base));
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
case ALL_SIGNED_INTS:
|
case ALL_INTS:
|
||||||
case ALL_UNSIGNED_INTS:
|
case ALL_FLOATS:
|
||||||
case ALL_REAL_FLOATS:
|
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
@@ -644,10 +644,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
|||||||
DEBUG_LOG("* Enum type resolved to %s.", type->name);
|
DEBUG_LOG("* Enum type resolved to %s.", type->name);
|
||||||
bool success = true;
|
bool success = true;
|
||||||
unsigned enums = vec_size(decl->enums.values);
|
unsigned enums = vec_size(decl->enums.values);
|
||||||
BigInt value;
|
Int128 value = { 0, 0 };
|
||||||
BigInt add;
|
|
||||||
bigint_init_unsigned(&add, 1);
|
|
||||||
bigint_init_unsigned(&value, 0);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < enums; i++)
|
for (unsigned i = 0; i < enums; i++)
|
||||||
{
|
{
|
||||||
@@ -668,23 +665,24 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
|||||||
if (!expr)
|
if (!expr)
|
||||||
{
|
{
|
||||||
expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token));
|
expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token));
|
||||||
expr_set_type(expr, type);
|
expr->type = type;
|
||||||
expr->resolve_status = RESOLVE_NOT_DONE;
|
expr->resolve_status = RESOLVE_NOT_DONE;
|
||||||
bigint_init_bigint(&expr->const_expr.i, &value);
|
REMINDER("Do range check");
|
||||||
expr->const_expr.int_type = TYPE_IXX;
|
expr->const_expr.ixx = (Int) { value, canonical->type_kind };
|
||||||
expr->const_expr.const_kind = CONST_INTEGER;
|
expr->const_expr.const_kind = CONST_INTEGER;
|
||||||
expr_set_type(expr, type_compint);
|
expr->const_expr.narrowable = true;
|
||||||
|
expr->type = canonical;
|
||||||
enum_value->enum_constant.expr = expr;
|
enum_value->enum_constant.expr = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We try to convert to the desired type.
|
// We try to convert to the desired type.
|
||||||
if (!sema_analyse_expr_of_required_type(context, type, expr, false))
|
if (!sema_analyse_expr_of_required_type(context, type, expr))
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
enum_value->resolve_status = RESOLVE_DONE;
|
enum_value->resolve_status = RESOLVE_DONE;
|
||||||
decl_poison(enum_value);
|
decl_poison(enum_value);
|
||||||
// Reset!
|
// Reset!
|
||||||
bigint_init_unsigned(&value, 0);
|
value = (Int128) { 0, 0 };
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +699,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the value
|
// Update the value
|
||||||
bigint_add(&value, &expr->const_expr.i, &add);
|
value = i128_add64(value, 1);
|
||||||
DEBUG_LOG("* Value: %s", expr_const_to_error_string(&expr->const_expr));
|
DEBUG_LOG("* Value: %s", expr_const_to_error_string(&expr->const_expr));
|
||||||
enum_value->resolve_status = RESOLVE_DONE;
|
enum_value->resolve_status = RESOLVE_DONE;
|
||||||
}
|
}
|
||||||
@@ -897,26 +895,24 @@ AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDoma
|
|||||||
SEMA_TOKID_ERROR(attr->name, "'align' requires an power-of-2 argument, e.g. align(8).");
|
SEMA_TOKID_ERROR(attr->name, "'align' requires an power-of-2 argument, e.g. align(8).");
|
||||||
return ATTRIBUTE_NONE;
|
return ATTRIBUTE_NONE;
|
||||||
}
|
}
|
||||||
if (!sema_analyse_expr(context, type_usize, attr->expr)) return false;
|
if (!sema_analyse_expr(context, attr->expr)) return false;
|
||||||
if (attr->expr->expr_kind != EXPR_CONST || !type_is_any_integer(attr->expr->type->canonical))
|
if (attr->expr->expr_kind != EXPR_CONST || !type_is_integer(attr->expr->type->canonical))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(attr->expr, "Expected a constant integer value as argument.");
|
SEMA_ERROR(attr->expr, "Expected a constant integer value as argument.");
|
||||||
return ATTRIBUTE_NONE;
|
return ATTRIBUTE_NONE;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
BigInt comp;
|
if (int_ucomp(attr->expr->const_expr.ixx, MAX_ALIGNMENT, BINARYOP_GT))
|
||||||
bigint_init_unsigned(&comp, MAX_ALIGNMENT);
|
|
||||||
if (bigint_cmp(&attr->expr->const_expr.i, &comp) == CMP_GT)
|
|
||||||
{
|
{
|
||||||
SEMA_ERROR(attr->expr, "Alignment must be less or equal to %ull.", MAX_ALIGNMENT);
|
SEMA_ERROR(attr->expr, "Alignment must be less or equal to %ull.", MAX_ALIGNMENT);
|
||||||
return ATTRIBUTE_NONE;
|
return ATTRIBUTE_NONE;
|
||||||
}
|
}
|
||||||
if (bigint_cmp_zero(&attr->expr->const_expr.i) != CMP_GT)
|
if (int_ucomp(attr->expr->const_expr.ixx, 0, BINARYOP_LE))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(attr->expr, "Alignment must be greater than zero.");
|
SEMA_ERROR(attr->expr, "Alignment must be greater than zero.");
|
||||||
return ATTRIBUTE_NONE;
|
return ATTRIBUTE_NONE;
|
||||||
}
|
}
|
||||||
uint64_t align = bigint_as_unsigned(&attr->expr->const_expr.i);
|
uint64_t align = int_to_u64(attr->expr->const_expr.ixx);
|
||||||
if (!is_power_of_two(align))
|
if (!is_power_of_two(align))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(attr->expr, "Alignment must be a power of two.");
|
SEMA_ERROR(attr->expr, "Alignment must be a power of two.");
|
||||||
@@ -938,7 +934,7 @@ AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDoma
|
|||||||
SEMA_TOKID_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", TOKSTR(attr->name), TOKSTR(attr->name));
|
SEMA_TOKID_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", TOKSTR(attr->name), TOKSTR(attr->name));
|
||||||
return ATTRIBUTE_NONE;
|
return ATTRIBUTE_NONE;
|
||||||
}
|
}
|
||||||
if (!sema_analyse_expr(context, NULL, attr->expr)) return false;
|
if (!sema_analyse_expr(context, attr->expr)) return false;
|
||||||
if (attr->expr->expr_kind != EXPR_CONST || attr->expr->type->canonical != type_compstr)
|
if (attr->expr->expr_kind != EXPR_CONST || attr->expr->type->canonical != type_compstr)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(attr->expr, "Expected a constant string value as argument.");
|
SEMA_ERROR(attr->expr, "Expected a constant string value as argument.");
|
||||||
@@ -1333,7 +1329,7 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
if (!decl->var.type_info)
|
if (!decl->var.type_info)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, NULL, init_expr)) return false;
|
if (!sema_analyse_expr(context, init_expr)) return false;
|
||||||
decl->type = init_expr->type;
|
decl->type = init_expr->type;
|
||||||
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
|
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
|
||||||
|
|
||||||
@@ -1358,7 +1354,6 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
|
|||||||
{
|
{
|
||||||
bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY;
|
bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY;
|
||||||
Expr *init = decl->var.init_expr;
|
Expr *init = decl->var.init_expr;
|
||||||
|
|
||||||
// Handle explicit undef
|
// Handle explicit undef
|
||||||
if (init->expr_kind == EXPR_UNDEF)
|
if (init->expr_kind == EXPR_UNDEF)
|
||||||
{
|
{
|
||||||
@@ -1376,7 +1371,8 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
|
|||||||
decl->resolve_status = RESOLVE_DONE;
|
decl->resolve_status = RESOLVE_DONE;
|
||||||
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
|
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
|
||||||
}
|
}
|
||||||
if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, decl->var.failable || decl->var.unwrap ? FAILABLE_YES : FAILABLE_NO)) return decl_poison(decl);
|
|
||||||
|
if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false)) return decl_poison(decl);
|
||||||
|
|
||||||
if (type_is_inferred)
|
if (type_is_inferred)
|
||||||
{
|
{
|
||||||
@@ -1386,13 +1382,13 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
else if (decl->type)
|
else if (decl->type)
|
||||||
{
|
{
|
||||||
expr_set_type(decl->var.init_expr, decl->type);
|
decl->var.init_expr->type = decl->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr *init_expr = decl->var.init_expr;
|
Expr *init_expr = decl->var.init_expr;
|
||||||
|
|
||||||
// 1. Check type.
|
// 1. Check type.
|
||||||
if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false;
|
if (!sema_analyse_assigned_expr(context, decl->type, init_expr, false)) return false;
|
||||||
|
|
||||||
// 2. Check const-ness
|
// 2. Check const-ness
|
||||||
if ((is_global || decl->var.is_static) && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_ANY))
|
if ((is_global || decl->var.is_static) && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_ANY))
|
||||||
@@ -1401,12 +1397,13 @@ bool sema_analyse_var_decl(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (decl->var.unwrap && !init->failable)
|
if (decl->var.unwrap && init->type->type_kind != TYPE_FAILABLE)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here.");
|
SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here.");
|
||||||
return decl_poison(decl);
|
return decl_poison(decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (init_expr->expr_kind == EXPR_CONST) init_expr->const_expr.narrowable = false;
|
||||||
}
|
}
|
||||||
EXIT_OK:
|
EXIT_OK:
|
||||||
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
|
if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -54,5 +54,5 @@ void context_change_scope_with_flags(Context *context, ScopeFlags flags);
|
|||||||
void c_abi_func_create(FunctionSignature *signature);
|
void c_abi_func_create(FunctionSignature *signature);
|
||||||
AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDomain domain);
|
AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDomain domain);
|
||||||
bool expr_is_ltype(Expr *expr);
|
bool expr_is_ltype(Expr *expr);
|
||||||
bool sema_analyse_expr_value(Context *context, Type *to, Expr *expr);
|
|
||||||
|
|
||||||
|
bool sema_analyse_expr_lvalue(Context *context, Expr *expr);
|
||||||
|
|||||||
@@ -475,14 +475,14 @@ bool sema_unwrap_var(Context *context, Decl *decl)
|
|||||||
Decl *alias = decl_copy(decl);
|
Decl *alias = decl_copy(decl);
|
||||||
alias->var.kind = VARDECL_UNWRAPPED;
|
alias->var.kind = VARDECL_UNWRAPPED;
|
||||||
alias->var.alias = decl;
|
alias->var.alias = decl;
|
||||||
alias->var.failable = false;
|
alias->type = alias->type->failable;
|
||||||
alias->resolve_status = RESOLVE_DONE;
|
alias->resolve_status = RESOLVE_DONE;
|
||||||
return sema_append_local(context, alias);
|
return sema_append_local(context, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sema_rewrap_var(Context *context, Decl *decl)
|
bool sema_rewrap_var(Context *context, Decl *decl)
|
||||||
{
|
{
|
||||||
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_UNWRAPPED && decl->var.alias->var.failable);
|
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_UNWRAPPED && decl->var.alias->type->type_kind == TYPE_FAILABLE);
|
||||||
return sema_append_local(context, decl->var.alias);
|
return sema_append_local(context, decl->var.alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,11 +497,11 @@ bool sema_erase_var(Context *context, Decl *decl)
|
|||||||
|
|
||||||
bool sema_erase_unwrapped(Context *context, Decl *decl)
|
bool sema_erase_unwrapped(Context *context, Decl *decl)
|
||||||
{
|
{
|
||||||
assert(decl->var.failable);
|
assert(IS_FAILABLE(decl));
|
||||||
Decl *rewrapped = decl_copy(decl);
|
Decl *rewrapped = decl_copy(decl);
|
||||||
rewrapped->var.kind = VARDECL_REWRAPPED;
|
rewrapped->var.kind = VARDECL_REWRAPPED;
|
||||||
rewrapped->var.alias = decl;
|
rewrapped->var.alias = decl;
|
||||||
rewrapped->var.failable = true;
|
rewrapped->type = decl->type;
|
||||||
rewrapped->resolve_status = RESOLVE_DONE;
|
rewrapped->resolve_status = RESOLVE_DONE;
|
||||||
return sema_append_local(context, rewrapped);
|
return sema_append_local(context, rewrapped);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ static void sema_unwrappable_from_catch_in_else(Context *c, Expr *cond)
|
|||||||
if (expr->expr_kind != EXPR_IDENTIFIER) continue;
|
if (expr->expr_kind != EXPR_IDENTIFIER) continue;
|
||||||
Decl *decl = expr->identifier_expr.decl;
|
Decl *decl = expr->identifier_expr.decl;
|
||||||
if (decl->decl_kind != DECL_VAR) continue;
|
if (decl->decl_kind != DECL_VAR) continue;
|
||||||
assert(decl->var.failable && "The variable should always be failable at this point.");
|
assert(decl->type->type_kind == TYPE_FAILABLE && "The variable should always be failable at this point.");
|
||||||
|
|
||||||
// 5. Locals and globals may be unwrapped
|
// 5. Locals and globals may be unwrapped
|
||||||
switch (decl->var.kind)
|
switch (decl->var.kind)
|
||||||
@@ -54,10 +54,10 @@ static inline bool sema_analyse_block_return_stmt(Context *context, Ast *stateme
|
|||||||
context->active_scope.jump_end = true;
|
context->active_scope.jump_end = true;
|
||||||
if (statement->return_stmt.expr)
|
if (statement->return_stmt.expr)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr_of_required_type(context,
|
if (!sema_analyse_expr(context, statement->return_stmt.expr))
|
||||||
context->expected_block_type,
|
{
|
||||||
statement->return_stmt.expr, true)) return false;
|
return false;
|
||||||
context->expr_failable_return |= statement->return_stmt.expr->failable;
|
}
|
||||||
}
|
}
|
||||||
vec_add(context->returns, statement);
|
vec_add(context->returns, statement);
|
||||||
return true;
|
return true;
|
||||||
@@ -94,7 +94,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
|
|||||||
// 2. First handle the plain return.
|
// 2. First handle the plain return.
|
||||||
if (return_expr == NULL)
|
if (return_expr == NULL)
|
||||||
{
|
{
|
||||||
if (expected_rtype->canonical != type_void)
|
if (type_no_fail(expected_rtype)->canonical != type_void)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(statement, "Expected to return a result of type %s.", type_to_error_string(expected_rtype));
|
SEMA_ERROR(statement, "Expected to return a result of type %s.", type_to_error_string(expected_rtype));
|
||||||
return false;
|
return false;
|
||||||
@@ -103,9 +103,9 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. Evaluate the return value to be the expected return type.
|
// 3. Evaluate the return value to be the expected return type.
|
||||||
if (!sema_analyse_expr_of_required_type(context, expected_rtype, return_expr, context->failable_return)) return false;
|
if (!sema_analyse_expr_of_required_type(context, expected_rtype, return_expr)) return false;
|
||||||
|
|
||||||
assert(statement->return_stmt.expr->type->canonical == expected_rtype->canonical);
|
assert(type_no_fail(statement->return_stmt.expr->type)->canonical == type_no_fail(expected_rtype)->canonical);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
// Case A. Unwrapping a single variable.
|
// Case A. Unwrapping a single variable.
|
||||||
if (!failable)
|
if (!failable)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, NULL, ident)) return false;
|
if (!sema_analyse_expr(context, ident)) return false;
|
||||||
if (ident->expr_kind != EXPR_IDENTIFIER)
|
if (ident->expr_kind != EXPR_IDENTIFIER)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(ident, "Only single identifiers may be unwrapped using 'try var', maybe you wanted 'try (expr)' instead?");
|
SEMA_ERROR(ident, "Only single identifiers may be unwrapped using 'try var', maybe you wanted 'try (expr)' instead?");
|
||||||
@@ -137,7 +137,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
SEMA_ERROR(ident, "Expected this to be the name of a failable variable, but it isn't. Did you mistype?");
|
SEMA_ERROR(ident, "Expected this to be the name of a failable variable, but it isn't. Did you mistype?");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!decl->var.failable)
|
if (!IS_FAILABLE(decl))
|
||||||
{
|
{
|
||||||
if (decl->var.kind == VARDECL_UNWRAPPED)
|
if (decl->var.kind == VARDECL_UNWRAPPED)
|
||||||
{
|
{
|
||||||
@@ -148,7 +148,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
expr->try_unwrap_expr.decl = decl;
|
expr->try_unwrap_expr.decl = decl;
|
||||||
expr_set_type(expr, type_bool);
|
expr->type = type_bool;
|
||||||
sema_unwrap_var(context, decl);
|
sema_unwrap_var(context, decl);
|
||||||
expr->resolve_status = RESOLVE_DONE;
|
expr->resolve_status = RESOLVE_DONE;
|
||||||
return true;
|
return true;
|
||||||
@@ -166,13 +166,21 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. If we have a type for the variable, resolve it.
|
// 2. If we have a type for the variable, resolve it.
|
||||||
if (var_type && !sema_resolve_type_info(context, var_type)) return false;
|
if (var_type)
|
||||||
|
{
|
||||||
|
if (!sema_resolve_type_info(context, var_type)) return false;
|
||||||
|
if (IS_FAILABLE(var_type))
|
||||||
|
{
|
||||||
|
SEMA_ERROR(var_type, "Only non-failable types may be used as types for 'try', please remove the '!'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3. We interpret this as an assignment to an existing variable.
|
// 3. We interpret this as an assignment to an existing variable.
|
||||||
if (!var_type && !implicit_declaration)
|
if (!var_type && !implicit_declaration)
|
||||||
{
|
{
|
||||||
// 3a. Resolve the identifier.
|
// 3a. Resolve the identifier.
|
||||||
if (!sema_analyse_expr_value(context, NULL, ident)) return false;
|
if (!sema_analyse_expr_lvalue(context, ident)) return false;
|
||||||
|
|
||||||
// 3b. Make sure it's assignable
|
// 3b. Make sure it's assignable
|
||||||
if (!expr_is_ltype(ident))
|
if (!expr_is_ltype(ident))
|
||||||
@@ -182,7 +190,7 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3c. It can't be failable either.
|
// 3c. It can't be failable either.
|
||||||
if (ident->failable)
|
if (IS_FAILABLE(ident))
|
||||||
{
|
{
|
||||||
if (ident->expr_kind == EXPR_IDENTIFIER)
|
if (ident->expr_kind == EXPR_IDENTIFIER)
|
||||||
{
|
{
|
||||||
@@ -196,7 +204,15 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3d. We can now analyse the expression using the variable type.
|
// 3d. We can now analyse the expression using the variable type.
|
||||||
if (!sema_analyse_expr_of_required_type(context, ident->type, failable, true)) return false;
|
if (!sema_analyse_expr(context, failable)) return false;
|
||||||
|
|
||||||
|
if (!IS_FAILABLE(failable))
|
||||||
|
{
|
||||||
|
SEMA_ERROR(failable, "Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cast_implicit_ignore_failable(failable, ident->type)) return false;
|
||||||
|
|
||||||
expr->try_unwrap_expr.assign_existing = true;
|
expr->try_unwrap_expr.assign_existing = true;
|
||||||
expr->try_unwrap_expr.lhs = ident;
|
expr->try_unwrap_expr.lhs = ident;
|
||||||
@@ -226,16 +242,24 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4a. Type may be assigned or inferred.
|
|
||||||
Type *type = var_type ? var_type->type : NULL;
|
|
||||||
|
|
||||||
// 4b. Evaluate the expression
|
// 4b. Evaluate the expression
|
||||||
if (!sema_analyse_expr_of_required_type(context, type, failable, true)) return false;
|
if (!sema_analyse_expr(context, failable)) return false;
|
||||||
|
|
||||||
|
if (!IS_FAILABLE(failable))
|
||||||
|
{
|
||||||
|
SEMA_ERROR(failable, "Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var_type)
|
||||||
|
{
|
||||||
|
if (!cast_implicit_ignore_failable(failable, var_type->type)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 4c. Create a type_info if needed.
|
// 4c. Create a type_info if needed.
|
||||||
if (!var_type)
|
if (!var_type)
|
||||||
{
|
{
|
||||||
var_type = type_info_new_base(failable->type, failable->span);
|
var_type = type_info_new_base(failable->type->failable, failable->span);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4d. A new declaration is created.
|
// 4d. A new declaration is created.
|
||||||
@@ -247,14 +271,8 @@ static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
|||||||
expr->try_unwrap_expr.decl = decl;
|
expr->try_unwrap_expr.decl = decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!failable->failable)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(failable, "Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
expr->try_unwrap_expr.failable = failable;
|
expr->try_unwrap_expr.failable = failable;
|
||||||
expr_set_type(expr, type_bool);
|
expr->type = type_bool;
|
||||||
expr->resolve_status = RESOLVE_DONE;
|
expr->resolve_status = RESOLVE_DONE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -269,9 +287,9 @@ static inline bool sema_analyse_try_unwrap_chain(Context *context, Expr *expr)
|
|||||||
if (!sema_analyse_try_unwrap(context, chain)) return false;
|
if (!sema_analyse_try_unwrap(context, chain)) return false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!sema_analyse_expr_of_required_type(context, type_bool, chain, false)) return false;
|
if (!sema_analyse_cond_expr(context, chain)) return false;
|
||||||
}
|
}
|
||||||
expr_set_type(expr, type_bool);
|
expr->type = type_bool;
|
||||||
expr->resolve_status = RESOLVE_DONE;
|
expr->resolve_status = RESOLVE_DONE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -296,7 +314,7 @@ static inline bool sema_analyse_catch_unwrap(Context *context, Expr *expr)
|
|||||||
|
|
||||||
if (!type && !implicit_declaration)
|
if (!type && !implicit_declaration)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr_value(context, NULL, ident)) return false;
|
if (!sema_analyse_expr_lvalue(context, ident)) return false;
|
||||||
|
|
||||||
if (!expr_is_ltype(ident))
|
if (!expr_is_ltype(ident))
|
||||||
{
|
{
|
||||||
@@ -361,14 +379,14 @@ RESOLVE_EXPRS:;
|
|||||||
VECEACH(exprs, i)
|
VECEACH(exprs, i)
|
||||||
{
|
{
|
||||||
Expr *fail = exprs[i];
|
Expr *fail = exprs[i];
|
||||||
if (!sema_analyse_expr(context, NULL, fail)) return false;
|
if (!sema_analyse_expr(context, fail)) return false;
|
||||||
if (!fail->failable)
|
if (fail->type->type_kind != TYPE_FAILABLE)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(fail, "This expression is not failable, did you add it by mistake?");
|
SEMA_ERROR(fail, "This expression is not failable, did you add it by mistake?");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr_set_type(expr, type_anyerr);
|
expr->type = type_anyerr;
|
||||||
expr->resolve_status = RESOLVE_DONE;
|
expr->resolve_status = RESOLVE_DONE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -414,7 +432,7 @@ static inline bool sema_analyse_last_cond(Context *context, Expr *expr, bool may
|
|||||||
}
|
}
|
||||||
return sema_analyse_catch_unwrap(context, expr);
|
return sema_analyse_catch_unwrap(context, expr);
|
||||||
default:
|
default:
|
||||||
return sema_analyse_expr(context, NULL, expr);
|
return sema_analyse_expr(context, expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -435,19 +453,19 @@ static inline bool sema_analyse_cond_list(Context *context, Expr *expr, bool may
|
|||||||
// 1. Special case, there are no entries, so the type is void
|
// 1. Special case, there are no entries, so the type is void
|
||||||
if (entries == 0)
|
if (entries == 0)
|
||||||
{
|
{
|
||||||
expr_set_type(expr, type_void);
|
expr->type = type_void;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Walk through each of our declarations / expressions as if they were regular expressions.
|
// 2. Walk through each of our declarations / expressions as if they were regular expressions.
|
||||||
for (unsigned i = 0; i < entries - 1; i++)
|
for (unsigned i = 0; i < entries - 1; i++)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, NULL, dexprs[i])) return false;
|
if (!sema_analyse_expr(context, dexprs[i])) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sema_analyse_last_cond(context, dexprs[entries - 1], may_unwrap)) return false;
|
if (!sema_analyse_last_cond(context, dexprs[entries - 1], may_unwrap)) return false;
|
||||||
|
|
||||||
expr_set_type(expr, dexprs[entries - 1]->type);
|
expr->type = dexprs[entries - 1]->type;
|
||||||
expr->resolve_status = RESOLVE_DONE;
|
expr->resolve_status = RESOLVE_DONE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -495,11 +513,12 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 3e. Expect that it isn't a failable
|
// 3e. Expect that it isn't a failable
|
||||||
if (init->failable && !decl->var.unwrap)
|
if (IS_FAILABLE(init) && !decl->var.unwrap)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(last, "'%s!' cannot be converted into '%s'.",
|
SEMA_ERROR(last, "%s cannot be converted to %s.",
|
||||||
type_to_error_string(last->type),
|
type_quoted_error_string(last->type),
|
||||||
cast_to_bool ? "bool" : type_to_error_string(init->type));
|
cast_to_bool ? "'bool'" : type_quoted_error_string(init->type));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// TODO document
|
// TODO document
|
||||||
if (!decl->var.unwrap && cast_to_bool && cast_to_bool_kind(decl->var.type_info->type) == CAST_ERROR)
|
if (!decl->var.unwrap && cast_to_bool && cast_to_bool_kind(decl->var.type_info->type) == CAST_ERROR)
|
||||||
@@ -510,11 +529,12 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 3a. Check for failables in case of an expression.
|
// 3a. Check for failables in case of an expression.
|
||||||
if (last->failable)
|
if (IS_FAILABLE(last))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(last, "'%s!' cannot be converted into '%s'.",
|
SEMA_ERROR(last, "%s cannot be converted to %s.",
|
||||||
type_to_error_string(last->type),
|
type_quoted_error_string(last->type),
|
||||||
cast_to_bool ? "bool" : type_to_error_string(last->type));
|
cast_to_bool ? "'bool'" : type_quoted_error_string(type_no_fail(last->type)));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// 3b. Cast to bool if that is needed
|
// 3b. Cast to bool if that is needed
|
||||||
if (cast_to_bool)
|
if (cast_to_bool)
|
||||||
@@ -618,7 +638,7 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
|
|||||||
SCOPE_START
|
SCOPE_START
|
||||||
|
|
||||||
// 10. Try to evaluate and implicitly cast to boolean.
|
// 10. Try to evaluate and implicitly cast to boolean.
|
||||||
if (!sema_analyse_expr_of_required_type(context, type_bool, expr, false))
|
if (!sema_analyse_cond_expr(context, expr))
|
||||||
{
|
{
|
||||||
// 10a. On failure, pop and return false.
|
// 10a. On failure, pop and return false.
|
||||||
return SCOPE_POP_ERROR();
|
return SCOPE_POP_ERROR();
|
||||||
@@ -669,7 +689,7 @@ bool sema_analyse_local_decl(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
if (!decl->var.type_info)
|
if (!decl->var.type_info)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, NULL, init_expr)) return false;
|
if (!sema_analyse_expr(context, init_expr)) return false;
|
||||||
decl->type = init_expr->type;
|
decl->type = init_expr->type;
|
||||||
// Skip further evaluation.
|
// Skip further evaluation.
|
||||||
goto EXIT_OK;
|
goto EXIT_OK;
|
||||||
@@ -692,7 +712,7 @@ bool sema_analyse_local_decl(Context *context, Decl *decl)
|
|||||||
goto EXIT_OK;
|
goto EXIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, decl->var.failable || decl->var.unwrap ? FAILABLE_YES : FAILABLE_NO)) return decl_poison(decl);
|
if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false)) return decl_poison(decl);
|
||||||
|
|
||||||
if (type_is_inferred)
|
if (type_is_inferred)
|
||||||
{
|
{
|
||||||
@@ -700,18 +720,13 @@ bool sema_analyse_local_decl(Context *context, Decl *decl)
|
|||||||
assert(right_side_type->type_kind == TYPE_ARRAY);
|
assert(right_side_type->type_kind == TYPE_ARRAY);
|
||||||
decl->type = type_get_array(decl->type->array.base, right_side_type->array.len);
|
decl->type = type_get_array(decl->type->array.base, right_side_type->array.len);
|
||||||
}
|
}
|
||||||
else if (decl->type)
|
|
||||||
{
|
|
||||||
expr_set_type(decl->var.init_expr, decl->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (decl->var.unwrap && init->type->type_kind != TYPE_FAILABLE)
|
||||||
if (decl->var.unwrap && !init->failable)
|
|
||||||
{
|
{
|
||||||
SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here.");
|
SEMA_ERROR(decl->var.init_expr, "A failable expression was expected here.");
|
||||||
return decl_poison(decl);
|
return decl_poison(decl);
|
||||||
}
|
}
|
||||||
|
if (init->expr_kind == EXPR_CONST) init->const_expr.narrowable = false;
|
||||||
}
|
}
|
||||||
EXIT_OK:
|
EXIT_OK:
|
||||||
if (decl->var.is_static)
|
if (decl->var.is_static)
|
||||||
@@ -739,15 +754,37 @@ static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
|
|||||||
return sema_analyse_local_decl(context, statement->declare_stmt);
|
return sema_analyse_local_decl(context, statement->declare_stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
|
/**
|
||||||
|
* Check "var $foo = ... " and "var $Foo = ..."
|
||||||
|
*/
|
||||||
|
static inline bool sema_analyse_var_stmt(Context *context, Ast *statement)
|
||||||
{
|
{
|
||||||
Decl *decl = statement->declare_stmt;
|
// 1. Pick the declaration.
|
||||||
|
Decl *decl = statement->var_stmt;
|
||||||
|
|
||||||
|
// 2. Convert it to a NOP early
|
||||||
statement->ast_kind = AST_NOP_STMT;
|
statement->ast_kind = AST_NOP_STMT;
|
||||||
|
|
||||||
assert(decl->decl_kind == DECL_VAR);
|
assert(decl->decl_kind == DECL_VAR);
|
||||||
switch (decl->var.kind)
|
switch (decl->var.kind)
|
||||||
{
|
{
|
||||||
case VARDECL_LOCAL_CT_TYPE:
|
case VARDECL_LOCAL_CT_TYPE:
|
||||||
if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false;
|
// Locally declared compile time type.
|
||||||
|
if (decl->var.type_info)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(decl->var.type_info, "Compile time type variables may not have a type.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Expr *init = decl->var.init_expr;
|
||||||
|
if (init)
|
||||||
|
{
|
||||||
|
if (!sema_analyse_expr_lvalue(context, init)) return false;
|
||||||
|
if (init->expr_kind != EXPR_TYPEINFO)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(decl->var.init_expr, "Expected a type assigned to %s.", decl->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case VARDECL_LOCAL_CT:
|
case VARDECL_LOCAL_CT:
|
||||||
if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false;
|
if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||||
@@ -761,7 +798,7 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
|
|||||||
}
|
}
|
||||||
if (decl->var.init_expr)
|
if (decl->var.init_expr)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false;
|
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr)) return false;
|
||||||
if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY))
|
if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
|
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
|
||||||
@@ -779,7 +816,7 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
|
|||||||
Expr *init = decl->var.init_expr;
|
Expr *init = decl->var.init_expr;
|
||||||
if (init)
|
if (init)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, NULL, init)) return false;
|
if (!sema_analyse_expr(context, init)) return false;
|
||||||
if (!expr_is_constant_eval(init, CONSTANT_EVAL_ANY))
|
if (!expr_is_constant_eval(init, CONSTANT_EVAL_ANY))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
|
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
|
||||||
@@ -803,7 +840,7 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
|
|||||||
|
|
||||||
static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement)
|
static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, NULL, statement->expr_stmt)) return false;
|
if (!sema_analyse_expr(context, statement->expr_stmt)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -860,7 +897,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
|
|||||||
// Conditional scope start
|
// Conditional scope start
|
||||||
SCOPE_START
|
SCOPE_START
|
||||||
Expr *cond = statement->for_stmt.cond;
|
Expr *cond = statement->for_stmt.cond;
|
||||||
success = sema_analyse_expr_of_required_type(context, type_bool, cond, false);
|
success = sema_analyse_cond_expr(context, cond);
|
||||||
statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond);
|
statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond);
|
||||||
// If this is const true, then set this to infinite and remove the expression.
|
// If this is const true, then set this to infinite and remove the expression.
|
||||||
if (statement->for_stmt.cond->expr_kind == EXPR_CONST && statement->for_stmt.cond->const_expr.b)
|
if (statement->for_stmt.cond->expr_kind == EXPR_CONST && statement->for_stmt.cond->const_expr.b)
|
||||||
@@ -876,7 +913,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
|
|||||||
// Incr scope start
|
// Incr scope start
|
||||||
SCOPE_START
|
SCOPE_START
|
||||||
Expr *incr = statement->for_stmt.incr;
|
Expr *incr = statement->for_stmt.incr;
|
||||||
success = sema_analyse_expr(context, NULL, incr);
|
success = sema_analyse_expr(context, incr);
|
||||||
statement->for_stmt.incr = context_pop_defers_and_wrap_expr(context, incr);
|
statement->for_stmt.incr = context_pop_defers_and_wrap_expr(context, incr);
|
||||||
// Incr scope end
|
// Incr scope end
|
||||||
SCOPE_END;
|
SCOPE_END;
|
||||||
@@ -919,7 +956,8 @@ static inline bool sema_inline_default_iterator(Context *context, Expr *expr, De
|
|||||||
expr->call_expr = (ExprCall) {
|
expr->call_expr = (ExprCall) {
|
||||||
.is_type_method = true,
|
.is_type_method = true,
|
||||||
};
|
};
|
||||||
return sema_expr_analyse_general_call(context, NULL, expr, decl, inner, decl->decl_kind == DECL_MACRO);
|
REMINDER("Failability");
|
||||||
|
return sema_expr_analyse_general_call(context, expr, decl, inner, decl->decl_kind == DECL_MACRO, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Decl *find_iterator(Context *context, Expr *enumerator)
|
static Decl *find_iterator(Context *context, Expr *enumerator)
|
||||||
@@ -1085,7 +1123,7 @@ static bool sema_rewrite_foreach_to_for(Context *context, Ast *statement, Expr *
|
|||||||
expr->decl_expr = iterator;
|
expr->decl_expr = iterator;
|
||||||
vec_add(init_expr->cond_expr, expr);
|
vec_add(init_expr->cond_expr, expr);
|
||||||
init_expr->resolve_status = RESOLVE_DONE;
|
init_expr->resolve_status = RESOLVE_DONE;
|
||||||
expr_set_type(init_expr, iterator->type);
|
init_expr->type = iterator->type;
|
||||||
|
|
||||||
// Generate "next": it.next(&value)
|
// Generate "next": it.next(&value)
|
||||||
Expr *call = expr_new(EXPR_CALL, enumerator->span);
|
Expr *call = expr_new(EXPR_CALL, enumerator->span);
|
||||||
@@ -1101,7 +1139,12 @@ static bool sema_rewrite_foreach_to_for(Context *context, Ast *statement, Expr *
|
|||||||
Expr *iterator_access = expr_variable(iterator);
|
Expr *iterator_access = expr_variable(iterator);
|
||||||
expr_insert_addr(iterator_access);
|
expr_insert_addr(iterator_access);
|
||||||
|
|
||||||
if (!sema_expr_analyse_general_call(context, NULL, call, next_method, iterator_access, next_method->decl_kind == DECL_MACRO)) return false;
|
REMINDER("Failability");
|
||||||
|
if (!sema_expr_analyse_general_call(context,
|
||||||
|
call,
|
||||||
|
next_method,
|
||||||
|
iterator_access,
|
||||||
|
next_method->decl_kind == DECL_MACRO, false)) return false;
|
||||||
call->resolve_status = RESOLVE_DONE;
|
call->resolve_status = RESOLVE_DONE;
|
||||||
|
|
||||||
statement->for_stmt = (AstForStmt){ .init = init_expr,
|
statement->for_stmt = (AstForStmt){ .init = init_expr,
|
||||||
@@ -1179,7 +1222,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// because we don't want the index + variable to move into the internal scope
|
// because we don't want the index + variable to move into the internal scope
|
||||||
if (!sema_analyse_expr(context, inferred_type, enumerator))
|
if (!sema_analyse_inferred_expr(context, inferred_type, enumerator))
|
||||||
{
|
{
|
||||||
// Exit early here, because semantic checking might be messed up otherwise.
|
// Exit early here, because semantic checking might be messed up otherwise.
|
||||||
return SCOPE_POP_ERROR();
|
return SCOPE_POP_ERROR();
|
||||||
@@ -1242,6 +1285,12 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
|
|||||||
// Analyse the declaration.
|
// Analyse the declaration.
|
||||||
if (!sema_analyse_local_decl(context, index)) return SCOPE_POP_ERROR();
|
if (!sema_analyse_local_decl(context, index)) return SCOPE_POP_ERROR();
|
||||||
|
|
||||||
|
if (index->type->type_kind == TYPE_FAILABLE)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(index->var.type_info, "The index may not be a failable.");
|
||||||
|
return SCOPE_POP_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure that the index is an integer.
|
// Make sure that the index is an integer.
|
||||||
if (!type_is_integer(type_flatten(index->type)))
|
if (!type_is_integer(type_flatten(index->type)))
|
||||||
{
|
{
|
||||||
@@ -1250,11 +1299,6 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
|
|||||||
type_to_error_string(index->type));
|
type_to_error_string(index->type));
|
||||||
return SCOPE_POP_ERROR();
|
return SCOPE_POP_ERROR();
|
||||||
}
|
}
|
||||||
if (index->var.failable)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(index->var.type_info, "The index may not be a failable.");
|
|
||||||
return SCOPE_POP_ERROR();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the expected type for the value.
|
// Find the expected type for the value.
|
||||||
@@ -1272,7 +1316,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
|
|||||||
// Analyse the value declaration.
|
// Analyse the value declaration.
|
||||||
if (!sema_analyse_local_decl(context, var)) return SCOPE_POP_ERROR();
|
if (!sema_analyse_local_decl(context, var)) return SCOPE_POP_ERROR();
|
||||||
|
|
||||||
if (var->var.failable)
|
if (IS_FAILABLE(var))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(var->var.type_info, "The variable may not be a failable.");
|
SEMA_ERROR(var->var.type_info, "The variable may not be a failable.");
|
||||||
return SCOPE_POP_ERROR();
|
return SCOPE_POP_ERROR();
|
||||||
@@ -1287,7 +1331,7 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
|
|||||||
{
|
{
|
||||||
// This is hackish, replace when cast is refactored.
|
// This is hackish, replace when cast is refactored.
|
||||||
Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc,
|
Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc,
|
||||||
var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type, .original_type = expected_var_type };
|
var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type };
|
||||||
if (!cast_implicit(&dummy, var->type)) return SCOPE_POP_ERROR();
|
if (!cast_implicit(&dummy, var->type)) return SCOPE_POP_ERROR();
|
||||||
|
|
||||||
assert(dummy.expr_kind == EXPR_CAST);
|
assert(dummy.expr_kind == EXPR_CAST);
|
||||||
@@ -1418,7 +1462,7 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
|
|||||||
|
|
||||||
static bool sema_analyse_asm_stmt(Context *context, Ast *stmt)
|
static bool sema_analyse_asm_stmt(Context *context, Ast *stmt)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, NULL, stmt->asm_stmt.body)) return false;
|
if (!sema_analyse_expr(context, stmt->asm_stmt.body)) return false;
|
||||||
if (stmt->asm_stmt.body->expr_kind != EXPR_CONST
|
if (stmt->asm_stmt.body->expr_kind != EXPR_CONST
|
||||||
|| stmt->asm_stmt.body->const_expr.const_kind != CONST_STRING)
|
|| stmt->asm_stmt.body->const_expr.const_kind != CONST_STRING)
|
||||||
{
|
{
|
||||||
@@ -1594,7 +1638,7 @@ static bool sema_analyse_nextcase_stmt(Context *context, Ast *statement)
|
|||||||
|
|
||||||
Type *expected_type = parent->ast_kind == AST_SWITCH_STMT ? parent->switch_stmt.cond->type : type_anyerr;
|
Type *expected_type = parent->ast_kind == AST_SWITCH_STMT ? parent->switch_stmt.cond->type : type_anyerr;
|
||||||
|
|
||||||
if (!sema_analyse_expr_of_required_type(context, expected_type, target, false)) return false;
|
if (!sema_analyse_expr_of_required_type(context, expected_type, target)) return false;
|
||||||
|
|
||||||
if (target->expr_kind == EXPR_CONST)
|
if (target->expr_kind == EXPR_CONST)
|
||||||
{
|
{
|
||||||
@@ -1720,9 +1764,9 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st
|
|||||||
Expr *case_expr = case_stmt->case_stmt.expr;
|
Expr *case_expr = case_stmt->case_stmt.expr;
|
||||||
|
|
||||||
// 1. Try to do implicit conversion to the correct type.
|
// 1. Try to do implicit conversion to the correct type.
|
||||||
if (!sema_analyse_expr(context, to_type, case_expr)) return false;
|
if (!sema_analyse_inferred_expr(context, to_type, case_expr)) return false;
|
||||||
|
|
||||||
Type *case_type = case_expr->original_type->canonical;
|
Type *case_type = case_expr->type->canonical;
|
||||||
Type *to_type_canonical = to_type->canonical;
|
Type *to_type_canonical = to_type->canonical;
|
||||||
|
|
||||||
// 3. If we already have the same type we're done.
|
// 3. If we already have the same type we're done.
|
||||||
@@ -1730,7 +1774,7 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st
|
|||||||
|
|
||||||
// 4. Otherwise check if we have an enum receiving type and a number on
|
// 4. Otherwise check if we have an enum receiving type and a number on
|
||||||
// in the case. In that case we do an implicit conversion.
|
// in the case. In that case we do an implicit conversion.
|
||||||
if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_type))
|
if (to_type_canonical->type_kind == TYPE_ENUM && type_is_integer(case_type))
|
||||||
{
|
{
|
||||||
return cast(case_expr, to_type);
|
return cast(case_expr, to_type);
|
||||||
}
|
}
|
||||||
@@ -1758,7 +1802,7 @@ static inline bool sema_analyse_compound_statement_no_scope(Context *context, As
|
|||||||
static inline bool sema_check_type_case(Context *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index)
|
static inline bool sema_check_type_case(Context *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index)
|
||||||
{
|
{
|
||||||
Expr *expr = case_stmt->case_stmt.expr;
|
Expr *expr = case_stmt->case_stmt.expr;
|
||||||
if (!sema_analyse_expr_of_required_type(context, type_typeid, expr, false)) return false;
|
if (!sema_analyse_expr_of_required_type(context, type_typeid, expr)) return false;
|
||||||
|
|
||||||
if (expr->expr_kind == EXPR_CONST)
|
if (expr->expr_kind == EXPR_CONST)
|
||||||
{
|
{
|
||||||
@@ -1810,7 +1854,7 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpa
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We need an if chain if this isn't an integer type.
|
// We need an if chain if this isn't an integer type.
|
||||||
bool if_chain = !type_is_any_integer(type_flatten(switch_type));
|
bool if_chain = !type_is_integer(type_flatten(switch_type));
|
||||||
|
|
||||||
Ast *default_case = NULL;
|
Ast *default_case = NULL;
|
||||||
assert(context->active_scope.defer_start == context->active_scope.defer_last);
|
assert(context->active_scope.defer_start == context->active_scope.defer_last);
|
||||||
@@ -1895,7 +1939,7 @@ static bool sema_analyse_ct_switch_body(Context *context, Ast *statement)
|
|||||||
if (use_type_id)
|
if (use_type_id)
|
||||||
{
|
{
|
||||||
Expr *expr = stmt->case_stmt.expr;
|
Expr *expr = stmt->case_stmt.expr;
|
||||||
if (!sema_analyse_expr_value(context, NULL, expr)) return false;
|
if (!sema_analyse_expr_lvalue(context, expr)) return false;
|
||||||
if (stmt->case_stmt.expr->expr_kind != EXPR_TYPEINFO)
|
if (stmt->case_stmt.expr->expr_kind != EXPR_TYPEINFO)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(stmt, "Unexpectedly encountered a value rather than a type in the $case");
|
SEMA_ERROR(stmt, "Unexpectedly encountered a value rather than a type in the $case");
|
||||||
@@ -1921,8 +1965,7 @@ static bool sema_analyse_ct_switch_body(Context *context, Ast *statement)
|
|||||||
{
|
{
|
||||||
if (!sema_analyse_expr_of_required_type(context,
|
if (!sema_analyse_expr_of_required_type(context,
|
||||||
cond->type,
|
cond->type,
|
||||||
stmt->case_stmt.expr,
|
stmt->case_stmt.expr))
|
||||||
false))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1956,7 +1999,7 @@ static bool sema_analyse_ct_switch_body(Context *context, Ast *statement)
|
|||||||
static bool sema_analyse_ct_switch_stmt(Context *context, Ast *statement)
|
static bool sema_analyse_ct_switch_stmt(Context *context, Ast *statement)
|
||||||
{
|
{
|
||||||
Expr *cond = statement->ct_switch_stmt.cond;
|
Expr *cond = statement->ct_switch_stmt.cond;
|
||||||
if (!sema_analyse_expr(context, NULL, cond)) return false;
|
if (!sema_analyse_expr(context, cond)) return false;
|
||||||
if (cond->expr_kind != EXPR_CONST && cond->expr_kind != EXPR_TYPEID)
|
if (cond->expr_kind != EXPR_CONST && cond->expr_kind != EXPR_TYPEID)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(cond, "A compile time $switch must be over a constant value.");
|
SEMA_ERROR(cond, "A compile time $switch must be over a constant value.");
|
||||||
@@ -2018,7 +2061,7 @@ bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement)
|
|||||||
Expr *message = statement->ct_assert_stmt.message;
|
Expr *message = statement->ct_assert_stmt.message;
|
||||||
if (message)
|
if (message)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, type_compstr, message)) return false;
|
if (!sema_analyse_expr(context, message)) return false;
|
||||||
if (message->type->type_kind != TYPE_STRLIT)
|
if (message->type->type_kind != TYPE_STRLIT)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(message, "Expected a string as the error message.");
|
SEMA_ERROR(message, "Expected a string as the error message.");
|
||||||
@@ -2049,7 +2092,7 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement)
|
|||||||
Expr *message = statement->assert_stmt.message;
|
Expr *message = statement->assert_stmt.message;
|
||||||
if (message)
|
if (message)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, type_compstr, message)) return false;
|
if (!sema_analyse_expr(context, message)) return false;
|
||||||
if (message->type->type_kind != TYPE_STRLIT)
|
if (message->type->type_kind != TYPE_STRLIT)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(message, "Expected a string as the error message.");
|
SEMA_ERROR(message, "Expected a string as the error message.");
|
||||||
@@ -2061,7 +2104,7 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr_of_required_type(context, type_bool, expr, false)) return false;
|
if (!sema_analyse_assigned_expr(context, type_bool, expr, false)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2144,8 +2187,8 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
|
|||||||
return false;
|
return false;
|
||||||
case AST_DEFER_STMT:
|
case AST_DEFER_STMT:
|
||||||
return sema_analyse_defer_stmt(context, statement);
|
return sema_analyse_defer_stmt(context, statement);
|
||||||
case AST_DEFINE_STMT:
|
case AST_VAR_STMT:
|
||||||
return sema_analyse_define_stmt(context, statement);
|
return sema_analyse_var_stmt(context, statement);
|
||||||
case AST_DO_STMT:
|
case AST_DO_STMT:
|
||||||
return sema_analyse_do_stmt(context, statement);
|
return sema_analyse_do_stmt(context, statement);
|
||||||
case AST_EXPR_STMT:
|
case AST_EXPR_STMT:
|
||||||
@@ -2219,7 +2262,7 @@ static bool sema_analyse_requires(Context *context, Ast *docs, Ast ***asserts)
|
|||||||
SEMA_ERROR(expr, "Only expressions are allowed.");
|
SEMA_ERROR(expr, "Only expressions are allowed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!sema_analyse_expr_of_required_type(context, type_bool, expr, false)) return false;
|
if (!sema_analyse_cond_expr(context, expr)) return false;
|
||||||
Ast *assert = new_ast(AST_ASSERT_STMT, expr->span);
|
Ast *assert = new_ast(AST_ASSERT_STMT, expr->span);
|
||||||
assert->assert_stmt.expr = expr;
|
assert->assert_stmt.expr = expr;
|
||||||
assert->assert_stmt.message = comment;
|
assert->assert_stmt.message = comment;
|
||||||
@@ -2243,12 +2286,10 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
|||||||
.current_local = &context->locals[0]
|
.current_local = &context->locals[0]
|
||||||
};
|
};
|
||||||
context->macro_scope = (MacroScope) { 0 };
|
context->macro_scope = (MacroScope) { 0 };
|
||||||
context->failable_return = signature->failable;
|
|
||||||
|
|
||||||
// Clear returns
|
// Clear returns
|
||||||
vec_resize(context->returns, 0);
|
vec_resize(context->returns, 0);
|
||||||
context->scope_id = 0;
|
context->scope_id = 0;
|
||||||
context->expected_block_type = NULL;
|
|
||||||
context->in_volatile_section = 0;
|
context->in_volatile_section = 0;
|
||||||
context->continue_target = 0;
|
context->continue_target = 0;
|
||||||
context->next_target = 0;
|
context->next_target = 0;
|
||||||
@@ -2283,11 +2324,11 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
|||||||
assert(context->active_scope.depth == 1);
|
assert(context->active_scope.depth == 1);
|
||||||
if (!context->active_scope.jump_end)
|
if (!context->active_scope.jump_end)
|
||||||
{
|
{
|
||||||
Type *canonical_rtype = signature->rtype->type->canonical;
|
Type *canonical_rtype = type_no_fail(signature->rtype->type)->canonical;
|
||||||
if (canonical_rtype != type_void)
|
if (canonical_rtype != type_void)
|
||||||
{
|
{
|
||||||
// IMPROVE better pointer to end.
|
// IMPROVE better pointer to end.
|
||||||
SEMA_ERROR(func, "Missing return statement at the end of the function.");
|
SEMA_TOKID_ERROR(func->name_token, "Missing return statement at the end of the function.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,40 +18,34 @@ static inline bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info)
|
|||||||
bool sema_resolve_array_like_len(Context *context, TypeInfo *type_info, ArrayIndex *len_ref)
|
bool sema_resolve_array_like_len(Context *context, TypeInfo *type_info, ArrayIndex *len_ref)
|
||||||
{
|
{
|
||||||
Expr *len_expr = type_info->array.len;
|
Expr *len_expr = type_info->array.len;
|
||||||
if (!sema_analyse_expr(context, type_usize, len_expr)) return type_info_poison(type_info);
|
if (!sema_analyse_expr(context, len_expr)) return type_info_poison(type_info);
|
||||||
|
|
||||||
if (len_expr->expr_kind != EXPR_CONST)
|
if (len_expr->expr_kind != EXPR_CONST)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(len_expr, "Expected a constant value as size.");
|
SEMA_ERROR(len_expr, "Expected a constant value as size.");
|
||||||
return type_info_poison(type_info);
|
return type_info_poison(type_info);
|
||||||
}
|
}
|
||||||
if (!type_is_any_integer(len_expr->type->canonical))
|
if (!type_is_integer(len_expr->type->canonical))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(len_expr, "Expected an integer size.");
|
SEMA_ERROR(len_expr, "Expected an integer size.");
|
||||||
return type_info_poison(type_info);
|
return type_info_poison(type_info);
|
||||||
}
|
}
|
||||||
BigInt *big_len = &len_expr->const_expr.i;
|
|
||||||
bool is_vector = type_info->kind == TYPE_INFO_VECTOR;
|
bool is_vector = type_info->kind == TYPE_INFO_VECTOR;
|
||||||
switch (bigint_cmp_zero(big_len))
|
Int len = len_expr->const_expr.ixx;
|
||||||
|
if (int_is_neg(len))
|
||||||
{
|
{
|
||||||
case CMP_LT:
|
SEMA_ERROR(len_expr,
|
||||||
SEMA_ERROR(len_expr,
|
is_vector ? "A vector may not have a negative width." :
|
||||||
is_vector ? "A vector may not have a negative width." :
|
"An array may not have a negative size.");
|
||||||
"An array may not have a negative size.");
|
return type_info_poison(type_info);
|
||||||
return type_info_poison(type_info);
|
|
||||||
case CMP_EQ:
|
|
||||||
if (is_vector)
|
|
||||||
{
|
|
||||||
SEMA_ERROR(len_expr, "A vector may not have a zero width.");
|
|
||||||
return type_info_poison(type_info);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CMP_GT:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
BigInt max;
|
if (is_vector && int_is_zero(len))
|
||||||
bigint_init_unsigned(&max, is_vector ? MAX_VECTOR_WIDTH : MAX_ARRAY_SIZE);
|
{
|
||||||
if (bigint_cmp(big_len, &max) == CMP_GT)
|
SEMA_ERROR(len_expr, "A vector may not have a zero width.");
|
||||||
|
return type_info_poison(type_info);
|
||||||
|
}
|
||||||
|
if (int_icomp(len, is_vector ? MAX_VECTOR_WIDTH : MAX_ARRAY_SIZE, BINARYOP_GT))
|
||||||
{
|
{
|
||||||
if (is_vector)
|
if (is_vector)
|
||||||
{
|
{
|
||||||
@@ -63,7 +57,7 @@ bool sema_resolve_array_like_len(Context *context, TypeInfo *type_info, ArrayInd
|
|||||||
}
|
}
|
||||||
return type_info_poison(type_info);
|
return type_info_poison(type_info);
|
||||||
}
|
}
|
||||||
*len_ref = bigint_as_signed(big_len);
|
*len_ref = len.i.low;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +142,11 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
|
|||||||
case DECL_VAR:
|
case DECL_VAR:
|
||||||
if (decl->var.kind == VARDECL_PARAM_CT_TYPE || decl->var.kind == VARDECL_LOCAL_CT_TYPE)
|
if (decl->var.kind == VARDECL_PARAM_CT_TYPE || decl->var.kind == VARDECL_LOCAL_CT_TYPE)
|
||||||
{
|
{
|
||||||
|
if (!decl->var.init_expr)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(type_info, "The variable '%s' is not defined yet.", decl->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
assert(decl->var.init_expr->expr_kind == EXPR_TYPEINFO);
|
assert(decl->var.init_expr->expr_kind == EXPR_TYPEINFO);
|
||||||
assert(decl->var.init_expr->resolve_status == RESOLVE_DONE);
|
assert(decl->var.init_expr->resolve_status == RESOLVE_DONE);
|
||||||
*type_info = *decl->var.init_expr->type_expr;
|
*type_info = *decl->var.init_expr->type_expr;
|
||||||
@@ -213,6 +212,8 @@ bool sema_resolve_type(Context *context, Type *type)
|
|||||||
return sema_resolve_type(context, type->array.base);
|
return sema_resolve_type(context, type->array.base);
|
||||||
case TYPE_VIRTUAL:
|
case TYPE_VIRTUAL:
|
||||||
TODO;
|
TODO;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
return sema_resolve_type(context, type->failable);
|
||||||
}
|
}
|
||||||
return sema_analyse_decl(context, type->decl);
|
return sema_analyse_decl(context, type->decl);
|
||||||
}
|
}
|
||||||
@@ -243,17 +244,13 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow
|
|||||||
case TYPE_INFO_EXPRESSION:
|
case TYPE_INFO_EXPRESSION:
|
||||||
{
|
{
|
||||||
Expr *expr = type_info->unresolved_type_expr;
|
Expr *expr = type_info->unresolved_type_expr;
|
||||||
if (!sema_analyse_expr(context, NULL, expr))
|
if (!sema_analyse_expr(context, expr))
|
||||||
{
|
{
|
||||||
return type_info_poison(type_info);
|
return type_info_poison(type_info);
|
||||||
}
|
}
|
||||||
if (!cast_implicitly_to_runtime(expr))
|
|
||||||
{
|
|
||||||
SEMA_ERROR(expr, "The expression does not fit any runtime type.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
type_info->type = expr->type;
|
type_info->type = expr->type;
|
||||||
type_info->resolve_status = RESOLVE_DONE;
|
type_info->resolve_status = RESOLVE_DONE;
|
||||||
|
assert(!type_info->failable);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TYPE_INFO_INFERRED_ARRAY:
|
case TYPE_INFO_INFERRED_ARRAY:
|
||||||
@@ -272,6 +269,10 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow
|
|||||||
if (!sema_resolve_ptr_type(context, type_info)) return false;
|
if (!sema_resolve_ptr_type(context, type_info)) return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (type_info->failable)
|
||||||
|
{
|
||||||
|
type_info->type = type_get_failable(type_info->type);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ void sema_shadow_error(Decl *decl, Decl *old)
|
|||||||
bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type)
|
bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type)
|
||||||
{
|
{
|
||||||
if (!sema_resolve_type_shallow(context, type_info, allow_inferred_type, false)) return false;
|
if (!sema_resolve_type_shallow(context, type_info, allow_inferred_type, false)) return false;
|
||||||
Type *type = type_info->type;
|
Type *type = type_no_fail(type_info->type);
|
||||||
// usize and similar typedefs will not have a decl.
|
// usize and similar typedefs will not have a decl.
|
||||||
if (type->type_kind == TYPE_TYPEDEF && type->decl == NULL) return true;
|
if (type->type_kind == TYPE_TYPEDEF && type->decl == NULL) return true;
|
||||||
if (!type_is_user_defined(type)) return true;
|
if (!type_is_user_defined(type)) return true;
|
||||||
@@ -95,7 +95,7 @@ Expr *context_pop_defers_and_wrap_expr(Context *context, Expr *expr)
|
|||||||
context_pop_defers_to(context, &defers);
|
context_pop_defers_to(context, &defers);
|
||||||
if (defers.end == defers.start) return expr;
|
if (defers.end == defers.start) return expr;
|
||||||
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
|
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
|
||||||
expr_copy_types(wrap, expr);
|
wrap->type = expr->type;
|
||||||
wrap->resolve_status = RESOLVE_DONE;
|
wrap->resolve_status = RESOLVE_DONE;
|
||||||
wrap->expr_scope.expr = expr;
|
wrap->expr_scope.expr = expr;
|
||||||
wrap->expr_scope.defers = defers;
|
wrap->expr_scope.defers = defers;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ static struct
|
|||||||
Type f16, f32, f64, f128, fxx;
|
Type f16, f32, f64, f128, fxx;
|
||||||
Type usz, isz, uptr, iptr, uptrdiff, iptrdiff;
|
Type usz, isz, uptr, iptr, uptrdiff, iptrdiff;
|
||||||
Type voidstar, typeid, anyerr, typeinfo, ctlist;
|
Type voidstar, typeid, anyerr, typeinfo, ctlist;
|
||||||
Type str, virtual, virtual_generic;
|
Type str, virtual, virtual_generic, anyfail;
|
||||||
} t;
|
} t;
|
||||||
|
|
||||||
Type *type_bool = &t.u1;
|
Type *type_bool = &t.u1;
|
||||||
@@ -47,6 +47,7 @@ Type *type_compfloat = &t.fxx;
|
|||||||
Type *type_compstr = &t.str;
|
Type *type_compstr = &t.str;
|
||||||
Type *type_anyerr = &t.anyerr;
|
Type *type_anyerr = &t.anyerr;
|
||||||
Type *type_complist = &t.ctlist;
|
Type *type_complist = &t.ctlist;
|
||||||
|
Type *type_anyfail = &t.anyfail;
|
||||||
|
|
||||||
static unsigned size_subarray;
|
static unsigned size_subarray;
|
||||||
static AlignSize alignment_subarray;
|
static AlignSize alignment_subarray;
|
||||||
@@ -57,7 +58,8 @@ static AlignSize max_alignment_vector;
|
|||||||
#define PTR_OFFSET 0
|
#define PTR_OFFSET 0
|
||||||
#define INFERRED_ARRAY_OFFSET 1
|
#define INFERRED_ARRAY_OFFSET 1
|
||||||
#define SUB_ARRAY_OFFSET 2
|
#define SUB_ARRAY_OFFSET 2
|
||||||
#define ARRAY_OFFSET 3
|
#define FAILABLE_OFFSET 3
|
||||||
|
#define ARRAY_OFFSET 4
|
||||||
|
|
||||||
Type *type_cint(void)
|
Type *type_cint(void)
|
||||||
{
|
{
|
||||||
@@ -144,6 +146,10 @@ const char *type_to_error_string(Type *type)
|
|||||||
}
|
}
|
||||||
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
|
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
|
||||||
return buffer;
|
return buffer;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
if (!type->failable) return "void!";
|
||||||
|
asprintf(&buffer, "%s!", type_to_error_string(type->failable));
|
||||||
|
return buffer;
|
||||||
case TYPE_STRLIT:
|
case TYPE_STRLIT:
|
||||||
return "string literal";
|
return "string literal";
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
@@ -187,12 +193,15 @@ void type_append_signature_name(Type *type, char *dst, size_t *offset)
|
|||||||
|
|
||||||
ByteSize type_size(Type *type)
|
ByteSize type_size(Type *type)
|
||||||
{
|
{
|
||||||
|
RETRY:
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
return type_size(type->decl->bitstruct.base_type->type);
|
type = type->decl->bitstruct.base_type->type;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
return type_size(type->decl->distinct_decl.base_type);
|
type = type->decl->distinct_decl.base_type;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_VECTOR:
|
case TYPE_VECTOR:
|
||||||
{
|
{
|
||||||
ByteSize width = type_size(type->vector.base) * type->vector.len;
|
ByteSize width = type_size(type->vector.base) * type->vector.len;
|
||||||
@@ -205,10 +214,16 @@ ByteSize type_size(Type *type)
|
|||||||
}
|
}
|
||||||
case CT_TYPES:
|
case CT_TYPES:
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
type = type->failable;
|
||||||
|
if (!type) return 1;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
return type_size(type->canonical);
|
type = type->canonical;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_ERRTYPE:
|
case TYPE_ERRTYPE:
|
||||||
return type_size(type_usize->canonical);
|
type = type_iptr->canonical;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
return type->decl->enums.type_info->type->canonical->builtin.bytesize;
|
return type->decl->enums.type_info->type->canonical->builtin.bytesize;
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
@@ -229,7 +244,7 @@ ByteSize type_size(Type *type)
|
|||||||
case TYPE_STRLIT:
|
case TYPE_STRLIT:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
return t.usz.canonical->builtin.bytesize;
|
return t.iptr.canonical->builtin.bytesize;
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
return type_size(type->array.base) * type->array.len;
|
return type_size(type->array.base) * type->array.len;
|
||||||
case TYPE_SUBARRAY:
|
case TYPE_SUBARRAY:
|
||||||
@@ -332,16 +347,22 @@ Type *type_abi_find_single_struct_element(Type *type)
|
|||||||
|
|
||||||
bool type_is_abi_aggregate(Type *type)
|
bool type_is_abi_aggregate(Type *type)
|
||||||
{
|
{
|
||||||
|
RETRY:
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
case TYPE_POISONED:
|
case TYPE_POISONED:
|
||||||
return false;
|
return false;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
type = type->failable;
|
||||||
|
if (!type) return false;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
return type_is_abi_aggregate(type->decl->distinct_decl.base_type);
|
type = type->decl->distinct_decl.base_type;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
return type_is_abi_aggregate(type->canonical);
|
type = type->canonical;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
return type_is_abi_aggregate(type->decl->bitstruct.base_type->type);
|
|
||||||
case ALL_FLOATS:
|
case ALL_FLOATS:
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
case ALL_INTS:
|
case ALL_INTS:
|
||||||
@@ -495,14 +516,16 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
|
|||||||
RETRY:
|
RETRY:
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
type = type->failable;
|
||||||
|
if (!type) return false;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
type = type->decl->distinct_decl.base_type;
|
type = type->decl->distinct_decl.base_type;
|
||||||
goto RETRY;
|
goto RETRY;
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
type = type->decl->bitstruct.base_type->type;
|
type = type->decl->bitstruct.base_type->type;
|
||||||
goto RETRY;
|
goto RETRY;
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_IXX:
|
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
@@ -584,7 +607,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
|
|||||||
type = type_int_unsigned_by_bitsize(type->builtin.bitsize);
|
type = type_int_unsigned_by_bitsize(type->builtin.bitsize);
|
||||||
break;
|
break;
|
||||||
case ALL_UNSIGNED_INTS:
|
case ALL_UNSIGNED_INTS:
|
||||||
case ALL_REAL_FLOATS:
|
case ALL_FLOATS:
|
||||||
case TYPE_VECTOR:
|
case TYPE_VECTOR:
|
||||||
break;
|
break;
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
@@ -700,6 +723,7 @@ bool type_is_comparable(Type *type)
|
|||||||
|
|
||||||
AlignSize type_abi_alignment(Type *type)
|
AlignSize type_abi_alignment(Type *type)
|
||||||
{
|
{
|
||||||
|
RETRY:
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
case TYPE_POISONED:
|
case TYPE_POISONED:
|
||||||
@@ -707,7 +731,8 @@ AlignSize type_abi_alignment(Type *type)
|
|||||||
case TYPE_UNTYPED_LIST:
|
case TYPE_UNTYPED_LIST:
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
return type_abi_alignment(type->decl->bitstruct.base_type->type);
|
type = type->decl->bitstruct.base_type->type;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_VECTOR:
|
case TYPE_VECTOR:
|
||||||
{
|
{
|
||||||
ByteSize width = type_size(type->vector.base) * type->vector.len;
|
ByteSize width = type_size(type->vector.base) * type->vector.len;
|
||||||
@@ -721,10 +746,16 @@ AlignSize type_abi_alignment(Type *type)
|
|||||||
}
|
}
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
return 1;
|
return 1;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
type = type->failable;
|
||||||
|
if (!type) return 1;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
return type_abi_alignment(type->decl->distinct_decl.base_type);
|
type = type->decl->distinct_decl.base_type;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
return type_abi_alignment(type->canonical);
|
type = type->canonical;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
return type->decl->enums.type_info->type->canonical->builtin.abi_alignment;
|
return type->decl->enums.type_info->type->canonical->builtin.abi_alignment;
|
||||||
case TYPE_ERRTYPE:
|
case TYPE_ERRTYPE:
|
||||||
@@ -732,8 +763,6 @@ AlignSize type_abi_alignment(Type *type)
|
|||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
case TYPE_UNION:
|
case TYPE_UNION:
|
||||||
return type->decl->alignment;
|
return type->decl->alignment;
|
||||||
case TYPE_TYPEID:
|
|
||||||
return type_abi_alignment(type_usize);
|
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
case ALL_INTS:
|
case ALL_INTS:
|
||||||
case ALL_FLOATS:
|
case ALL_FLOATS:
|
||||||
@@ -745,10 +774,12 @@ AlignSize type_abi_alignment(Type *type)
|
|||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
case TYPE_STRLIT:
|
case TYPE_STRLIT:
|
||||||
|
case TYPE_TYPEID:
|
||||||
return t.iptr.canonical->builtin.abi_alignment;
|
return t.iptr.canonical->builtin.abi_alignment;
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
return type_abi_alignment(type->array.base);
|
type = type->array.base;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_SUBARRAY:
|
case TYPE_SUBARRAY:
|
||||||
return alignment_subarray;
|
return alignment_subarray;
|
||||||
}
|
}
|
||||||
@@ -789,6 +820,30 @@ static Type *type_generate_ptr(Type *ptr_type, bool canonical)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Type *type_generate_failable(Type *failable_type, bool canonical)
|
||||||
|
{
|
||||||
|
if (canonical) failable_type = failable_type->canonical;
|
||||||
|
if (!failable_type->type_cache)
|
||||||
|
{
|
||||||
|
create_type_cache(failable_type);
|
||||||
|
}
|
||||||
|
Type *failable = failable_type->type_cache[FAILABLE_OFFSET];
|
||||||
|
if (failable == NULL)
|
||||||
|
{
|
||||||
|
failable = type_new(TYPE_FAILABLE, strformat("%s!", failable_type->name));
|
||||||
|
failable->pointer = failable_type;
|
||||||
|
failable_type->type_cache[FAILABLE_OFFSET] = failable;
|
||||||
|
if (failable_type == failable_type->canonical)
|
||||||
|
{
|
||||||
|
failable->canonical = failable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
failable->canonical = type_generate_failable(failable_type->canonical, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return failable;
|
||||||
|
}
|
||||||
|
|
||||||
static Type *type_generate_subarray(Type *arr_type, bool canonical)
|
static Type *type_generate_subarray(Type *arr_type, bool canonical)
|
||||||
{
|
{
|
||||||
@@ -843,12 +898,28 @@ static Type *type_generate_inferred_array(Type *arr_type, bool canonical)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Type *type_get_ptr_recurse(Type *ptr_type)
|
||||||
|
{
|
||||||
|
if (ptr_type->type_kind == TYPE_FAILABLE)
|
||||||
|
{
|
||||||
|
ptr_type = ptr_type->failable;
|
||||||
|
return type_get_failable(type_get_ptr(ptr_type));
|
||||||
|
}
|
||||||
|
return type_get_ptr(ptr_type);
|
||||||
|
|
||||||
|
}
|
||||||
Type *type_get_ptr(Type *ptr_type)
|
Type *type_get_ptr(Type *ptr_type)
|
||||||
{
|
{
|
||||||
|
assert(ptr_type->type_kind != TYPE_FAILABLE);
|
||||||
return type_generate_ptr(ptr_type, false);
|
return type_generate_ptr(ptr_type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *type_get_failable(Type *failable_type)
|
||||||
|
{
|
||||||
|
assert(failable_type->type_kind != TYPE_FAILABLE);
|
||||||
|
return type_generate_failable(failable_type, false);
|
||||||
|
}
|
||||||
|
|
||||||
Type *type_get_subarray(Type *arr_type)
|
Type *type_get_subarray(Type *arr_type)
|
||||||
{
|
{
|
||||||
return type_generate_subarray(arr_type, false);
|
return type_generate_subarray(arr_type, false);
|
||||||
@@ -1050,9 +1121,8 @@ bool type_is_valid_for_vector(Type *type)
|
|||||||
RETRY:
|
RETRY:
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
{
|
{
|
||||||
case ALL_SIGNED_INTS:
|
case ALL_INTS:
|
||||||
case ALL_UNSIGNED_INTS:
|
case ALL_FLOATS:
|
||||||
case ALL_REAL_FLOATS:
|
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
return true;
|
return true;
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
@@ -1143,6 +1213,17 @@ static void type_append_name_to_scratch(Type *type)
|
|||||||
type_append_name_to_scratch(type->pointer);
|
type_append_name_to_scratch(type->pointer);
|
||||||
scratch_buffer_append_char('*');
|
scratch_buffer_append_char('*');
|
||||||
break;
|
break;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
if (type->failable)
|
||||||
|
{
|
||||||
|
type_append_name_to_scratch(type->failable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scratch_buffer_append("void");
|
||||||
|
}
|
||||||
|
scratch_buffer_append_char('!');
|
||||||
|
break;
|
||||||
case TYPE_SUBARRAY:
|
case TYPE_SUBARRAY:
|
||||||
type_append_name_to_scratch(type->pointer);
|
type_append_name_to_scratch(type->pointer);
|
||||||
scratch_buffer_append("[]");
|
scratch_buffer_append("[]");
|
||||||
@@ -1168,8 +1249,6 @@ static void type_append_name_to_scratch(Type *type)
|
|||||||
case TYPE_VECTOR:
|
case TYPE_VECTOR:
|
||||||
scratch_buffer_append(type->name);
|
scratch_buffer_append(type->name);
|
||||||
break;
|
break;
|
||||||
case TYPE_IXX:
|
|
||||||
case TYPE_FXX:
|
|
||||||
case TYPE_STRLIT:
|
case TYPE_STRLIT:
|
||||||
case TYPE_UNTYPED_LIST:
|
case TYPE_UNTYPED_LIST:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
@@ -1191,7 +1270,6 @@ Type *type_find_function_type(FunctionSignature *signature)
|
|||||||
{
|
{
|
||||||
scratch_buffer_clear();
|
scratch_buffer_clear();
|
||||||
type_append_name_to_scratch(signature->rtype->type);
|
type_append_name_to_scratch(signature->rtype->type);
|
||||||
if (signature->failable) scratch_buffer_append_char('!');
|
|
||||||
scratch_buffer_append_char('(');
|
scratch_buffer_append_char('(');
|
||||||
unsigned elements = vec_size(signature->params);
|
unsigned elements = vec_size(signature->params);
|
||||||
for (unsigned i = 0; i < elements; i++)
|
for (unsigned i = 0; i < elements; i++)
|
||||||
@@ -1267,6 +1345,7 @@ void type_setup(PlatformTarget *target)
|
|||||||
|
|
||||||
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1);
|
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1);
|
||||||
type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1);
|
type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1);
|
||||||
|
t.anyfail = (Type){ .type_kind = TYPE_FAILABLE, .failable = type_void };
|
||||||
type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer);
|
type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer);
|
||||||
|
|
||||||
type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer);
|
type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer);
|
||||||
@@ -1276,8 +1355,6 @@ void type_setup(PlatformTarget *target)
|
|||||||
type_init("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer);
|
type_init("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer);
|
||||||
type_init("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer);
|
type_init("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer);
|
||||||
|
|
||||||
type_create("compint", &t.ixx, TYPE_IXX, 1, 1, 1);
|
|
||||||
type_create("compfloat", &t.fxx, TYPE_FXX, 1, 1, 1);
|
|
||||||
|
|
||||||
type_create_alias("usize", &t.usz, type_int_unsigned_by_bitsize(target->width_pointer));
|
type_create_alias("usize", &t.usz, type_int_unsigned_by_bitsize(target->width_pointer));
|
||||||
type_create_alias("isize", &t.isz, type_int_signed_by_bitsize(target->width_pointer));
|
type_create_alias("isize", &t.isz, type_int_signed_by_bitsize(target->width_pointer));
|
||||||
@@ -1293,6 +1370,33 @@ void type_setup(PlatformTarget *target)
|
|||||||
type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer);
|
type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int type_kind_bitsize(TypeKind kind)
|
||||||
|
{
|
||||||
|
switch (kind)
|
||||||
|
{
|
||||||
|
case TYPE_I8:
|
||||||
|
case TYPE_U8:
|
||||||
|
return 8;
|
||||||
|
case TYPE_I16:
|
||||||
|
case TYPE_U16:
|
||||||
|
case TYPE_F16:
|
||||||
|
return 16;
|
||||||
|
case TYPE_I32:
|
||||||
|
case TYPE_U32:
|
||||||
|
case TYPE_F32:
|
||||||
|
return 32;
|
||||||
|
case TYPE_I64:
|
||||||
|
case TYPE_U64:
|
||||||
|
case TYPE_F64:
|
||||||
|
return 64;
|
||||||
|
case TYPE_I128:
|
||||||
|
case TYPE_U128:
|
||||||
|
case TYPE_F128:
|
||||||
|
return 128;
|
||||||
|
default:
|
||||||
|
UNREACHABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
bool type_is_scalar(Type *type)
|
bool type_is_scalar(Type *type)
|
||||||
{
|
{
|
||||||
RETRY:
|
RETRY:
|
||||||
@@ -1326,6 +1430,10 @@ bool type_is_scalar(Type *type)
|
|||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
type = type->decl->distinct_decl.base_type;
|
type = type->decl->distinct_decl.base_type;
|
||||||
goto RETRY;
|
goto RETRY;
|
||||||
|
case TYPE_FAILABLE:
|
||||||
|
type = type->failable;
|
||||||
|
if (!type) return false;
|
||||||
|
goto RETRY;
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
type = type->canonical;
|
type = type->canonical;
|
||||||
goto RETRY;
|
goto RETRY;
|
||||||
@@ -1412,46 +1520,6 @@ Type *type_from_token(TokenType type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool type_may_convert_to_boolean(Type *type)
|
|
||||||
{
|
|
||||||
RETRY:
|
|
||||||
switch (type->type_kind)
|
|
||||||
{
|
|
||||||
case TYPE_POISONED:
|
|
||||||
return false;
|
|
||||||
case TYPE_TYPEDEF:
|
|
||||||
type = type->canonical;
|
|
||||||
goto RETRY;
|
|
||||||
case TYPE_DISTINCT:
|
|
||||||
type = type->decl->distinct_decl.base_type;
|
|
||||||
goto RETRY;
|
|
||||||
case ALL_INTS:
|
|
||||||
case ALL_FLOATS:
|
|
||||||
case TYPE_POINTER:
|
|
||||||
case TYPE_VIRTUAL:
|
|
||||||
case TYPE_VIRTUAL_ANY:
|
|
||||||
case TYPE_BOOL:
|
|
||||||
case TYPE_SUBARRAY:
|
|
||||||
case TYPE_ENUM:
|
|
||||||
case TYPE_ANYERR:
|
|
||||||
case TYPE_ERRTYPE:
|
|
||||||
case TYPE_STRLIT:
|
|
||||||
case TYPE_UNTYPED_LIST:
|
|
||||||
return true;
|
|
||||||
case TYPE_FUNC:
|
|
||||||
case TYPE_ARRAY:
|
|
||||||
case TYPE_INFERRED_ARRAY:
|
|
||||||
case TYPE_BITSTRUCT:
|
|
||||||
case TYPE_VECTOR:
|
|
||||||
case TYPE_STRUCT:
|
|
||||||
case TYPE_TYPEID:
|
|
||||||
case TYPE_TYPEINFO:
|
|
||||||
case TYPE_UNION:
|
|
||||||
case TYPE_VOID:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
UNREACHABLE
|
|
||||||
}
|
|
||||||
bool type_may_have_sub_elements(Type *type)
|
bool type_may_have_sub_elements(Type *type)
|
||||||
{
|
{
|
||||||
// An alias is not ok.
|
// An alias is not ok.
|
||||||
@@ -1476,15 +1544,13 @@ Type *type_find_max_num_type(Type *num_type, Type *other_num)
|
|||||||
assert(kind != other_kind);
|
assert(kind != other_kind);
|
||||||
|
|
||||||
// 1. The only conversions need to happen if the other type is a number.
|
// 1. The only conversions need to happen if the other type is a number.
|
||||||
if (other_kind < TYPE_I8 || other_kind > TYPE_FXX) return NULL;
|
if (other_kind < TYPE_INTEGER_FIRST || other_kind > TYPE_FLOAT_LAST) return NULL;
|
||||||
|
|
||||||
// 2. First check the float case.
|
// 2. First check the float case.
|
||||||
if (other_kind >= TYPE_F16 && other_kind <= TYPE_FXX)
|
if (other_kind >= TYPE_FLOAT_FIRST && other_kind <= TYPE_FLOAT_LAST)
|
||||||
{
|
{
|
||||||
switch (other_kind)
|
switch (other_kind)
|
||||||
{
|
{
|
||||||
case TYPE_FXX:
|
|
||||||
return kind <= TYPE_IXX ? type_double : num_type;
|
|
||||||
case TYPE_F16:
|
case TYPE_F16:
|
||||||
case TYPE_F32:
|
case TYPE_F32:
|
||||||
case TYPE_F64:
|
case TYPE_F64:
|
||||||
@@ -1499,9 +1565,6 @@ Type *type_find_max_num_type(Type *num_type, Type *other_num)
|
|||||||
// Handle integer <=> integer conversions.
|
// Handle integer <=> integer conversions.
|
||||||
assert(type_kind_is_any_integer(other_kind) && type_is_integer(num_type));
|
assert(type_kind_is_any_integer(other_kind) && type_is_integer(num_type));
|
||||||
|
|
||||||
// 3. If the other type is IXX, return the current type.
|
|
||||||
if (other_kind == TYPE_IXX) return num_type;
|
|
||||||
|
|
||||||
// 4. Check the bit sizes.
|
// 4. Check the bit sizes.
|
||||||
unsigned other_bit_size = other_num->builtin.bitsize;
|
unsigned other_bit_size = other_num->builtin.bitsize;
|
||||||
unsigned bit_size = num_type->builtin.bitsize;
|
unsigned bit_size = num_type->builtin.bitsize;
|
||||||
@@ -1574,8 +1637,20 @@ static inline Type *type_find_max_ptr_type(Type *type, Type *other)
|
|||||||
|
|
||||||
Type *type_find_max_type(Type *type, Type *other)
|
Type *type_find_max_type(Type *type, Type *other)
|
||||||
{
|
{
|
||||||
assert(type->canonical == type);
|
if (type == type_anyfail)
|
||||||
assert(other->canonical == other);
|
{
|
||||||
|
return type_get_opt_fail(other, true);
|
||||||
|
}
|
||||||
|
if (other == type_anyfail)
|
||||||
|
{
|
||||||
|
return type_get_failable(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
type = type->canonical;
|
||||||
|
other = other->canonical;
|
||||||
|
|
||||||
|
assert(type->type_kind != TYPE_FAILABLE && other->type_kind != TYPE_FAILABLE);
|
||||||
|
|
||||||
if (type == other) return type;
|
if (type == other) return type;
|
||||||
|
|
||||||
// Sort types
|
// Sort types
|
||||||
@@ -1590,6 +1665,7 @@ Type *type_find_max_type(Type *type, Type *other)
|
|||||||
{
|
{
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
case TYPE_POISONED:
|
case TYPE_POISONED:
|
||||||
|
case TYPE_FAILABLE:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
@@ -1598,17 +1674,12 @@ Type *type_find_max_type(Type *type, Type *other)
|
|||||||
case TYPE_VIRTUAL_ANY:
|
case TYPE_VIRTUAL_ANY:
|
||||||
case TYPE_BITSTRUCT:
|
case TYPE_BITSTRUCT:
|
||||||
return NULL;
|
return NULL;
|
||||||
case TYPE_IXX:
|
case ALL_INTS:
|
||||||
if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other;
|
if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other;
|
||||||
FALLTHROUGH;
|
|
||||||
case ALL_SIGNED_INTS:
|
|
||||||
case ALL_UNSIGNED_INTS:
|
|
||||||
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
|
if (other->type_kind == TYPE_ENUM) return type_find_max_type(type, other->decl->enums.type_info->type->canonical);
|
||||||
return type_find_max_num_type(type, other);
|
return type_find_max_num_type(type, other);
|
||||||
case TYPE_FXX:
|
case ALL_FLOATS:
|
||||||
if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other;
|
if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct_decl.base_type)) return other;
|
||||||
FALLTHROUGH;
|
|
||||||
case ALL_REAL_FLOATS:
|
|
||||||
return type_find_max_num_type(type, other);
|
return type_find_max_num_type(type, other);
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
return type_find_max_ptr_type(type, other);
|
return type_find_max_ptr_type(type, other);
|
||||||
@@ -1664,7 +1735,7 @@ Type *type_find_common_ancestor(Type *left, Type *right)
|
|||||||
if (left->type_kind == TYPE_POINTER)
|
if (left->type_kind == TYPE_POINTER)
|
||||||
{
|
{
|
||||||
Type *common = type_find_common_ancestor(left->pointer, right->pointer);
|
Type *common = type_find_common_ancestor(left->pointer, right->pointer);
|
||||||
return common ? type_generate_ptr(common, true) : NULL;
|
return common ? type_get_ptr(common) : NULL;
|
||||||
}
|
}
|
||||||
if (left->type_kind != TYPE_STRUCT) return NULL;
|
if (left->type_kind != TYPE_STRUCT) return NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "benchmark.h"
|
#include "benchmark.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void test_file(void)
|
void test_file(void)
|
||||||
{
|
{
|
||||||
File file;
|
File file;
|
||||||
@@ -37,12 +36,160 @@ void test_file(void)
|
|||||||
TEST_ASSERT(source_file_find_position_in_file(&file, 21).line == 3, "Expected third line");
|
TEST_ASSERT(source_file_find_position_in_file(&file, 21).line == 3, "Expected third line");
|
||||||
TEST_ASSERT(source_file_find_position_in_file(&file, 25).line == 3, "Expected third line");
|
TEST_ASSERT(source_file_find_position_in_file(&file, 25).line == 3, "Expected third line");
|
||||||
TEST_ASSERT(source_file_find_position_in_file(&file, 31).line == 4, "Expected fourth line");
|
TEST_ASSERT(source_file_find_position_in_file(&file, 31).line == 4, "Expected fourth line");
|
||||||
|
}
|
||||||
|
#define i128(x_, y_) ((Int128){x_, y_})
|
||||||
|
void test128()
|
||||||
|
{
|
||||||
|
printf("Begin i128 testing.\n");
|
||||||
|
Int128 addres = i128_add(i128(0x123, 0x123), i128(0x222, 0x333));
|
||||||
|
TEST_ASSERTF(addres.high == 0x345 && addres.low == 0x456, "i128 add failed with small numbers was %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_add(i128(0x123, UINT64_MAX), i128(0x222, 0x1));
|
||||||
|
TEST_ASSERT(addres.high == 0x346 && addres.low == 0, "i128 add failed with simple overflow");
|
||||||
|
addres = i128_add(i128(0x123, UINT64_MAX), i128(0x222, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == 0x346 && addres.low == UINT64_MAX - 1, "i128 add failed with simple overflow2");
|
||||||
|
addres = i128_add(i128(UINT64_MAX, UINT64_MAX), i128(0x0, 0x1));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "i128 add failed with wrap");
|
||||||
|
addres = i128_add(i128(UINT64_MAX, UINT64_MAX), i128(UINT64_MAX, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX - 1, "i128 add failed overflow with wrap");
|
||||||
|
printf("-- i128 Add - Ok.\n");
|
||||||
|
addres = i128_sub(i128(0x345, 0x457), i128(0x222, 0x333));
|
||||||
|
TEST_ASSERTF(addres.high == 0x123 && addres.low == 0x124, "i128 sub failed with small numbers was %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_sub(i128(0x346, 0), i128(0x222, 0x1));
|
||||||
|
TEST_ASSERTF(addres.high == 0x123 && addres.low == UINT64_MAX, "i128 sub failed with simple overflow %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_sub(i128(0x346, UINT64_MAX - 1), i128(0x222, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == 0x123 && addres.low == UINT64_MAX, "i128 sub failed with simple overflow2");
|
||||||
|
addres = i128_sub(i128(0, 0), i128(0x0, 0x1));
|
||||||
|
TEST_ASSERTF(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "i128 sub failed with wrap %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_sub(i128(UINT64_MAX, UINT64_MAX - 1), i128(UINT64_MAX, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "i128 sub failed overflow with wrap");
|
||||||
|
printf("-- i128 Sub - Ok.\n");
|
||||||
|
addres = i128_and(i128(0x0, 0x0), i128(UINT64_MAX, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "And failed");
|
||||||
|
addres = i128_and(i128(0x123, 0x123456789abcdef1), i128(UINT64_MAX, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == 0x123 && addres.low == 0x123456789abcdef1, "And failed");
|
||||||
|
addres = i128_and(i128(0xabcdef2233, 0x123456789A), i128(0x0F0F0F0F0F0F, 0xF0F0F0F0F0F0));
|
||||||
|
TEST_ASSERT(addres.high == 0x0b0d0f0203 && addres.low == 0x1030507090, "And failed");
|
||||||
|
printf("-- i128 And - Ok.\n");
|
||||||
|
addres = i128_or(i128(0x0, 0x0), i128(UINT64_MAX, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "Or failed");
|
||||||
|
addres = i128_or(i128(0x123, 0x123456789abcdef1), i128(0x123203, 0x0));
|
||||||
|
TEST_ASSERT(addres.high == 0x123323 && addres.low == 0x123456789abcdef1, "Or failed");
|
||||||
|
addres = i128_or(i128(0xabcdef2233, 0x123456789A), i128(0x0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0));
|
||||||
|
TEST_ASSERTF(addres.high == 0x0FAFCFEF2F3F && addres.low == 0xF0F0F2F4F6F8FA, "Or failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Or - Ok.\n");
|
||||||
|
addres = i128_xor(i128(0x0, 0x0), i128(UINT64_MAX, UINT64_MAX));
|
||||||
|
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "Xor failed");
|
||||||
|
addres = i128_xor(i128(0x123, 0x123456789abcdef1), i128(0x123223, 0x0));
|
||||||
|
TEST_ASSERT(addres.high == 0x123300 && addres.low == 0x123456789abcdef1, "Xor failed");
|
||||||
|
addres = i128_xor(i128(0xabcdef2233, 0x123456789A), i128(0x0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0));
|
||||||
|
TEST_ASSERTF(addres.high == 0x0FA4C2E02d3c && addres.low == 0xF0F0e2c4a6886A, "Xor failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Xor - Ok.\n");
|
||||||
|
addres = i128_neg(i128(0x0, 0x0));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "Neg failed");
|
||||||
|
addres = i128_neg(i128(0x123, 0x123456789abcdef1));
|
||||||
|
TEST_ASSERT(addres.high == ~((uint64_t)0x123) && addres.low == ~(uint64_t)0x123456789abcdef0, "Neg failed");
|
||||||
|
addres = i128_neg(i128(0xabcdef2233, 0x123456789A));
|
||||||
|
TEST_ASSERTF(addres.high == ~(uint64_t)0xabcdef2233 && addres.low == ~(uint64_t)0x1234567899, "Neg failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Neg - Ok.\n");
|
||||||
|
|
||||||
|
addres = i128_from_str("1123");
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 1123, "Init failed");
|
||||||
|
addres = i128_from_str("10000000000000000000012344434232");
|
||||||
|
TEST_ASSERT(addres.high == 0x7e37be2022 && addres.low == 0xc0914b295fc91e38, "Init failed");
|
||||||
|
|
||||||
|
addres = i128_mult(i128(0x111, 0x222), i128(0, 2));
|
||||||
|
TEST_ASSERTF(addres.high == 0x222 && addres.low == 0x444, "Mult failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_mult(i128(0x111, 0x222), i128(2, 0));
|
||||||
|
TEST_ASSERTF(addres.high == 0x444 && addres.low == 0, "Mult failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_mult(i128_from_str("523871293871232000123"), i128_from_str("283712312938293299"));
|
||||||
|
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128_from_str("148628736466183585621117368965778075777"), addres) == CMP_EQ, "Mult failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Mult ok.\n");
|
||||||
|
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128_from_str("123"), i128_from_str("123")) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128_from_str("123"), i128_from_str("124")) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128_from_str("123"), i128_from_str("121")) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128(0x222, 0x111), i128(0x111, 0x222)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128(0x111, 0x222), i128(0x222, 0x111)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128(0x222, 0x111), i128(0x222, 0x111)) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128(UINT64_MAX, 0x111), i128(0x111, 0x222)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_ucomp(i128(0x111, 0x222), i128(UINT64_MAX, 0x111)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Ucomp ok.\n");
|
||||||
|
|
||||||
|
TEST_ASSERTF(i128_scomp(i128_from_str("123"), i128_from_str("123")) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_scomp(i128_from_str("123"), i128_from_str("124")) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_scomp(i128_from_str("123"), i128_from_str("121")) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_scomp(i128(0x222, 0x111), i128(0x111, 0x222)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_scomp(i128(0x111, 0x222), i128(0x222, 0x111)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_scomp(i128(0x222, 0x111), i128(0x222, 0x111)) == CMP_EQ, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_scomp(i128(UINT64_MAX, 0x111), i128(0x111, 0x222)) == CMP_LT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
TEST_ASSERTF(i128_scomp(i128(0x111, 0x222), i128(UINT64_MAX, 0x111)) == CMP_GT, "Comp failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Scomp ok.\n");
|
||||||
|
|
||||||
|
|
||||||
|
addres = i128_shl(i128(0x234, 0x123456), i128(0, 0x4));
|
||||||
|
TEST_ASSERT(addres.high == 0x2340 && addres.low == 0x1234560, "shl failed");
|
||||||
|
addres = i128_shl(i128(0x234, 0x1234561), i128(0, 128));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "shl failed");
|
||||||
|
addres = i128_shl(i128(0x234, 0x1234561), i128(1, 1));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "shl failed");
|
||||||
|
addres = i128_shl(i128(0x234, 0x1234561), i128(0, 64));
|
||||||
|
TEST_ASSERT(addres.high == 0x1234561 && addres.low == 0, "shl failed");
|
||||||
|
printf("-- i128 Shl ok.\n");
|
||||||
|
|
||||||
|
addres = i128_lshr(i128(0x234, 0x123456), i128(0, 0x4));
|
||||||
|
TEST_ASSERTF(addres.high == 0x23 && addres.low == 0x4000000000012345, "lshr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_lshr(i128(0x234, 0x1234561), i128(0, 128));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "lshr failed");
|
||||||
|
addres = i128_lshr(i128(0x234, 0x1234561), i128(1, 1));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "lshr failed");
|
||||||
|
addres = i128_lshr(i128(0x234, 0x1234561), i128(0, 64));
|
||||||
|
TEST_ASSERTF(addres.high == 0 && addres.low == 0x234, "lshr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Lshr ok.\n");
|
||||||
|
|
||||||
|
addres = i128_ashr(i128(0x234, 0x123456), i128(0, 0x4));
|
||||||
|
TEST_ASSERTF(addres.high == 0x23 && addres.low == 0x4000000000012345, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_ashr(i128(0xF000000000000234, 0x123456), i128(0, 0x4));
|
||||||
|
TEST_ASSERTF(addres.high == 0xFF00000000000023 && addres.low == 0x4000000000012345, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_ashr(i128(0x234, 0x1234561), i128(0, 128));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "ashr failed");
|
||||||
|
addres = i128_ashr(i128(0xF000000000000234, 0x1234561), i128(0, 128));
|
||||||
|
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "ashr failed");
|
||||||
|
addres = i128_ashr(i128(0x234, 0x1234561), i128(1, 1));
|
||||||
|
TEST_ASSERT(addres.high == 0 && addres.low == 0, "ashr failed");
|
||||||
|
addres = i128_ashr(i128(0xF000000000000234, 0x1234561), i128(1, 1));
|
||||||
|
TEST_ASSERT(addres.high == UINT64_MAX && addres.low == UINT64_MAX, "ashr failed");
|
||||||
|
addres = i128_ashr(i128(0x234, 0x1234561), i128(0, 64));
|
||||||
|
TEST_ASSERTF(addres.high == 0 && addres.low == 0x234, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
addres = i128_ashr(i128(0xF000000000000234, 0x1234561), i128(0, 64));
|
||||||
|
TEST_ASSERTF(addres.high == UINT64_MAX && addres.low == 0xF000000000000234, "ashr failed %llx, %llx", (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Ashr ok.\n");
|
||||||
|
|
||||||
|
TEST_ASSERT(i128_ucomp(i128_udiv(i128_from_str("123"), i128_from_str("123")), i128_from_str("1")) == CMP_EQ, "Div failed");
|
||||||
|
TEST_ASSERT(i128_ucomp(i128_udiv(i128_from_str("123"), i128_from_str("124")), i128_from_str("0")) == CMP_EQ, "Div failed");
|
||||||
|
TEST_ASSERT(i128_ucomp(i128_udiv(i128_from_str("245"), i128_from_str("123")), i128_from_str("1")) == CMP_EQ, "Div failed");
|
||||||
|
addres = i128_udiv(i128(0x12345, UINT64_MAX), i128(1, 0));
|
||||||
|
TEST_ASSERT(addres.low == 0x12345 && addres.high == 0, "Div failed");
|
||||||
|
addres = i128_sdiv(i128(0x12345, UINT64_MAX), i128(1, 0));
|
||||||
|
TEST_ASSERT(addres.low == 0x12345 && addres.high == 0, "Div failed");
|
||||||
|
addres = i128_udiv(i128(UINT64_MAX, 0), i128(1, 0));
|
||||||
|
TEST_ASSERT(addres.low == UINT64_MAX && addres.high == 0, "Div failed");
|
||||||
|
addres = i128_sdiv(i128(UINT64_MAX - 1, UINT64_MAX - 1), i128(1, 0));
|
||||||
|
TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed %s", i128_to_string(addres, 10, true));
|
||||||
|
addres = i128_sdiv(i128(2, 0), i128(UINT64_MAX - 1, UINT64_MAX - 1));
|
||||||
|
printf("-- i128 Div okfefe %x.\n", (unsigned)-2);
|
||||||
|
TEST_ASSERTF(addres.low == UINT64_MAX && addres.high == UINT64_MAX, "Div failed: %s %llx, %llx", i128_to_string(addres, 10, true), (unsigned long long)addres.high, (unsigned long long)addres.low);
|
||||||
|
printf("-- i128 Div ok.\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
void compiler_tests(void)
|
void compiler_tests(void)
|
||||||
{
|
{
|
||||||
symtab_init(0x100000);
|
symtab_init(0x100000);
|
||||||
|
|
||||||
test_file();
|
test_file();
|
||||||
|
test128();
|
||||||
run_arena_allocator_tests();
|
run_arena_allocator_tests();
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|||||||
@@ -43,7 +43,8 @@
|
|||||||
|
|
||||||
#define TODO FATAL_ERROR("TODO reached");
|
#define TODO FATAL_ERROR("TODO reached");
|
||||||
|
|
||||||
#define TEST_ASSERT(_condition, _string, ...) while (!(_condition)) { FATAL_ERROR(_string, ##__VA_ARGS__); }
|
#define TEST_ASSERT(condition_, string_) while (!(condition_)) { FATAL_ERROR(string_); }
|
||||||
|
#define TEST_ASSERTF(condition_, string_, ...) while (!(condition_)) { char* str_; asprintf(&str_, string_, __VA_ARGS__); FATAL_ERROR(str_); }
|
||||||
|
|
||||||
#define EXPECT(_string, _value, _expected) \
|
#define EXPECT(_string, _value, _expected) \
|
||||||
do { long long __tempval1 = _value; long long __tempval2 = _expected; \
|
do { long long __tempval1 = _value; long long __tempval2 = _expected; \
|
||||||
|
|||||||
@@ -250,6 +250,17 @@ static inline bool is_hex(char c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int hex_nibble(char c)
|
||||||
|
{
|
||||||
|
static int conv[256] = {
|
||||||
|
['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4,
|
||||||
|
['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9,
|
||||||
|
['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15,
|
||||||
|
['a'] = 10, ['b'] = 11, ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15,
|
||||||
|
};
|
||||||
|
return conv[(unsigned char)c];
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool is_whitespace(char c)
|
static inline bool is_whitespace(char c)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define COMPILER_VERSION "A238"
|
#define COMPILER_VERSION "A239"
|
||||||
@@ -294,6 +294,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print("Error: Invalid path to tests: " + filepath)
|
print("Error: Invalid path to tests: " + filepath)
|
||||||
usage()
|
usage()
|
||||||
print("Found %d tests: %d / %d passed (%d skipped)." % (conf.numtests, conf.numsuccess, conf.numtests - conf.numskipped, conf.numskipped))
|
|
||||||
|
print("Found %d tests: %.1f%% (%d / %d) passed (%d skipped)." % (conf.numtests, 100 * conf.numsuccess / max(1, conf.numtests - conf.numskipped), conf.numsuccess, conf.numtests - conf.numskipped, conf.numskipped))
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|||||||
6
test/test_suite/attributes/repeat_of_attributes.c3
Normal file
6
test/test_suite/attributes/repeat_of_attributes.c3
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
func void test()
|
||||||
|
{
|
||||||
|
for (int a @align(16) @align(16) = 0 ; a < 10; a++) // #error: Repeat of attribute 'align'
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
15
test/test_suite/compile_time/cttype_reassign.c3t
Normal file
15
test/test_suite/compile_time/cttype_reassign.c3t
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
|
module reassign;
|
||||||
|
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
var $Foo = double;
|
||||||
|
$Foo = int;
|
||||||
|
$Foo hello;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #expect: reassign.ll
|
||||||
|
|
||||||
|
%hello = alloca i32, align 4
|
||||||
|
store i32 0, i32* %hello, align 4
|
||||||
|
ret void
|
||||||
17
test/test_suite/compile_time/not_yet_initialized.c3
Normal file
17
test/test_suite/compile_time/not_yet_initialized.c3
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
macro foo($Foo)
|
||||||
|
{
|
||||||
|
$Foo a;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test1()
|
||||||
|
{
|
||||||
|
var $Bar;
|
||||||
|
@foo($Bar); // #error: '$Bar' is not defined yet
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test2()
|
||||||
|
{
|
||||||
|
var $Bar;
|
||||||
|
$Bar z; // #error: '$Bar' is not defined yet
|
||||||
|
}
|
||||||
@@ -2,13 +2,13 @@ module foo;
|
|||||||
|
|
||||||
func void a()
|
func void a()
|
||||||
{
|
{
|
||||||
$typeof(9146744073709551615) ef;
|
$typeof(9146744073709551615i64) ef;
|
||||||
int fffx = ef; // #error: 'long' to 'int'
|
int fffx = ef; // #error: 'long' to 'int'
|
||||||
}
|
}
|
||||||
|
|
||||||
func void b()
|
func void b()
|
||||||
{
|
{
|
||||||
$typeof(9223372036854775809) ef;
|
$typeof(9223372036854775809u64) ef;
|
||||||
int fffx = ef; // #error: 'ulong' to 'int'
|
int fffx = ef; // #error: 'ulong' to 'int'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
test/test_suite/enumerations/simple_inference.c3t
Normal file
23
test/test_suite/enumerations/simple_inference.c3t
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
|
|
||||||
|
enum HelloEnum
|
||||||
|
{
|
||||||
|
HELLO,
|
||||||
|
WORLD,
|
||||||
|
ELLOWORLD,
|
||||||
|
}
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
HelloEnum h = WORLD;
|
||||||
|
h = ELLOWORLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #expect: simple_inference.ll
|
||||||
|
|
||||||
|
define void @simple_inference.test() #0 {
|
||||||
|
entry:
|
||||||
|
%h = alloca i32, align 4
|
||||||
|
store i32 1, i32* %h, align 4
|
||||||
|
store i32 2, i32* %h, align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
5
test/test_suite/errors/bitshift_failable.c3
Normal file
5
test/test_suite/errors/bitshift_failable.c3
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
func void test()
|
||||||
|
{
|
||||||
|
int! x = 0;
|
||||||
|
int! z = x << 100; // #error: shift exceeds bitsize of 'int'
|
||||||
|
}
|
||||||
124
test/test_suite/errors/failable_taddr_and_access.c3t
Normal file
124
test/test_suite/errors/failable_taddr_and_access.c3t
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
|
|
||||||
|
module test;
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
}
|
||||||
|
|
||||||
|
errtype MyErr
|
||||||
|
{
|
||||||
|
FOO
|
||||||
|
}
|
||||||
|
|
||||||
|
extern func int printf(char *c, ...);
|
||||||
|
|
||||||
|
func void main()
|
||||||
|
{
|
||||||
|
int! z = 2;
|
||||||
|
Foo*! w = &&Foo{ z, 0 };
|
||||||
|
printf("%d\n", w.x);
|
||||||
|
z = MyErr.FOO!;
|
||||||
|
w = &&Foo{ z, 0 };
|
||||||
|
printf("Not visible: %d\n", w.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #expect: test.ll
|
||||||
|
|
||||||
|
%Foo = type { i32, i32 }
|
||||||
|
|
||||||
|
@Foo = linkonce_odr constant i8 1
|
||||||
|
@"test.MyErr$elements" = linkonce_odr constant [1 x i8*] zeroinitializer
|
||||||
|
@MyErr = linkonce_odr constant i8 1
|
||||||
|
@.str = private constant [4 x i8] c"%d\0A\00", align 1
|
||||||
|
@.str.1 = private constant [17 x i8] c"Not visible: %d\0A\00", align 1
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
declare i32 @printf(i8*, ...) #0
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define void @main() #0 {
|
||||||
|
entry:
|
||||||
|
%z = alloca i32, align 4
|
||||||
|
%z.f = alloca i64, align 8
|
||||||
|
%w = alloca %Foo*, align 8
|
||||||
|
%w.f = alloca i64, align 8
|
||||||
|
%literal = alloca %Foo, align 4
|
||||||
|
%literal5 = alloca %Foo, align 4
|
||||||
|
store i64 0, i64* %z.f, align 8
|
||||||
|
store i32 2, i32* %z, align 4
|
||||||
|
store i64 0, i64* %z.f, align 8
|
||||||
|
%0 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 0
|
||||||
|
%1 = load i64, i64* %z.f, align 8
|
||||||
|
%not_err = icmp eq i64 %1, 0
|
||||||
|
br i1 %not_err, label %after_check, label %error
|
||||||
|
|
||||||
|
error: ; preds = %entry
|
||||||
|
store i64 %1, i64* %w.f, align 8
|
||||||
|
br label %after_assign
|
||||||
|
|
||||||
|
after_check: ; preds = %entry
|
||||||
|
%2 = load i32, i32* %z, align 4
|
||||||
|
store i32 %2, i32* %0, align 4
|
||||||
|
%3 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 1
|
||||||
|
store i32 0, i32* %3, align 4
|
||||||
|
store %Foo* %literal, %Foo** %w, align 8
|
||||||
|
store i64 0, i64* %w.f, align 8
|
||||||
|
br label %after_assign
|
||||||
|
|
||||||
|
after_assign: ; preds = %after_check, %error
|
||||||
|
%4 = load i64, i64* %w.f, align 8
|
||||||
|
%not_err1 = icmp eq i64 %4, 0
|
||||||
|
br i1 %not_err1, label %after_check2, label %voiderr
|
||||||
|
|
||||||
|
after_check2: ; preds = %after_assign
|
||||||
|
%5 = load %Foo*, %Foo** %w, align 8
|
||||||
|
%6 = getelementptr inbounds %Foo, %Foo* %5, i32 0, i32 0
|
||||||
|
%7 = load i32, i32* %6, align 8
|
||||||
|
%8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %7)
|
||||||
|
br label %voiderr
|
||||||
|
|
||||||
|
voiderr: ; preds = %after_check2, %after_assign
|
||||||
|
store i64 ptrtoint ([1 x i8*]* @"test.MyErr$elements" to i64), i64* %z.f, align 8
|
||||||
|
br label %after_assign3
|
||||||
|
|
||||||
|
after_assign3: ; preds = %voiderr
|
||||||
|
br label %voiderr4
|
||||||
|
|
||||||
|
voiderr4: ; preds = %after_assign3
|
||||||
|
%9 = getelementptr inbounds %Foo, %Foo* %literal5, i32 0, i32 0
|
||||||
|
%10 = load i64, i64* %z.f, align 8
|
||||||
|
%not_err6 = icmp eq i64 %10, 0
|
||||||
|
br i1 %not_err6, label %after_check8, label %error7
|
||||||
|
|
||||||
|
error7: ; preds = %voiderr4
|
||||||
|
store i64 %10, i64* %w.f, align 8
|
||||||
|
br label %after_assign9
|
||||||
|
|
||||||
|
after_check8: ; preds = %voiderr4
|
||||||
|
%11 = load i32, i32* %z, align 4
|
||||||
|
store i32 %11, i32* %9, align 4
|
||||||
|
%12 = getelementptr inbounds %Foo, %Foo* %literal5, i32 0, i32 1
|
||||||
|
store i32 0, i32* %12, align 4
|
||||||
|
store %Foo* %literal5, %Foo** %w, align 8
|
||||||
|
store i64 0, i64* %w.f, align 8
|
||||||
|
br label %after_assign9
|
||||||
|
|
||||||
|
after_assign9: ; preds = %after_check8, %error7
|
||||||
|
br label %voiderr10
|
||||||
|
|
||||||
|
voiderr10: ; preds = %after_assign9
|
||||||
|
%13 = load i64, i64* %w.f, align 8
|
||||||
|
%not_err11 = icmp eq i64 %13, 0
|
||||||
|
br i1 %not_err11, label %after_check12, label %voiderr13
|
||||||
|
|
||||||
|
after_check12: ; preds = %voiderr10
|
||||||
|
%14 = load %Foo*, %Foo** %w, align 8
|
||||||
|
%15 = getelementptr inbounds %Foo, %Foo* %14, i32 0, i32 0
|
||||||
|
%16 = load i32, i32* %15, align 8
|
||||||
|
%17 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.1, i32 0, i32 0), i32 %16)
|
||||||
|
br label %voiderr13
|
||||||
|
|
||||||
|
voiderr13: ; preds = %after_check12, %voiderr10
|
||||||
|
ret void
|
||||||
|
}
|
||||||
24
test/test_suite/errors/failable_untyped_list.c3
Normal file
24
test/test_suite/errors/failable_untyped_list.c3
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
module test;
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
}
|
||||||
|
|
||||||
|
errtype MyErr
|
||||||
|
{
|
||||||
|
FOO
|
||||||
|
}
|
||||||
|
|
||||||
|
extern func int printf(char *c, ...);
|
||||||
|
|
||||||
|
func void main()
|
||||||
|
{
|
||||||
|
int! z = 2;
|
||||||
|
Foo*! w = &&{ z, 0 }; // #error: casting 'int[2]*' to 'Foo*' is not permitted
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
int! z = 2;
|
||||||
|
Foo*! w = &&Foo!{ z, 0 }; // #error: please remove the '!'
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
func void syntaxErrors()
|
func void syntaxErrors()
|
||||||
{
|
{
|
||||||
int! i = 0;
|
int! i = 0;
|
||||||
while (i + 1) {} // #error: 'int!' cannot be converted into 'bool'
|
while (i + 1) {} // #error: 'int!' cannot be converted to 'bool'
|
||||||
if (i + 1) {} // #error: 'int!' cannot be converted into 'bool'
|
if (i + 1) {} // #error: 'int!' cannot be converted to 'bool'
|
||||||
for (int x = i;;) {} // #error: 'int!' cannot be converted into 'int'.
|
for (int x = i;;) {} // #error: 'int!' cannot be converted to 'int'.
|
||||||
for (int x = 0; x < i + 1;) {} // #error: 'bool!' cannot be converted into 'bool'
|
for (int x = 0; x < i + 1;) {} // #error: 'bool!' cannot be converted to 'bool'
|
||||||
for (int x = 0; x < 10; x += i + 1) {} // #error: 'int!' cannot be converted into 'int'
|
for (int x = 0; x < 10; x += i + 1) {} // #error: 'int!' cannot be converted to 'int'
|
||||||
switch (i + 1) // #error: 'int!' cannot be converted into 'int'
|
switch (i + 1) // #error: 'int!' cannot be converted to 'int'
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
i + 1;
|
i + 1;
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ entry:
|
|||||||
%a.f = alloca i64, align 8
|
%a.f = alloca i64, align 8
|
||||||
%err = alloca i64, align 8
|
%err = alloca i64, align 8
|
||||||
%retparam = alloca i32, align 4
|
%retparam = alloca i32, align 4
|
||||||
store i64 0, i64* %a.f, align 8
|
|
||||||
store i32 123, i32* %a, align 4
|
store i32 123, i32* %a, align 4
|
||||||
store i64 0, i64* %a.f, align 8
|
store i64 0, i64* %a.f, align 8
|
||||||
br label %testblock
|
br label %testblock
|
||||||
|
|||||||
@@ -88,6 +88,6 @@ func void test10()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int g = a; // #error: 'int!' cannot be converted into 'int'
|
int g = a; // #error: 'int!' cannot be converted to 'int'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
145
test/test_suite/expressions/addr_compiles.c3t
Normal file
145
test/test_suite/expressions/addr_compiles.c3t
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
extern func void printf(char*, ...);
|
||||||
|
|
||||||
|
func void main()
|
||||||
|
{
|
||||||
|
test();
|
||||||
|
test2();
|
||||||
|
test3();
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
int f = 3;
|
||||||
|
int* x = &(((f)));
|
||||||
|
int* h = &&(f++);
|
||||||
|
printf("x = %d (4), h = %d (3)\n", *x, *h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const int XX = 314;
|
||||||
|
func void test2()
|
||||||
|
{
|
||||||
|
int* w = &XX;
|
||||||
|
printf("w = %d (314)\n", *w);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
}
|
||||||
|
func void test3()
|
||||||
|
{
|
||||||
|
Foo h = { 345, 555 };
|
||||||
|
int* zx = &h.x;
|
||||||
|
int* zy = &h.y;
|
||||||
|
int[3] arr = { 333, 444, 999 };
|
||||||
|
printf("zx = %d (345) zy = %d (555)\n", *zx, *zy);
|
||||||
|
arr[0]--;
|
||||||
|
arr[1]--;
|
||||||
|
arr[2]--;
|
||||||
|
int* d = &arr[2];
|
||||||
|
int[]* e = &&arr[1..2];
|
||||||
|
printf("d = %d (998) e = %d (443)\n", *d, (*e)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #expect: test.ll
|
||||||
|
|
||||||
|
define void @main() #0 {
|
||||||
|
entry:
|
||||||
|
call void @test.test()
|
||||||
|
call void @test.test2()
|
||||||
|
call void @test.test3()
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define void @test.test() #0 {
|
||||||
|
entry:
|
||||||
|
%f = alloca i32, align 4
|
||||||
|
%x = alloca i32*, align 8
|
||||||
|
%h = alloca i32*, align 8
|
||||||
|
%taddr = alloca i32, align 4
|
||||||
|
store i32 3, i32* %f, align 4
|
||||||
|
store i32* %f, i32** %x, align 8
|
||||||
|
%0 = load i32, i32* %f, align 4
|
||||||
|
%add = add i32 %0, 1
|
||||||
|
store i32 %add, i32* %f, align 4
|
||||||
|
store i32 %0, i32* %taddr, align 4
|
||||||
|
store i32* %taddr, i32** %h, align 8
|
||||||
|
%1 = load i32*, i32** %x, align 8
|
||||||
|
%2 = load i32, i32* %1, align 8
|
||||||
|
%3 = load i32*, i32** %h, align 8
|
||||||
|
%4 = load i32, i32* %3, align 8
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str, i32 0, i32 0), i32 %2, i32 %4)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define void @test.test2() #0 {
|
||||||
|
entry:
|
||||||
|
%w = alloca i32*, align 8
|
||||||
|
store i32* @test.XX, i32** %w, align 8
|
||||||
|
%0 = load i32*, i32** %w, align 8
|
||||||
|
%1 = load i32, i32* %0, align 8
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.1, i32 0, i32 0), i32 %1)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define void @test.test3() #0 {
|
||||||
|
entry:
|
||||||
|
%h = alloca %Foo, align 4
|
||||||
|
%zx = alloca i32*, align 8
|
||||||
|
%zy = alloca i32*, align 8
|
||||||
|
%arr = alloca [3 x i32], align 4
|
||||||
|
%d = alloca i32*, align 8
|
||||||
|
%e = alloca %"int[]"*, align 8
|
||||||
|
%taddr = alloca %"int[]", align 8
|
||||||
|
%0 = bitcast %Foo* %h to i8*
|
||||||
|
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%Foo* @.__const to i8*), i32 8, i1 false)
|
||||||
|
%1 = getelementptr inbounds %Foo, %Foo* %h, i32 0, i32 0
|
||||||
|
store i32* %1, i32** %zx, align 8
|
||||||
|
%2 = getelementptr inbounds %Foo, %Foo* %h, i32 0, i32 1
|
||||||
|
store i32* %2, i32** %zy, align 8
|
||||||
|
%3 = bitcast [3 x i32]* %arr to i8*
|
||||||
|
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %3, i8* align 4 bitcast ([3 x i32]* @.__const.2 to i8*), i32 12, i1 false)
|
||||||
|
%4 = load i32*, i32** %zx, align 8
|
||||||
|
%5 = load i32, i32* %4, align 8
|
||||||
|
%6 = load i32*, i32** %zy, align 8
|
||||||
|
%7 = load i32, i32* %6, align 8
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @.str.3, i32 0, i32 0), i32 %5, i32 %7)
|
||||||
|
%arridx = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 0
|
||||||
|
%8 = load i32, i32* %arridx, align 4
|
||||||
|
%sub = sub i32 %8, 1
|
||||||
|
store i32 %sub, i32* %arridx, align 4
|
||||||
|
%arridx1 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 1
|
||||||
|
%9 = load i32, i32* %arridx1, align 4
|
||||||
|
%sub2 = sub i32 %9, 1
|
||||||
|
store i32 %sub2, i32* %arridx1, align 4
|
||||||
|
%arridx3 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2
|
||||||
|
%10 = load i32, i32* %arridx3, align 4
|
||||||
|
%sub4 = sub i32 %10, 1
|
||||||
|
store i32 %sub4, i32* %arridx3, align 4
|
||||||
|
%arridx5 = getelementptr inbounds [3 x i32], [3 x i32]* %arr, i64 0, i64 2
|
||||||
|
store i32* %arridx5, i32** %d, align 8
|
||||||
|
%11 = bitcast [3 x i32]* %arr to i32*
|
||||||
|
%offset = getelementptr inbounds i32, i32* %11, i64 1
|
||||||
|
%12 = insertvalue %"int[]" undef, i32* %offset, 0
|
||||||
|
%13 = insertvalue %"int[]" %12, i64 2, 1
|
||||||
|
store %"int[]" %13, %"int[]"* %taddr, align 8
|
||||||
|
store %"int[]"* %taddr, %"int[]"** %e, align 8
|
||||||
|
%14 = load i32*, i32** %d, align 8
|
||||||
|
%15 = load i32, i32* %14, align 8
|
||||||
|
%16 = load %"int[]"*, %"int[]"** %e, align 8
|
||||||
|
%subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %16, i32 0, i32 0
|
||||||
|
%saptr = load i32*, i32** %subarrayptr, align 8
|
||||||
|
%sarridx = getelementptr inbounds i32, i32* %saptr, i64 0
|
||||||
|
%17 = load i32, i32* %sarridx, align 4
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.4, i32 0, i32 0), i32 %15, i32 %17)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
78
test/test_suite/expressions/addr_of_fails.c3
Normal file
78
test/test_suite/expressions/addr_of_fails.c3
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
func void test()
|
||||||
|
{
|
||||||
|
int f;
|
||||||
|
int* x = &(((f)));
|
||||||
|
int* h = &&(f++);
|
||||||
|
int* z = &(f++); // #error: To take the address of a temporary value, use '&&' instead of '&'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func void test2()
|
||||||
|
{
|
||||||
|
int f;
|
||||||
|
var $foo;
|
||||||
|
int* x = &$foo; // #error: It's not possible to take the address of a compile time value
|
||||||
|
}
|
||||||
|
|
||||||
|
int he;
|
||||||
|
macro int hello()
|
||||||
|
{
|
||||||
|
return he;
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test3()
|
||||||
|
{
|
||||||
|
int* x = &@hello(); // #error: To take the address of a temporary value, use '&&' instead of '&'
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test3b()
|
||||||
|
{
|
||||||
|
int* x = &hello; // #error: It is not possible to take the address of a macro.
|
||||||
|
}
|
||||||
|
|
||||||
|
const X = 2;
|
||||||
|
const int XX = 3;
|
||||||
|
func void test4()
|
||||||
|
{
|
||||||
|
int* w = &XX;
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test5()
|
||||||
|
{
|
||||||
|
int* z = &X; // #error: The constant is not typed, either type it or use && to take the reference to a temporary.
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
}
|
||||||
|
|
||||||
|
define heh = he;
|
||||||
|
|
||||||
|
func void test6()
|
||||||
|
{
|
||||||
|
int* hee = &heh;
|
||||||
|
Foo h;
|
||||||
|
int* z = &h.x;
|
||||||
|
int[3] arr;
|
||||||
|
int* d = &arr[2];
|
||||||
|
int[]* e = &arr[1..2]; // #error: To take the address of a temporary value, use '&&' instead of '&'
|
||||||
|
}
|
||||||
|
|
||||||
|
define Baz = Foo;
|
||||||
|
define Bar = distinct int;
|
||||||
|
errtype Err { FOO }
|
||||||
|
union Un { int x; }
|
||||||
|
enum MyEnum { BAR }
|
||||||
|
|
||||||
|
func void test7()
|
||||||
|
{
|
||||||
|
&Baz; // #error: It is not possible to take the address of a type.
|
||||||
|
&Bar; // #error: It is not possible to take the address of a type.
|
||||||
|
&Err; // #error: It is not possible to take the address of a type.
|
||||||
|
&Un; // #error: It is not possible to take the address of a type.
|
||||||
|
&Err.FOO; // #error: To take the address of a temporary value, use '&&' instead of '&'
|
||||||
|
&MyEnum; // #error: It is not possible to take the address of a type.
|
||||||
|
&MyEnum.BAR; // #error: To take the address of a temporary value, use '&&' instead of '&'
|
||||||
|
}
|
||||||
@@ -5,5 +5,5 @@ struct Struct
|
|||||||
|
|
||||||
func void test1()
|
func void test1()
|
||||||
{
|
{
|
||||||
int a = (Struct)(200); // #error: Cannot cast 'compint' to 'Struct'
|
int a = (Struct)(200); // #error: Cannot cast 'int' to 'Struct'
|
||||||
}
|
}
|
||||||
|
|||||||
41
test/test_suite/expressions/negate_int.c3
Normal file
41
test/test_suite/expressions/negate_int.c3
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
func void test1()
|
||||||
|
{
|
||||||
|
short! a = 1;
|
||||||
|
try(-a);
|
||||||
|
short b = -a; // #error: 'int!' cannot be converted to 'short'.
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test2()
|
||||||
|
{
|
||||||
|
int! a = 1;
|
||||||
|
try(-a);
|
||||||
|
int b = -a; // #error: 'int!' cannot be converted to 'int'
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test3()
|
||||||
|
{
|
||||||
|
long! a = 1;
|
||||||
|
try(-a);
|
||||||
|
long b = -a; // #error: 'long!' cannot be converted to 'long'
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test4()
|
||||||
|
{
|
||||||
|
short! a = 1;
|
||||||
|
try(~a);
|
||||||
|
short b = ~a; // #error: 'short!' cannot be converted to 'short'
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test5()
|
||||||
|
{
|
||||||
|
int! a = 1;
|
||||||
|
try(~a);
|
||||||
|
int b = ~a; // #error: 'int!' cannot be converted to 'int'
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test6()
|
||||||
|
{
|
||||||
|
long! a = 1;
|
||||||
|
try(~a);
|
||||||
|
long b = ~a; // #error: 'long!' cannot be converted to 'long'
|
||||||
|
}
|
||||||
@@ -14,5 +14,5 @@ func void test1(ichar* cp)
|
|||||||
func void test2(ichar* cp)
|
func void test2(ichar* cp)
|
||||||
{
|
{
|
||||||
cp + 1;
|
cp + 1;
|
||||||
cp * 1.0; // #error: Cannot multiply 'ichar*' by 'compfloat'
|
cp * 1.0; // #error: 'ichar*' by 'double'
|
||||||
}
|
}
|
||||||
16
test/test_suite/expressions/rvalues.c3
Normal file
16
test/test_suite/expressions/rvalues.c3
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
macro void hello($bar)
|
||||||
|
{
|
||||||
|
$bar;
|
||||||
|
}
|
||||||
|
const FOO = 1 + 2;
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
var $Foo = int;
|
||||||
|
var $Bar = $Foo;
|
||||||
|
$Bar x;
|
||||||
|
@hello(1);
|
||||||
|
var $foo = 1;
|
||||||
|
$foo;
|
||||||
|
FOO;
|
||||||
|
}
|
||||||
|
|
||||||
189
test/test_suite/failable_catch.c3t
Normal file
189
test/test_suite/failable_catch.c3t
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
|
|
||||||
|
errtype MyErr
|
||||||
|
{
|
||||||
|
TEST
|
||||||
|
}
|
||||||
|
|
||||||
|
macro foo(int x)
|
||||||
|
{
|
||||||
|
if (x) return x;
|
||||||
|
return MyErr.TEST!;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern func void printf(char*, ...);
|
||||||
|
|
||||||
|
func void main()
|
||||||
|
{
|
||||||
|
int! a = @foo(1);
|
||||||
|
|
||||||
|
int! b = @foo((a + 3) ?? 2);
|
||||||
|
int! c = @foo(0);
|
||||||
|
printf("a = %d\n", a);
|
||||||
|
printf("b = %d\n", b);
|
||||||
|
printf("c = %d\n", c);
|
||||||
|
if (catch(c)) printf("c had error\n");
|
||||||
|
c = 3;
|
||||||
|
printf("c = %d\n", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #expect: failable_catch.ll
|
||||||
|
|
||||||
|
define void @main() #0 {
|
||||||
|
entry:
|
||||||
|
%a = alloca i32, align 4
|
||||||
|
%a.f = alloca i64, align 8
|
||||||
|
%x = alloca i32, align 4
|
||||||
|
%blockret = alloca i32, align 4
|
||||||
|
%b = alloca i32, align 4
|
||||||
|
%b.f = alloca i64, align 8
|
||||||
|
%x1 = alloca i32, align 4
|
||||||
|
%blockret2 = alloca i32, align 4
|
||||||
|
%c = alloca i32, align 4
|
||||||
|
%c.f = alloca i64, align 8
|
||||||
|
%x8 = alloca i32, align 4
|
||||||
|
%blockret9 = alloca i32, align 4
|
||||||
|
%error_var = alloca i64, align 8
|
||||||
|
store i32 1, i32* %x, align 4
|
||||||
|
%0 = load i32, i32* %x, align 4
|
||||||
|
%intbool = icmp ne i32 %0, 0
|
||||||
|
br i1 %intbool, label %if.then, label %if.exit
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%1 = load i32, i32* %x, align 4
|
||||||
|
store i32 %1, i32* %blockret, align 4
|
||||||
|
br label %expr_block.exit
|
||||||
|
|
||||||
|
if.exit: ; preds = %entry
|
||||||
|
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %a.f, align 8
|
||||||
|
br label %after_assign
|
||||||
|
|
||||||
|
expr_block.exit: ; preds = %if.then
|
||||||
|
%2 = load i32, i32* %blockret, align 4
|
||||||
|
store i32 %2, i32* %a, align 4
|
||||||
|
store i64 0, i64* %a.f, align 8
|
||||||
|
br label %after_assign
|
||||||
|
|
||||||
|
after_assign: ; preds = %expr_block.exit, %if.exit
|
||||||
|
%3 = load i64, i64* %a.f, align 8
|
||||||
|
%not_err = icmp eq i64 %3, 0
|
||||||
|
br i1 %not_err, label %after_check, label %else_block
|
||||||
|
|
||||||
|
after_check: ; preds = %after_assign
|
||||||
|
%4 = load i32, i32* %a, align 4
|
||||||
|
%add = add i32 %4, 3
|
||||||
|
br label %phi_block
|
||||||
|
|
||||||
|
else_block: ; preds = %after_assign
|
||||||
|
br label %phi_block
|
||||||
|
|
||||||
|
phi_block: ; preds = %else_block, %after_check
|
||||||
|
%val = phi i32 [ %add, %after_check ], [ 2, %else_block ]
|
||||||
|
store i32 %val, i32* %x1, align 4
|
||||||
|
%5 = load i32, i32* %x1, align 4
|
||||||
|
%intbool3 = icmp ne i32 %5, 0
|
||||||
|
br i1 %intbool3, label %if.then4, label %if.exit5
|
||||||
|
|
||||||
|
if.then4: ; preds = %phi_block
|
||||||
|
%6 = load i32, i32* %x1, align 4
|
||||||
|
store i32 %6, i32* %blockret2, align 4
|
||||||
|
br label %expr_block.exit6
|
||||||
|
|
||||||
|
if.exit5: ; preds = %phi_block
|
||||||
|
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %b.f, align 8
|
||||||
|
br label %after_assign7
|
||||||
|
|
||||||
|
expr_block.exit6: ; preds = %if.then4
|
||||||
|
%7 = load i32, i32* %blockret2, align 4
|
||||||
|
store i32 %7, i32* %b, align 4
|
||||||
|
store i64 0, i64* %b.f, align 8
|
||||||
|
br label %after_assign7
|
||||||
|
|
||||||
|
after_assign7: ; preds = %expr_block.exit6, %if.exit5
|
||||||
|
store i32 0, i32* %x8, align 4
|
||||||
|
%8 = load i32, i32* %x8, align 4
|
||||||
|
%intbool10 = icmp ne i32 %8, 0
|
||||||
|
br i1 %intbool10, label %if.then11, label %if.exit12
|
||||||
|
|
||||||
|
if.then11: ; preds = %after_assign7
|
||||||
|
%9 = load i32, i32* %x8, align 4
|
||||||
|
store i32 %9, i32* %blockret9, align 4
|
||||||
|
br label %expr_block.exit13
|
||||||
|
|
||||||
|
if.exit12: ; preds = %after_assign7
|
||||||
|
store i64 ptrtoint ([1 x i8*]* @"failable_catch.MyErr$elements" to i64), i64* %c.f, align 8
|
||||||
|
br label %after_assign14
|
||||||
|
|
||||||
|
expr_block.exit13: ; preds = %if.then11
|
||||||
|
%10 = load i32, i32* %blockret9, align 4
|
||||||
|
store i32 %10, i32* %c, align 4
|
||||||
|
store i64 0, i64* %c.f, align 8
|
||||||
|
br label %after_assign14
|
||||||
|
|
||||||
|
after_assign14: ; preds = %expr_block.exit13, %if.exit12
|
||||||
|
%11 = load i64, i64* %a.f, align 8
|
||||||
|
%not_err15 = icmp eq i64 %11, 0
|
||||||
|
br i1 %not_err15, label %after_check16, label %voiderr
|
||||||
|
|
||||||
|
after_check16: ; preds = %after_assign14
|
||||||
|
%12 = load i32, i32* %a, align 4
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i32 0, i32 0), i32 %12)
|
||||||
|
br label %voiderr
|
||||||
|
|
||||||
|
voiderr: ; preds = %after_check16, %after_assign14
|
||||||
|
%13 = load i64, i64* %b.f, align 8
|
||||||
|
%not_err17 = icmp eq i64 %13, 0
|
||||||
|
br i1 %not_err17, label %after_check18, label %voiderr19
|
||||||
|
|
||||||
|
after_check18: ; preds = %voiderr
|
||||||
|
%14 = load i32, i32* %b, align 4
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0), i32 %14)
|
||||||
|
br label %voiderr19
|
||||||
|
|
||||||
|
voiderr19: ; preds = %after_check18, %voiderr
|
||||||
|
%15 = load i64, i64* %c.f, align 8
|
||||||
|
%not_err20 = icmp eq i64 %15, 0
|
||||||
|
br i1 %not_err20, label %after_check21, label %voiderr22
|
||||||
|
|
||||||
|
after_check21: ; preds = %voiderr19
|
||||||
|
%16 = load i32, i32* %c, align 4
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i32 %16)
|
||||||
|
br label %voiderr22
|
||||||
|
|
||||||
|
voiderr22: ; preds = %after_check21, %voiderr19
|
||||||
|
store i64 0, i64* %error_var, align 8
|
||||||
|
%17 = load i64, i64* %c.f, align 8
|
||||||
|
%not_err23 = icmp eq i64 %17, 0
|
||||||
|
br i1 %not_err23, label %after_check24, label %error
|
||||||
|
|
||||||
|
error: ; preds = %voiderr22
|
||||||
|
store i64 %17, i64* %error_var, align 8
|
||||||
|
br label %noerr_block
|
||||||
|
|
||||||
|
after_check24: ; preds = %voiderr22
|
||||||
|
br label %noerr_block
|
||||||
|
|
||||||
|
noerr_block: ; preds = %after_check24, %error
|
||||||
|
%18 = load i64, i64* %error_var, align 8
|
||||||
|
%neq = icmp ne i64 %18, 0
|
||||||
|
br i1 %neq, label %if.then25, label %if.exit26
|
||||||
|
|
||||||
|
if.then25: ; preds = %noerr_block
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.3, i32 0, i32 0))
|
||||||
|
br label %if.exit26
|
||||||
|
|
||||||
|
if.exit26: ; preds = %if.then25, %noerr_block
|
||||||
|
store i32 3, i32* %c, align 4
|
||||||
|
store i64 0, i64* %c.f, align 8
|
||||||
|
%19 = load i64, i64* %c.f, align 8
|
||||||
|
%not_err27 = icmp eq i64 %19, 0
|
||||||
|
br i1 %not_err27, label %after_check28, label %voiderr29
|
||||||
|
|
||||||
|
after_check28: ; preds = %if.exit26
|
||||||
|
%20 = load i32, i32* %c, align 4
|
||||||
|
call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.4, i32 0, i32 0), i32 %20)
|
||||||
|
br label %voiderr29
|
||||||
|
|
||||||
|
voiderr29: ; preds = %after_check28, %if.exit26
|
||||||
|
ret void
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
func void test()
|
func void test()
|
||||||
{
|
{
|
||||||
float x = 0x7FFFFFFFFFFF.0p+400; // #error: The value '3.63419e+134' is out of range for 'float', so you need an explicit cast to truncate the value
|
float x = 0x7FFFFFFFFFFF.0p+400; // #error: The value '3.63419e+134' is out of range for 'float'
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ func void main()
|
|||||||
}
|
}
|
||||||
list.free();
|
list.free();
|
||||||
|
|
||||||
printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, MyEnum.elements);
|
printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, (int)(MyEnum.elements));
|
||||||
|
|
||||||
int max = MyEnum.max;
|
int max = MyEnum.max;
|
||||||
int min = MyEnum.min;
|
int min = MyEnum.min;
|
||||||
@@ -245,7 +245,7 @@ func Type getValue(Blob blob)
|
|||||||
return blob.a;
|
return blob.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|
||||||
%Blob = type { i32 }
|
%Blob = type { i32 }
|
||||||
%Blob.0 = type { double }
|
%Blob.0 = type { double }
|
||||||
@@ -364,7 +364,7 @@ entry:
|
|||||||
store i32 0, i32* %sum, align 4
|
store i32 0, i32* %sum, align 4
|
||||||
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
|
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
|
||||||
%2 = load i64, i64* %len, align 8
|
%2 = load i64, i64* %len, align 8
|
||||||
%eq = icmp eq i64 %2, 0
|
%eq = icmp eq i64 0, %2
|
||||||
br i1 %eq, label %if.then, label %if.exit
|
br i1 %eq, label %if.then, label %if.exit
|
||||||
|
|
||||||
if.then: ; preds = %entry
|
if.then: ; preds = %entry
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ func void main()
|
|||||||
}
|
}
|
||||||
list.free();
|
list.free();
|
||||||
|
|
||||||
printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, MyEnum.elements);
|
printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, (int)(MyEnum.elements));
|
||||||
|
|
||||||
int max = MyEnum.max;
|
int max = MyEnum.max;
|
||||||
int min = MyEnum.min;
|
int min = MyEnum.min;
|
||||||
@@ -358,7 +358,7 @@ entry:
|
|||||||
store i32 0, i32* %sum, align 4
|
store i32 0, i32* %sum, align 4
|
||||||
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
|
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
|
||||||
%3 = load i64, i64* %len, align 8
|
%3 = load i64, i64* %len, align 8
|
||||||
%eq = icmp eq i64 %3, 0
|
%eq = icmp eq i64 0, %3
|
||||||
br i1 %eq, label %if.then, label %if.exit
|
br i1 %eq, label %if.then, label %if.exit
|
||||||
|
|
||||||
if.then:
|
if.then:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ char[] str3 = "hello";
|
|||||||
|
|
||||||
int[2] a1 = { 1, 2 };
|
int[2] a1 = { 1, 2 };
|
||||||
|
|
||||||
int[2] a2 = 30; // #error: 'compint' into 'int[2]'
|
int[2] a2 = 30; // #error: 'int' into 'int[2]'
|
||||||
// TODO int[2] a3 = a1;
|
// TODO int[2] a3 = a1;
|
||||||
|
|
||||||
ichar[*] a; // #error: Inferred array types can only be used in declarations with initializers
|
ichar[*] a; // #error: Inferred array types can only be used in declarations with initializers
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
module fasta;
|
module fasta;
|
||||||
|
|
||||||
const IM = 139968;
|
const IM = 139968u;
|
||||||
const IA = 3877;
|
const IA = 3877u;
|
||||||
const IC = 29573;
|
const IC = 29573u;
|
||||||
const SEED = 42;
|
const SEED = 42u;
|
||||||
|
|
||||||
uint seed = SEED;
|
uint seed = SEED;
|
||||||
|
|
||||||
@@ -108,10 +109,10 @@ func void main(int argc, char **argv)
|
|||||||
%"char[]" = type { i8*, i64 }
|
%"char[]" = type { i8*, i64 }
|
||||||
%"double[]" = type { double*, i64 }
|
%"double[]" = type { double*, i64 }
|
||||||
|
|
||||||
@fasta.IM = constant i32 139968, align 1
|
@fasta.IM = constant i32 139968, align 4
|
||||||
@fasta.IA = constant i32 3877, align 1
|
@fasta.IA = constant i32 3877, align 4
|
||||||
@fasta.IC = constant i32 29573, align 1
|
@fasta.IC = constant i32 29573, align 4
|
||||||
@fasta.SEED = constant i32 42, align 1
|
@fasta.SEED = constant i32 42, align 4
|
||||||
@fasta.seed = global i32 42, align 4
|
@fasta.seed = global i32 42, align 4
|
||||||
@.str = private constant [288 x i8] c"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA\00", align 1
|
@.str = private constant [288 x i8] c"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA\00", align 1
|
||||||
@fasta.alu = protected global %"char[]" { i8* getelementptr inbounds ([288 x i8], [288 x i8]* @.str, i32 0, i32 0), i64 287 }, align 8
|
@fasta.alu = protected global %"char[]" { i8* getelementptr inbounds ([288 x i8], [288 x i8]* @.str, i32 0, i32 0), i64 287 }, align 8
|
||||||
@@ -123,7 +124,7 @@ func void main(int argc, char **argv)
|
|||||||
@fasta.homosapiens = global %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0), i64 4 }, align 8
|
@fasta.homosapiens = global %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0), i64 4 }, align 8
|
||||||
@.taddr.13 = private hidden global [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8
|
@.taddr.13 = private hidden global [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8
|
||||||
@fasta.homosapiens_p = global %"double[]" { double* getelementptr inbounds ([4 x double], [4 x double]* @.taddr.13, i32 0, i32 0), i64 4 }, align 8
|
@fasta.homosapiens_p = global %"double[]" { double* getelementptr inbounds ([4 x double], [4 x double]* @.taddr.13, i32 0, i32 0), i64 4 }, align 8
|
||||||
@fasta.LINELEN = constant i32 60, align 1
|
@fasta.LINELEN = constant i32 60, align 4
|
||||||
@.str.14 = private constant [23 x i8] c">ONE Homo sapiens alu\0A\00", align 1
|
@.str.14 = private constant [23 x i8] c">ONE Homo sapiens alu\0A\00", align 1
|
||||||
@.str.15 = private constant [26 x i8] c">TWO IUB ambiguity codes\0A\00", align 1
|
@.str.15 = private constant [26 x i8] c">TWO IUB ambiguity codes\0A\00", align 1
|
||||||
@.str.16 = private constant [31 x i8] c">THREE Homo sapiens frequency\0A\00", align 1
|
@.str.16 = private constant [31 x i8] c">THREE Homo sapiens frequency\0A\00", align 1
|
||||||
@@ -229,7 +230,7 @@ entry:
|
|||||||
%symb = alloca %"char[]", align 8
|
%symb = alloca %"char[]", align 8
|
||||||
%probability = alloca %"double[]", align 8
|
%probability = alloca %"double[]", align 8
|
||||||
%n = alloca i32, align 4
|
%n = alloca i32, align 4
|
||||||
%len = alloca i32, align 4
|
%len5 = alloca i32, align 4
|
||||||
%i = alloca i32, align 4
|
%i = alloca i32, align 4
|
||||||
%v = alloca double, align 8
|
%v = alloca double, align 8
|
||||||
%j = alloca i32, align 4
|
%j = alloca i32, align 4
|
||||||
@@ -244,97 +245,103 @@ entry:
|
|||||||
%hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 1
|
%hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 1
|
||||||
store i64 %3, i64* %hi3, align 8
|
store i64 %3, i64* %hi3, align 8
|
||||||
store i32 %4, i32* %n, align 4
|
store i32 %4, i32* %n, align 4
|
||||||
|
%len = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 1
|
||||||
|
%5 = load i64, i64* %len, align 8
|
||||||
%len4 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1
|
%len4 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1
|
||||||
%5 = load i64, i64* %len4, align 8
|
%6 = load i64, i64* %len4, align 8
|
||||||
%uisitrunc = trunc i64 %5 to i32
|
%eq = icmp eq i64 %5, %6
|
||||||
store i32 %uisitrunc, i32* %len, align 4
|
call void @llvm.assume(i1 %eq)
|
||||||
|
%len6 = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 1
|
||||||
|
%7 = load i64, i64* %len6, align 8
|
||||||
|
%uisitrunc = trunc i64 %7 to i32
|
||||||
|
store i32 %uisitrunc, i32* %len5, align 4
|
||||||
store i32 0, i32* %i, align 4
|
store i32 0, i32* %i, align 4
|
||||||
br label %for.cond
|
br label %for.cond
|
||||||
|
|
||||||
for.cond: ; preds = %for.inc15, %entry
|
for.cond: ; preds = %for.inc18, %entry
|
||||||
%6 = load i32, i32* %i, align 4
|
%8 = load i32, i32* %i, align 4
|
||||||
%7 = load i32, i32* %n, align 4
|
%9 = load i32, i32* %n, align 4
|
||||||
%lt = icmp slt i32 %6, %7
|
%lt = icmp slt i32 %8, %9
|
||||||
br i1 %lt, label %for.body, label %for.exit17
|
br i1 %lt, label %for.body, label %for.exit20
|
||||||
|
|
||||||
for.body: ; preds = %for.cond
|
for.body: ; preds = %for.cond
|
||||||
%8 = call float @fasta.fasta_rand(float 1.000000e+00)
|
%10 = call float @fasta.fasta_rand(float 1.000000e+00)
|
||||||
%fpfpext = fpext float %8 to double
|
%fpfpext = fpext float %10 to double
|
||||||
store double %fpfpext, double* %v, align 8
|
store double %fpfpext, double* %v, align 8
|
||||||
store i32 0, i32* %j, align 4
|
store i32 0, i32* %j, align 4
|
||||||
br label %for.cond5
|
br label %for.cond7
|
||||||
|
|
||||||
for.cond5: ; preds = %for.inc, %for.body
|
for.cond7: ; preds = %for.inc, %for.body
|
||||||
%9 = load i32, i32* %j, align 4
|
%11 = load i32, i32* %j, align 4
|
||||||
%10 = load i32, i32* %len, align 4
|
%12 = load i32, i32* %len5, align 4
|
||||||
%sub = sub i32 %10, 1
|
%sub = sub i32 %12, 1
|
||||||
%lt6 = icmp slt i32 %9, %sub
|
%lt8 = icmp slt i32 %11, %sub
|
||||||
br i1 %lt6, label %for.body7, label %for.exit
|
br i1 %lt8, label %for.body9, label %for.exit
|
||||||
|
|
||||||
for.body7: ; preds = %for.cond5
|
for.body9: ; preds = %for.cond7
|
||||||
%11 = load double, double* %v, align 8
|
%13 = load double, double* %v, align 8
|
||||||
%subarrayptr = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 0
|
%subarrayptr = getelementptr inbounds %"double[]", %"double[]"* %probability, i32 0, i32 0
|
||||||
%saptr = load double*, double** %subarrayptr, align 8
|
%saptr = load double*, double** %subarrayptr, align 8
|
||||||
%12 = load i32, i32* %j, align 4
|
%14 = load i32, i32* %j, align 4
|
||||||
%sisiext = sext i32 %12 to i64
|
%sisiext = sext i32 %14 to i64
|
||||||
%sarridx = getelementptr inbounds double, double* %saptr, i64 %sisiext
|
%sarridx = getelementptr inbounds double, double* %saptr, i64 %sisiext
|
||||||
%13 = load double, double* %sarridx, align 8
|
%15 = load double, double* %sarridx, align 8
|
||||||
%fsub = fsub double %11, %13
|
%fsub = fsub double %13, %15
|
||||||
store double %fsub, double* %v, align 8
|
store double %fsub, double* %v, align 8
|
||||||
%14 = load double, double* %v, align 8
|
%16 = load double, double* %v, align 8
|
||||||
%lt8 = fcmp olt double %14, 0.000000e+00
|
%lt10 = fcmp olt double %16, 0.000000e+00
|
||||||
br i1 %lt8, label %if.then, label %if.exit
|
br i1 %lt10, label %if.then, label %if.exit
|
||||||
|
|
||||||
if.then: ; preds = %for.body7
|
if.then: ; preds = %for.body9
|
||||||
br label %for.exit
|
br label %for.exit
|
||||||
|
|
||||||
if.exit: ; preds = %for.body7
|
if.exit: ; preds = %for.body9
|
||||||
br label %for.inc
|
br label %for.inc
|
||||||
|
|
||||||
for.inc: ; preds = %if.exit
|
for.inc: ; preds = %if.exit
|
||||||
%15 = load i32, i32* %j, align 4
|
%17 = load i32, i32* %j, align 4
|
||||||
%add = add i32 %15, 1
|
%add = add i32 %17, 1
|
||||||
store i32 %add, i32* %j, align 4
|
store i32 %add, i32* %j, align 4
|
||||||
br label %for.cond5
|
br label %for.cond7
|
||||||
|
|
||||||
for.exit: ; preds = %if.then, %for.cond5
|
for.exit: ; preds = %if.then, %for.cond7
|
||||||
%subarrayptr9 = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 0
|
%subarrayptr11 = getelementptr inbounds %"char[]", %"char[]"* %symb, i32 0, i32 0
|
||||||
%saptr10 = load i8*, i8** %subarrayptr9, align 8
|
%saptr12 = load i8*, i8** %subarrayptr11, align 8
|
||||||
%16 = load i32, i32* %j, align 4
|
%18 = load i32, i32* %j, align 4
|
||||||
%sisiext11 = sext i32 %16 to i64
|
%sisiext13 = sext i32 %18 to i64
|
||||||
%sarridx12 = getelementptr inbounds i8, i8* %saptr10, i64 %sisiext11
|
%sarridx14 = getelementptr inbounds i8, i8* %saptr12, i64 %sisiext13
|
||||||
%17 = load i8, i8* %sarridx12, align 1
|
%19 = load i8, i8* %sarridx14, align 1
|
||||||
%uisiext = zext i8 %17 to i32
|
%uisiext = zext i8 %19 to i32
|
||||||
call void @putchar(i32 %uisiext)
|
call void @putchar(i32 %uisiext)
|
||||||
%18 = load i32, i32* %i, align 4
|
%20 = load i32, i32* %i, align 4
|
||||||
%smod = srem i32 %18, 60
|
%smod = srem i32 %20, 60
|
||||||
%eq = icmp eq i32 %smod, 59
|
%eq15 = icmp eq i32 %smod, 59
|
||||||
br i1 %eq, label %if.then13, label %if.exit14
|
br i1 %eq15, label %if.then16, label %if.exit17
|
||||||
|
|
||||||
if.then13: ; preds = %for.exit
|
if.then16: ; preds = %for.exit
|
||||||
call void @putchar(i32 10)
|
call void @putchar(i32 10)
|
||||||
br label %if.exit14
|
br label %if.exit17
|
||||||
|
|
||||||
if.exit14: ; preds = %if.then13, %for.exit
|
if.exit17: ; preds = %if.then16, %for.exit
|
||||||
br label %for.inc15
|
br label %for.inc18
|
||||||
|
|
||||||
for.inc15: ; preds = %if.exit14
|
for.inc18: ; preds = %if.exit17
|
||||||
%19 = load i32, i32* %i, align 4
|
%21 = load i32, i32* %i, align 4
|
||||||
%add16 = add i32 %19, 1
|
%add19 = add i32 %21, 1
|
||||||
store i32 %add16, i32* %i, align 4
|
store i32 %add19, i32* %i, align 4
|
||||||
br label %for.cond
|
br label %for.cond
|
||||||
|
|
||||||
for.exit17: ; preds = %for.cond
|
for.exit20: ; preds = %for.cond
|
||||||
%20 = load i32, i32* %i, align 4
|
%22 = load i32, i32* %i, align 4
|
||||||
%smod18 = srem i32 %20, 60
|
%smod21 = srem i32 %22, 60
|
||||||
%neq = icmp ne i32 %smod18, 0
|
%neq = icmp ne i32 %smod21, 0
|
||||||
br i1 %neq, label %if.then19, label %if.exit20
|
br i1 %neq, label %if.then22, label %if.exit23
|
||||||
|
|
||||||
if.then19: ; preds = %for.exit17
|
if.then22: ; preds = %for.exit20
|
||||||
call void @putchar(i32 10)
|
call void @putchar(i32 10)
|
||||||
br label %if.exit20
|
br label %if.exit23
|
||||||
|
|
||||||
if.exit20: ; preds = %if.then19, %for.exit17
|
if.exit23: ; preds = %if.then22, %for.exit20
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,4 +390,4 @@ if.exit: ; preds = %if.then, %entry
|
|||||||
%mul10 = mul i32 %11, 5
|
%mul10 = mul i32 %11, 5
|
||||||
call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10)
|
call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ func int test()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #expect: general_tests.ll
|
/* #expect: general_tests.ll
|
||||||
|
|
||||||
%Baz = type { double }
|
%Baz = type { double }
|
||||||
%Bar = type { i32, i32 }
|
%Bar = type { i32, i32 }
|
||||||
@@ -52,15 +52,14 @@ entry:
|
|||||||
%a = alloca [0 x i32], align 4
|
%a = alloca [0 x i32], align 4
|
||||||
%foo2 = alloca i32, align 4
|
%foo2 = alloca i32, align 4
|
||||||
%str = alloca i8*, align 8
|
%str = alloca i8*, align 8
|
||||||
%literal = alloca [1 x i8*], align 8
|
|
||||||
%x = alloca i8, align 1
|
%x = alloca i8, align 1
|
||||||
%literal1 = alloca [3 x i32], align 4
|
%literal = alloca [3 x i32], align 4
|
||||||
%b = alloca %Bar, align 4
|
%b = alloca %Bar, align 4
|
||||||
%z = alloca %Baz, align 8
|
%z = alloca %Baz, align 8
|
||||||
%sub = alloca %"int[]", align 8
|
%sub = alloca %"int[]", align 8
|
||||||
%literal2 = alloca [0 x i32], align 4
|
%literal1 = alloca [0 x i32], align 4
|
||||||
%foo = alloca %"Bar[]", align 8
|
%foo = alloca %"Bar[]", align 8
|
||||||
%literal3 = alloca [0 x %Bar], align 4
|
%literal2 = alloca [0 x %Bar], align 4
|
||||||
%baz = alloca [3 x %Baz], align 16
|
%baz = alloca [3 x %Baz], align 16
|
||||||
%0 = bitcast %Baz* %ffe to i8*
|
%0 = bitcast %Baz* %ffe to i8*
|
||||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %0, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false)
|
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %0, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false)
|
||||||
@@ -69,40 +68,35 @@ entry:
|
|||||||
%2 = bitcast [0 x i32]* %a to i8*
|
%2 = bitcast [0 x i32]* %a to i8*
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 0, i1 false)
|
call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 0, i1 false)
|
||||||
store i32 33, i32* %foo2, align 4
|
store i32 33, i32* %foo2, align 4
|
||||||
%3 = getelementptr inbounds i8*, [1 x i8*]* %literal, i32 0
|
store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8** %str, align 8
|
||||||
store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8** %3, align 8
|
%3 = getelementptr inbounds i32, [3 x i32]* %literal, i32 0
|
||||||
%arridx = getelementptr inbounds [1 x i8*], [1 x i8*]* %literal, i64 0, i64 0
|
store i32 1, i32* %3, align 4
|
||||||
%4 = load i8*, i8** %arridx, align 8
|
%4 = getelementptr inbounds i32, [3 x i32]* %literal, i32 1
|
||||||
store i8* %4, i8** %str, align 8
|
store i32 2, i32* %4, align 4
|
||||||
%5 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 0
|
%5 = getelementptr inbounds i32, [3 x i32]* %literal, i32 2
|
||||||
store i32 1, i32* %5, align 4
|
store i32 3, i32* %5, align 4
|
||||||
%6 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 1
|
%6 = bitcast [3 x i32]* %literal to i32*
|
||||||
store i32 2, i32* %6, align 4
|
%7 = insertvalue %"int[]" undef, i32* %6, 0
|
||||||
%7 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 2
|
%8 = insertvalue %"int[]" %7, i64 3, 1
|
||||||
store i32 3, i32* %7, align 4
|
%len = extractvalue %"int[]" %8, 1
|
||||||
%8 = bitcast [3 x i32]* %literal1 to i32*
|
%not = icmp eq i64 %len, 0
|
||||||
%9 = insertvalue %"int[]" undef, i32* %8, 0
|
%9 = zext i1 %not to i8
|
||||||
%10 = insertvalue %"int[]" %9, i64 3, 1
|
store i8 %9, i8* %x, align 1
|
||||||
%11 = extractvalue %"int[]" %10, 1
|
%10 = bitcast %Bar* %b to i8*
|
||||||
%neq = icmp ne i64 %11, 0
|
call void @llvm.memset.p0i8.i64(i8* align 4 %10, i8 0, i64 8, i1 false)
|
||||||
%not = xor i1 %neq, true
|
%11 = bitcast %Baz* %z to i8*
|
||||||
%12 = zext i1 %not to i8
|
call void @llvm.memset.p0i8.i64(i8* align 8 %11, i8 0, i64 8, i1 false)
|
||||||
store i8 %12, i8* %x, align 1
|
store [0 x i32] zeroinitializer, [0 x i32]* %literal1, align 4
|
||||||
%13 = bitcast %Bar* %b to i8*
|
%12 = bitcast [0 x i32]* %literal1 to i32*
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 4 %13, i8 0, i64 8, i1 false)
|
%13 = insertvalue %"int[]" undef, i32* %12, 0
|
||||||
%14 = bitcast %Baz* %z to i8*
|
%14 = insertvalue %"int[]" %13, i64 0, 1
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 8 %14, i8 0, i64 8, i1 false)
|
store %"int[]" %14, %"int[]"* %sub, align 8
|
||||||
store [0 x i32] zeroinitializer, [0 x i32]* %literal2, align 4
|
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal2, align 4
|
||||||
%15 = bitcast [0 x i32]* %literal2 to i32*
|
%15 = bitcast [0 x %Bar]* %literal2 to %Bar*
|
||||||
%16 = insertvalue %"int[]" undef, i32* %15, 0
|
%16 = insertvalue %"Bar[]" undef, %Bar* %15, 0
|
||||||
%17 = insertvalue %"int[]" %16, i64 0, 1
|
%17 = insertvalue %"Bar[]" %16, i64 0, 1
|
||||||
store %"int[]" %17, %"int[]"* %sub, align 8
|
store %"Bar[]" %17, %"Bar[]"* %foo, align 8
|
||||||
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal3, align 4
|
%18 = bitcast [3 x %Baz]* %baz to i8*
|
||||||
%18 = bitcast [0 x %Bar]* %literal3 to %Bar*
|
call void @llvm.memset.p0i8.i64(i8* align 16 %18, i8 0, i64 24, i1 false)
|
||||||
%19 = insertvalue %"Bar[]" undef, %Bar* %18, 0
|
|
||||||
%20 = insertvalue %"Bar[]" %19, i64 0, 1
|
|
||||||
store %"Bar[]" %20, %"Bar[]"* %foo, align 8
|
|
||||||
%21 = bitcast [3 x %Baz]* %baz to i8*
|
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 16 %21, i8 0, i64 24, i1 false)
|
|
||||||
ret i32 1
|
ret i32 1
|
||||||
}
|
}
|
||||||
28
test/test_suite/initializer_lists/indexing_into_complist.c3
Normal file
28
test/test_suite/initializer_lists/indexing_into_complist.c3
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
func void test()
|
||||||
|
{
|
||||||
|
char* c = { 1, 3, "hello"}[2];
|
||||||
|
int x;
|
||||||
|
int z = { 1, 3 }[x]; // #error: To subscript a compile time list a compile time integer index is needed
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test2()
|
||||||
|
{
|
||||||
|
int z = { 1, 3 }[-1]; // #error: The index may not be negative
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test3()
|
||||||
|
{
|
||||||
|
int z = { 1, 3 }[0xFFFF_FFFF_FFFF_FFFFu64]; // #error: The index is out of range.
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test4()
|
||||||
|
{
|
||||||
|
int z = { 1, 3 }[2]; // #error: An index of '2' is out of range, a value between 0 and 1 was expected.
|
||||||
|
int z2 = { 1 }[2]; // #error: An index of '2' is out of range, a value of 0 was expected.
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test5()
|
||||||
|
{
|
||||||
|
int z = { 1, 3 }[^4]; // #error: An index of '4' from the end is out of range, a value between 1 and 2 was expected
|
||||||
|
int z2 = { 1 }[^4]; // #error: An index of '4' from the end is out of range, a value of 1 was expected.
|
||||||
|
}
|
||||||
@@ -81,9 +81,9 @@ entry:
|
|||||||
%b = alloca %Bar, align 4
|
%b = alloca %Bar, align 4
|
||||||
%z = alloca %Baz, align 8
|
%z = alloca %Baz, align 8
|
||||||
%sub = alloca %"int[]", align 8
|
%sub = alloca %"int[]", align 8
|
||||||
%literal9 = alloca [0 x i32], align 4
|
%literal10 = alloca [0 x i32], align 4
|
||||||
%foo = alloca %"Bar[]", align 8
|
%foo = alloca %"Bar[]", align 8
|
||||||
%literal10 = alloca [0 x %Bar], align 4
|
%literal11 = alloca [0 x %Bar], align 4
|
||||||
%baz = alloca [3 x %Baz], align 16
|
%baz = alloca [3 x %Baz], align 16
|
||||||
%saptr = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8
|
%saptr = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8
|
||||||
%sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 1
|
%sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 1
|
||||||
@@ -145,36 +145,35 @@ entry:
|
|||||||
%30 = bitcast [3 x i32]* %literal7 to i32*
|
%30 = bitcast [3 x i32]* %literal7 to i32*
|
||||||
%31 = insertvalue %"int[]" undef, i32* %30, 0
|
%31 = insertvalue %"int[]" undef, i32* %30, 0
|
||||||
%32 = insertvalue %"int[]" %31, i64 3, 1
|
%32 = insertvalue %"int[]" %31, i64 3, 1
|
||||||
%33 = extractvalue %"int[]" %32, 1
|
%len8 = extractvalue %"int[]" %32, 1
|
||||||
%neq = icmp ne i64 %33, 0
|
%not = icmp eq i64 %len8, 0
|
||||||
%not = xor i1 %neq, true
|
%33 = zext i1 %not to i8
|
||||||
%34 = zext i1 %not to i8
|
store i8 %33, i8* %xy, align 1
|
||||||
store i8 %34, i8* %xy, align 1
|
%34 = load i8, i8* %xy, align 1
|
||||||
%35 = load i8, i8* %xy, align 1
|
%35 = trunc i8 %34 to i1
|
||||||
%36 = trunc i8 %35 to i1
|
%not9 = xor i1 %35, true
|
||||||
%not8 = xor i1 %36, true
|
br i1 %not9, label %if.then, label %if.exit
|
||||||
br i1 %not8, label %if.then, label %if.exit
|
|
||||||
|
|
||||||
if.then: ; preds = %entry
|
if.then: ; preds = %entry
|
||||||
%37 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3
|
%36 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3
|
||||||
br label %if.exit
|
br label %if.exit
|
||||||
|
|
||||||
if.exit: ; preds = %if.then, %entry
|
if.exit: ; preds = %if.then, %entry
|
||||||
%38 = bitcast %Bar* %b to i8*
|
%37 = bitcast %Bar* %b to i8*
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 4 %38, i8 0, i64 8, i1 false)
|
call void @llvm.memset.p0i8.i64(i8* align 4 %37, i8 0, i64 8, i1 false)
|
||||||
%39 = bitcast %Baz* %z to i8*
|
%38 = bitcast %Baz* %z to i8*
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 8 %39, i8 0, i64 8, i1 false)
|
call void @llvm.memset.p0i8.i64(i8* align 8 %38, i8 0, i64 8, i1 false)
|
||||||
store [0 x i32] zeroinitializer, [0 x i32]* %literal9, align 4
|
store [0 x i32] zeroinitializer, [0 x i32]* %literal10, align 4
|
||||||
%40 = bitcast [0 x i32]* %literal9 to i32*
|
%39 = bitcast [0 x i32]* %literal10 to i32*
|
||||||
%41 = insertvalue %"int[]" undef, i32* %40, 0
|
%40 = insertvalue %"int[]" undef, i32* %39, 0
|
||||||
%42 = insertvalue %"int[]" %41, i64 0, 1
|
%41 = insertvalue %"int[]" %40, i64 0, 1
|
||||||
store %"int[]" %42, %"int[]"* %sub, align 8
|
store %"int[]" %41, %"int[]"* %sub, align 8
|
||||||
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal10, align 4
|
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal11, align 4
|
||||||
%43 = bitcast [0 x %Bar]* %literal10 to %Bar*
|
%42 = bitcast [0 x %Bar]* %literal11 to %Bar*
|
||||||
%44 = insertvalue %"Bar[]" undef, %Bar* %43, 0
|
%43 = insertvalue %"Bar[]" undef, %Bar* %42, 0
|
||||||
%45 = insertvalue %"Bar[]" %44, i64 0, 1
|
%44 = insertvalue %"Bar[]" %43, i64 0, 1
|
||||||
store %"Bar[]" %45, %"Bar[]"* %foo, align 8
|
store %"Bar[]" %44, %"Bar[]"* %foo, align 8
|
||||||
%46 = bitcast [3 x %Baz]* %baz to i8*
|
%45 = bitcast [3 x %Baz]* %baz to i8*
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 16 %46, i8 0, i64 24, i1 false)
|
call void @llvm.memset.p0i8.i64(i8* align 16 %45, i8 0, i64 24, i1 false)
|
||||||
ret i32 1
|
ret i32 1
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ func void main()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #expect: withbody.ll
|
/* #expect: withbody.ll
|
||||||
|
|
||||||
define i32 @withbody.Foo__mutate(%Foo* %0)
|
define i32 @withbody.Foo__mutate(%Foo* %0)
|
||||||
entry:
|
entry:
|
||||||
|
|||||||
66
test/test_suite/macros/type_params.c3t
Normal file
66
test/test_suite/macros/type_params.c3t
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
|
macro foo($Foo)
|
||||||
|
{
|
||||||
|
$Foo a;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
define Bar = short;
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
int x = @foo(int);
|
||||||
|
var $Foo = double;
|
||||||
|
double d = @foo($Foo);
|
||||||
|
double d2 = @foo($typeof(d));
|
||||||
|
short z = @foo(Bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* #expect: type_params.ll
|
||||||
|
|
||||||
|
%x = alloca i32, align 4
|
||||||
|
%blockret = alloca i32, align 4
|
||||||
|
%a = alloca i32, align 4
|
||||||
|
%d = alloca double, align 8
|
||||||
|
%blockret1 = alloca double, align 8
|
||||||
|
%a2 = alloca double, align 8
|
||||||
|
%d2 = alloca double, align 8
|
||||||
|
%blockret4 = alloca double, align 8
|
||||||
|
%a5 = alloca double, align 8
|
||||||
|
%z = alloca i16, align 2
|
||||||
|
%blockret7 = alloca i16, align 2
|
||||||
|
%a8 = alloca i16, align 2
|
||||||
|
store i32 0, i32* %a, align 4
|
||||||
|
%0 = load i32, i32* %a, align 4
|
||||||
|
store i32 %0, i32* %blockret, align 4
|
||||||
|
br label %expr_block.exit
|
||||||
|
|
||||||
|
expr_block.exit: ; preds = %entry
|
||||||
|
%1 = load i32, i32* %blockret, align 4
|
||||||
|
store i32 %1, i32* %x, align 4
|
||||||
|
store double 0.000000e+00, double* %a2, align 8
|
||||||
|
%2 = load double, double* %a2, align 8
|
||||||
|
store double %2, double* %blockret1, align 8
|
||||||
|
br label %expr_block.exit3
|
||||||
|
|
||||||
|
expr_block.exit3: ; preds = %expr_block.exit
|
||||||
|
%3 = load double, double* %blockret1, align 8
|
||||||
|
store double %3, double* %d, align 8
|
||||||
|
store double 0.000000e+00, double* %a5, align 8
|
||||||
|
%4 = load double, double* %a5, align 8
|
||||||
|
store double %4, double* %blockret4, align 8
|
||||||
|
br label %expr_block.exit6
|
||||||
|
|
||||||
|
expr_block.exit6: ; preds = %expr_block.exit3
|
||||||
|
%5 = load double, double* %blockret4, align 8
|
||||||
|
store double %5, double* %d2, align 8
|
||||||
|
store i16 0, i16* %a8, align 2
|
||||||
|
%6 = load i16, i16* %a8, align 2
|
||||||
|
store i16 %6, i16* %blockret7, align 2
|
||||||
|
br label %expr_block.exit9
|
||||||
|
|
||||||
|
expr_block.exit9: ; preds = %expr_block.exit6
|
||||||
|
%7 = load i16, i16* %blockret7, align 2
|
||||||
|
store i16 %7, i16* %z, align 2
|
||||||
|
ret void
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ func void test1()
|
|||||||
{
|
{
|
||||||
char a = 1;
|
char a = 1;
|
||||||
int b = 2;
|
int b = 2;
|
||||||
char c = b > a ? 1 : 0;
|
char c = b > a ? 1u8 : 0u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #expect: comparison_widening.ll
|
// #expect: comparison_widening.ll
|
||||||
|
|||||||
12
test/test_suite/statements/foreach_with_error.c3
Normal file
12
test/test_suite/statements/foreach_with_error.c3
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
module test;
|
||||||
|
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
int[3]! x;
|
||||||
|
int g;
|
||||||
|
foreach (z : x) // #error: It's not possible to enumerate an expression of type 'int[3]!'
|
||||||
|
{
|
||||||
|
g += z;
|
||||||
|
x[0] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
module test;
|
|
||||||
|
|
||||||
func void test()
|
|
||||||
{
|
|
||||||
int[3]! x;
|
|
||||||
int g;
|
|
||||||
foreach (z : x)
|
|
||||||
{
|
|
||||||
g += z;
|
|
||||||
x[0] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// #expect: test.ll
|
|
||||||
|
|
||||||
entry:
|
|
||||||
%x = alloca [3 x i32], align 4
|
|
||||||
%x.f = alloca i64, align 8
|
|
||||||
%g = alloca i32, align 4
|
|
||||||
%idx = alloca i64, align 8
|
|
||||||
%z = alloca i32, align 4
|
|
||||||
store i64 0, i64* %x.f, align 8
|
|
||||||
%0 = bitcast [3 x i32]* %x to i8*
|
|
||||||
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 12, i1 false)
|
|
||||||
store i32 0, i32* %g, align 4
|
|
||||||
%1 = load i64, i64* %x.f, align 8
|
|
||||||
%not_err = icmp eq i64 %1, 0
|
|
||||||
br i1 %not_err, label %after_check, label %foreach.exit
|
|
||||||
|
|
||||||
after_check:
|
|
||||||
store i64 0, i64* %idx, align 8
|
|
||||||
br label %foreach.cond
|
|
||||||
|
|
||||||
foreach.cond:
|
|
||||||
%2 = load i64, i64* %idx, align 8
|
|
||||||
%lt = icmp ult i64 %2, 3
|
|
||||||
br i1 %lt, label %foreach.body, label %foreach.exit
|
|
||||||
|
|
||||||
foreach.body:
|
|
||||||
%3 = getelementptr inbounds i32, [3 x i32]* %x, i64 %2
|
|
||||||
%4 = load i32, i32* %3, align 4
|
|
||||||
store i32 %4, i32* %z, align 4
|
|
||||||
%5 = load i32, i32* %g, align 4
|
|
||||||
%6 = load i32, i32* %z, align 4
|
|
||||||
%add = add i32 %5, %6
|
|
||||||
store i32 %add, i32* %g, align 4
|
|
||||||
%7 = load i64, i64* %x.f, align 8
|
|
||||||
%not_err1 = icmp eq i64 %7, 0
|
|
||||||
br i1 %not_err1, label %after_check2, label %voiderr
|
|
||||||
|
|
||||||
after_check2:
|
|
||||||
%arridx = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 0
|
|
||||||
store i32 1, i32* %arridx, align 4
|
|
||||||
br label %voiderr
|
|
||||||
|
|
||||||
voiderr:
|
|
||||||
br label %foreach.inc
|
|
||||||
|
|
||||||
foreach.inc:
|
|
||||||
%8 = load i64, i64* %idx, align 8
|
|
||||||
%9 = add i64 %8, 1
|
|
||||||
store i64 %9, i64* %idx, align 8
|
|
||||||
br label %foreach.cond
|
|
||||||
|
|
||||||
foreach.exit:
|
|
||||||
ret void
|
|
||||||
@@ -3,7 +3,7 @@ module test;
|
|||||||
func void test1()
|
func void test1()
|
||||||
{
|
{
|
||||||
bool! x = 0;
|
bool! x = 0;
|
||||||
if (x) // #error: 'bool!' cannot be converted into 'bool'
|
if (x) // #error: 'bool!' cannot be converted to 'bool'
|
||||||
{
|
{
|
||||||
x = 100;
|
x = 100;
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ func void test1()
|
|||||||
func void test2()
|
func void test2()
|
||||||
{
|
{
|
||||||
bool! x = 0;
|
bool! x = 0;
|
||||||
while (x) // #error: 'bool!' cannot be converted into 'bool'
|
while (x) // #error: 'bool!' cannot be converted to 'bool'
|
||||||
{
|
{
|
||||||
x = false;
|
x = false;
|
||||||
}
|
}
|
||||||
@@ -30,5 +30,5 @@ func void test3()
|
|||||||
{
|
{
|
||||||
x = !x;
|
x = !x;
|
||||||
}
|
}
|
||||||
while (x); // #error: 'bool!' cannot be converted into 'bool'
|
while (x); // #error: 'bool!' cannot be converted to 'bool'
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ switch.case10: ; preds = %next_if8
|
|||||||
br label %switch.case13
|
br label %switch.case13
|
||||||
|
|
||||||
next_if11: ; preds = %next_if8
|
next_if11: ; preds = %next_if8
|
||||||
%eq12 = icmp eq i64 16, %4
|
%eq12 = icmp eq i64 15, %4
|
||||||
br i1 %eq12, label %switch.case13, label %next_if14
|
br i1 %eq12, label %switch.case13, label %next_if14
|
||||||
|
|
||||||
switch.case13: ; preds = %next_if11, %switch.case10
|
switch.case13: ; preds = %next_if11, %switch.case10
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// #target: x64-darwin
|
||||||
|
|
||||||
char *message0 = """
|
char *message0 = """
|
||||||
hello
|
hello
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ func void test2()
|
|||||||
{
|
{
|
||||||
int[2] a = { 1, 2 };
|
int[2] a = { 1, 2 };
|
||||||
|
|
||||||
int[2] b = 30; // #error: 'compint' into 'int[2]'
|
int[2] b = 30; // #error: 'int' into 'int[2]'
|
||||||
int[2] c = a;
|
int[2] c = a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
enum EnumTestOverflow
|
enum EnumTestOverflow
|
||||||
{
|
{
|
||||||
VALUE = 0x80000000, // #error: The value '2147483648' is out of range for 'int'
|
VALUE = 0x80000000i64, // #error: Cannot narrow 'long' to 'int'
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ func Xe foo(Xe a)
|
|||||||
{
|
{
|
||||||
a.c = 123;
|
a.c = 123;
|
||||||
a.a = 39249;
|
a.a = 39249;
|
||||||
a.b = 12301230123123;
|
a.b = 12301230123123i64;
|
||||||
a.z = 1;
|
a.z = 1;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -106,4 +106,6 @@ bool llvm_link_mingw(const char **args, int arg_count, const char** error_string
|
|||||||
return llvm_link(MINGW, args, arg_count, error_string);
|
return llvm_link(MINGW, args, arg_count, error_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user