TypeInfo gained a span. Hex lexing fixed. Basic block returns fixed. Removal of Ast.exit. Enum parameter list parses. Enum analysis improved. Exit deduction improved. Switch over a bool allowed. Switch analysis improved. Added -% operator. Updated implicit casts. Use of bigint. Signed-unsigned comparisons.

This commit is contained in:
Christoffer Lerno
2020-03-20 17:55:24 +01:00
parent f4b4bab947
commit b1aa64cdcc
25 changed files with 1679 additions and 672 deletions

View File

@@ -84,7 +84,7 @@ add_executable(c3c
src/compiler/llvm_codegen_type.c src/compiler/llvm_codegen_type.c
src/compiler/llvm_codegen_function.c src/compiler/llvm_codegen_function.c
src/build/builder.c src/build/builder.c
src/utils/toml.c src/build/project.c src/build/build_internal.h src/compiler/sema_name_resolution.c src/target_info/target_info.c src/compiler/parse_expr.c src/compiler/parser_internal.h src/compiler/parse_stmt.c src/compiler/sema_passes.c src/compiler/sema_internal.h src/compiler/sema_decls.c src/compiler/sema_types.c src/compiler/sema_stmts.c) src/utils/toml.c src/build/project.c src/build/build_internal.h src/compiler/sema_name_resolution.c src/target_info/target_info.c src/compiler/parse_expr.c src/compiler/parser_internal.h src/compiler/parse_stmt.c src/compiler/sema_passes.c src/compiler/sema_internal.h src/compiler/sema_decls.c src/compiler/sema_types.c src/compiler/sema_stmts.c src/compiler/number.c)
target_compile_options(c3c PRIVATE -Wimplicit-int -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) target_compile_options(c3c PRIVATE -Wimplicit-int -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter)

View File

@@ -0,0 +1,178 @@
module comparisons;
func void test_signed()
{
int a = 0;
int b = 1;
bool ab_gt = a > b;
bool ab_ge = a >= b;
bool ab_le = a <= b;
bool ab_lt = a < b;
bool ab_ne = a != b;
bool ab_eq = a == b;
}
func void test_unsigned()
{
uint a = 0;
uint b = 1;
bool ab_gt = a > b;
bool ab_ge = a >= b;
bool ab_le = a <= b;
bool ab_lt = a < b;
bool ab_ne = a != b;
bool ab_eq = a == b;
}
extern func void printf(char *s);
func void test_signedunsigned()
{
char a = 0 - 1;
byte b = cast(a, byte);
printf("Signed-unsigned -1 0xFF \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 1;
b = 1;
printf("Signed-unsigned 1 1 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 1;
b = 4;
printf("Signed-unsigned 1 4 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 4;
b = 1;
printf("Signed-unsigned 4 1 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 4;
b = 129;
printf("Signed-unsigned 4 129 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 0 - 4;
b = 129;
printf("Signed-unsigned -4 129 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
}
func void test_unsignedsigned()
{
int b = -1;
uint a = cast(b, uint);
printf("Unsigned-signed 0xFFFFFFFF -1 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 1;
b = 1;
printf("Unsigned-signed 1 1 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 4;
b = 1;
printf("Unsigned-signed 4 1 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 1;
b = 4;
printf("Unsigned-signed 1 4 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
a = 0x8000_0001;
b = 4;
printf("Unsigned-signed 0x8000_0001 4 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
b = 0 - 4;
a = 0x8000_0001;
printf("Unsigned-signed 0x8000_0001 -4 \n");
if (a > b) printf("a > b\n");
if (a >= b) printf("a >= b\n");
if (a < b) printf("a < b\n");
if (a <= b) printf("a <= b\n");
if (a != b) printf("a != b\n");
if (a == b) printf("a == b\n");
}
func void main()
{
test_signedunsigned();
test_unsignedsigned();
printf("-- Done ---\n");
}

View File

@@ -1,6 +1,6 @@
module helloworld; module helloworld;
func void printf(char *str); extern func void printf(char *str);
func void main() func void main()
{ {

View File

@@ -38,6 +38,87 @@ struct Teob
int oekfeo; int oekfeo;
} }
enum EnumTest : long
{
VALUE1 = 4,
VALUE2
}
enum EnumTestDefault
{
VALUE,
VALUE2
}
enum EnumTestNoOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestSmall : ushort
{
VALUE = 0xFF,
VALUE2 = 0xFFFF
}
enum EnumWithData : ushort (int a, char[] x, long b = 4)
{
// Currently the args are ignored TODO!
TEST1(42, "hello", 328) = 3,
TEST2(12, "world")
}
/* ERRORS
enum EnumWithErrorData : int (int
{
TEST
}
enum EnumWithErrorWithMissingName : int (int)
{
TEST
}
enum EnumTestNoOverflowAfterULong : ulong
{
VALUE = 0xFFFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestOverflow
{
VALUE = 0x80000000,
}
enum EnumTestOverflowAfter
{
VALUE = 0x80000000 - 1,
VALUE_EXCEED
}
enum EnumTestOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFF,
VALUE_EXCEED
}
enum EnumTestOverflowAfterULong : ulong
{
VALUE = 0xFFFF_FFFF_FFFF_FFFF,
VALUE_EXCEED
}
enum EnumTestErrorType : float
{
VALUE_BOOM
}
*/
error Error error Error
{ {
BLURB, BLURB,
@@ -60,6 +141,71 @@ func int borok() throws
{ {
return 1; return 1;
} }
func void testNoReturn()
{
int i = 0;
}
func int testReturn()
{
int i = 0;
return i;
}
func int testReturnWithOtherAtEnd()
{
int i = 0;
return i;
if (i == 10) i++;
i = i + 2;
}
func int testReturnWithError() throws Error
{
int i = 0;
throw Error.NO_SUCH_FILE;
i = i + 1;
}
func int testReturnWithConditional()
{
int i = 0;
if (i > 0)
{
return 1;
}
else
{
return 2;
}
}
func int testReturnWithCondThrow() throws Error
{
int i = 0;
if (i > 0)
{
throw Error.NO_SUCH_FILE;
}
else
{
throw Error.NO_SUCH_FILE;
}
}
func int testReturnSwitch()
{
int i = 0;
switch (i)
{
case 1:
return 2;
case 2:
return 3;
default:
return 4;
}
}
func int barok() throws Error, OtherError func int barok() throws Error, OtherError
{ {
@@ -281,6 +427,7 @@ func int main(int x)
{ {
int efd = 9; int efd = 9;
int okfe = 1; int okfe = 1;
return 1;
switch (int bobe = okfe > 0 ? 1 : 0) switch (int bobe = okfe > 0 ? 1 : 0)
{ {
case 0: case 0:
@@ -304,7 +451,6 @@ func int main(int x)
printf("default\n"); printf("default\n");
break; break;
} }
return 1;
int aa = x++; int aa = x++;
int bb = x--; int bb = x--;
int cc = ++x; int cc = ++x;
@@ -377,6 +523,7 @@ int i = 0;
EX: EX:
printf("EX\n"); printf("EX\n");
goto YEF; goto YEF;
return 1;
} }
func void test2(int* x, int y, int z) func void test2(int* x, int y, int z)

View File

@@ -256,6 +256,7 @@ UnaryOp unary_op[TOKEN_LAST + 1] = {
[TOKEN_BIT_NOT] = UNARYOP_BITNEG, [TOKEN_BIT_NOT] = UNARYOP_BITNEG,
[TOKEN_NOT] = UNARYOP_NOT, [TOKEN_NOT] = UNARYOP_NOT,
[TOKEN_MINUS] = UNARYOP_NEG, [TOKEN_MINUS] = UNARYOP_NEG,
[TOKEN_MINUS_MOD] = UNARYOP_NEGMOD,
[TOKEN_PLUSPLUS] = UNARYOP_INC, [TOKEN_PLUSPLUS] = UNARYOP_INC,
[TOKEN_MINUSMINUS] = UNARYOP_DEC, [TOKEN_MINUSMINUS] = UNARYOP_DEC,
}; };
@@ -411,9 +412,6 @@ void fprint_type_recursive(FILE *file, Type *type, int indent)
case TYPE_IXX: case TYPE_IXX:
fprintf_indented(file, indent, "(comp time int)\n"); fprintf_indented(file, indent, "(comp time int)\n");
break; break;
case TYPE_UXX:
fprintf_indented(file, indent, "(comp time uint)\n");
break;
case TYPE_FXX: case TYPE_FXX:
fprintf_indented(file, indent, "(comp time float)\n"); fprintf_indented(file, indent, "(comp time float)\n");
break; break;
@@ -530,31 +528,8 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
break; break;
case EXPR_CONST: case EXPR_CONST:
fprintf_indented(file, indent, "(const "); fprintf_indented(file, indent, "(const ");
switch (expr->const_expr.type) expr_const_fprint(file, &expr->const_expr);
{ fprintf(file, "\n");
case CONST_NIL:
fprintf(file, "nil\n");
break;
case CONST_BOOL:
fprintf(file, expr->const_expr.b ? "true\n" : "false\n");
break;
case CONST_INT:
if (expr->type->type_kind >= TYPE_U8 && expr->type->type_kind <= TYPE_UXX)
{
fprintf(file, "%llu\n", (unsigned long long)expr->const_expr.i);
}
else
{
fprintf(file, "%lld\n", (long long)expr->const_expr.i);
}
break;
case CONST_FLOAT:
fprintf(file, "%Lf\n", expr->const_expr.f);
break;
case CONST_STRING:
fprintf(file, "%s\n", expr->const_expr.string.chars);
break;
}
fprint_expr_common(file, expr, indent + 1); fprint_expr_common(file, expr, indent + 1);
break; break;
case EXPR_BINARY: case EXPR_BINARY:

View File

@@ -129,7 +129,7 @@ void bigint_init_bigint(BigInt *dest, const BigInt *src)
{ {
return bigint_init_unsigned(dest, 0); return bigint_init_unsigned(dest, 0);
} }
else if (src->digit_count == 1) if (src->digit_count == 1)
{ {
dest->digit_count = 1; dest->digit_count = 1;
dest->digit = src->digit; dest->digit = src->digit;
@@ -1878,6 +1878,65 @@ void bigint_print(BigInt *bigint, uint64_t base)
} }
} }
const char *bigint_to_error_string(const BigInt *bigint, uint64_t base)
{
if (bigint->digit_count == 0)
{
return "0";
}
if (bigint->digit_count == 1 && base == 10)
{
char *res = NULL;
asprintf(&res, "%" PRIu64, bigint->digit);
return res;
}
size_t len = bigint->digit_count * 64;
char *start = malloc_arena(len);
char *buf = start;
BigInt digit_bi = { 0 };
BigInt a1 = { 0 };
BigInt a2 = { 0 };
BigInt *a = &a1;
BigInt *other_a = &a2;
bigint_init_bigint(a, bigint);
BigInt base_bi = { 0 };
bigint_init_unsigned(&base_bi, 10);
for (;;)
{
bigint_rem(&digit_bi, a, &base_bi);
uint8_t digit = (uint8_t)bigint_as_unsigned(&digit_bi);
*(buf++) = digit_to_char(digit, false);
bigint_div_trunc(other_a, a, &base_bi);
{
BigInt *tmp = a;
a = other_a;
other_a = tmp;
}
if (bigint_cmp_zero(a) == CMP_EQ)
{
break;
}
}
// reverse
char *out = malloc_arena(buf - start + 2);
char *current = out;
if (bigint->is_negative)
{
*(current++) = '-';
}
for (char *ptr = buf - 1; ptr >= start; ptr--)
{
*(current++) = *ptr;
}
*(current++) = '\0';
return current;
}
void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base) void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base)
{ {
if (bigint->digit_count == 0) if (bigint->digit_count == 0)

View File

@@ -6,16 +6,6 @@
#include "compiler_internal.h" #include "compiler_internal.h"
typedef struct _BigInt
{
unsigned digit_count;
bool is_negative;
union {
uint64_t digit;
uint64_t *digits;
};
} BigInt;
typedef enum _CmpRes typedef enum _CmpRes
{ {
CMP_LT, CMP_LT,
@@ -54,6 +44,7 @@ bool bigint_eql(BigInt a, BigInt b);
CmpRes bigint_cmp(const BigInt *op1, const BigInt *op2); CmpRes bigint_cmp(const BigInt *op1, const BigInt *op2);
CmpRes bigint_cmp_zero(const BigInt *op); CmpRes bigint_cmp_zero(const BigInt *op);
uint32_t bigint_hash(BigInt x); 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_print(BigInt *bigint, uint64_t base);
void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base); void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base);
uint64_t bigint_as_unsigned(const BigInt *bigint); uint64_t bigint_as_unsigned(const BigInt *bigint);

View File

@@ -3,9 +3,11 @@
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include "compiler_internal.h" #include "compiler_internal.h"
#include "bigint.h"
#define EXIT_T_MISMATCH() return sema_type_mismatch(left, canonical, cast_type) #define EXIT_T_MISMATCH() return sema_type_mismatch(left, canonical, cast_type)
#define IS_EXPLICT()
#define RETURN_NON_CONST_CAST(kind) do { if (left->expr_kind == EXPR_CONST) { insert_cast(left, kind, canonical); return true; } } while (0)
static inline void insert_cast(Expr *expr, CastKind kind, Type *canonical) static inline void insert_cast(Expr *expr, CastKind kind, Type *canonical)
{ {
@@ -48,33 +50,28 @@ bool erro(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
EXIT_T_MISMATCH(); EXIT_T_MISMATCH();
} }
bool ptxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) bool ptxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_PTRXI);
{
assert(left->const_expr.type == CONST_NIL); assert(left->const_expr.kind == TYPE_POINTER);
left->const_expr.type = sign_from_type(canonical); expr_const_set_int(&left->const_expr, 0, type->type_kind);
left->const_expr.i = 0; left->type = type;
left->type = type;
return true;
}
insert_cast(left, CAST_PTRXI, canonical);
return true; return true;
} }
bool ptbo(Expr* left, Type *ignored, Type *canonical, Type *type, CastType cast_type) bool ptbo(Expr *left, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_PTRBOOL);
{
assert(left->const_expr.type == CONST_NIL); assert(left->const_expr.kind == TYPE_POINTER);
left->const_expr.type = CONST_BOOL; left->const_expr.b = false;
left->const_expr.b = false;
left->type = type; left->type = type;
return true;
}
insert_cast(left, CAST_PTRBOOL, canonical);
return true; return true;
} }
@@ -136,18 +133,15 @@ bool ptpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastTyp
{ {
return sema_type_mismatch(left, type, cast_type); return sema_type_mismatch(left, type, cast_type);
} }
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_PTRPTR);
{ assert(left->const_expr.kind == TYPE_POINTER);
assert(left->const_expr.type == CONST_NIL); left->type = type;
left->type = type;
return true;
}
insert_cast(left, CAST_PTRPTR, canonical);
return true; return true;
} }
bool strpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) bool strpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type)
{ {
// TODO // TODO
insert_cast(left, CAST_PTRPTR, canonical); insert_cast(left, CAST_PTRPTR, canonical);
return true; return true;
@@ -163,284 +157,272 @@ bool stpt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
return true; return true;
} }
void const_int_to_fp_cast(Expr *left, Type *canonical, Type *type)
bool boxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); long double f = bigint_as_float(&left->const_expr.i);
if (left->expr_kind == EXPR_CONST) switch (canonical->type_kind)
{ {
assert(left->const_expr.type == CONST_BOOL); case TYPE_F32:
left->const_expr.type = CONST_INT; left->const_expr.f = (float)f;
left->const_expr.i = left->const_expr.b ? 1 : 0; break;
left->type = type; case TYPE_F64:
return true; left->const_expr.f = (double)f;
break;
default:
left->const_expr.f = f;
break;
} }
insert_cast(left, CAST_BOOLINT, canonical); left->type = type;
left->const_expr.kind = canonical->type_kind;
}
/**
* Bool into a signed or unsigned int. Explicit conversions only.
* @return true unless this is not an explicit conversion.
*/
bool boxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
{
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
RETURN_NON_CONST_CAST(CAST_BOOLINT);
assert(left->const_expr.kind == TYPE_BOOL);
expr_const_set_int(&left->const_expr, left->const_expr.b ? 1 : 0, canonical->type_kind);
left->type = type;
return true; return true;
} }
bool bofp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) /**
* Bool into a float. Explicit conversions only.
* @return true unless this is not an explicit conversion.
*/
bool bofp(Expr *left, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_BOOLFP);
{
assert(left->const_expr.type == CONST_NIL); assert(left->const_expr.kind == TYPE_BOOL);
left->const_expr.type = CONST_FLOAT; expr_const_set_float(&left->const_expr, left->const_expr.b ? 1.0 : 0.0, canonical->type_kind);
left->const_expr.f = left->const_expr.b ? 1.0 : 0.0; left->type = type;
left->type = type;
return true;
}
insert_cast(left, CAST_BOOLFP, canonical);
return true; return true;
} }
bool xibo(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) /**
* Convert from any into to bool.
* @return true for any implicit conversion except assign and assign add.
*/
bool xibo(Expr *left, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_INTBOOL);
{
assert(left->const_expr.type == CONST_INT); expr_const_set_bool(&left->const_expr, bigint_cmp_zero(&left->const_expr.i) != CMP_EQ);
left->const_expr.type = CONST_BOOL; left->type = type;
left->const_expr.b = left->const_expr.i != 0;
left->type = type;
return true;
}
insert_cast(left, CAST_INTBOOL, canonical);
return true; return true;
} }
bool fpbo(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) /**
* Convert from any float to bool
* @return true for any implicit conversion except assign and assign add
*/
bool fpbo(Expr *left, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_FPBOOL);
{
assert(left->const_expr.type == CONST_FLOAT); expr_const_set_bool(&left->const_expr, left->const_expr.f != 0.0);
left->const_expr.type = CONST_BOOL; left->type = type;
left->const_expr.b = left->const_expr.f != 0;
left->type = type;
return true;
}
insert_cast(left, CAST_INTBOOL, canonical);
return true; return true;
} }
/**
* Convert from any fp to fp
* @return true for all except implicit assign (but allowing assign add)
*/
bool fpfp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) bool fpfp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{ {
bool is_narrowing = from->builtin.bytesize < canonical->builtin.bytesize && from->type_kind != TYPE_FXX; bool is_narrowing = from->builtin.bytesize < canonical->builtin.bytesize && from->type_kind != TYPE_FXX;
// Is this correct? TODO
if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_FPFP);
{
assert(left->const_expr.type == CONST_FLOAT); expr_const_set_float(&left->const_expr, left->const_expr.f, canonical->type_kind);
if (type->type_kind == TYPE_F32) left->type = type;
{
left->const_expr.f = (float)left->const_expr.f;
}
left->type = type;
return true;
}
insert_cast(left, CAST_FPFP, canonical);
return true; return true;
} }
bool fpui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) /**
* Convert from any floating point to int
* @return true only on explicit conversions.
*/
bool fpxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST) RETURN_NON_CONST_CAST(CAST_FPUI);
assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_U64);
long double d = left->const_expr.f;
BigInt temp;
if (canonical->type_kind >= TYPE_U8)
{ {
assert(left->const_expr.type == CONST_FLOAT); bigint_init_unsigned(&temp, (uint64_t)d);
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64); bigint_truncate(&left->const_expr.i, &temp, canonical->builtin.bitsize, false);
left->const_expr.i = (uint64_t)left->const_expr.f;
left->type = type;
return true;
} }
insert_cast(left, CAST_FPUI, canonical); else
{
bigint_init_signed(&temp, (int64_t)d);
bigint_truncate(&left->const_expr.i, &temp, canonical->builtin.bitsize, true);
}
left->const_expr.kind = canonical->type_kind;
left->type = type;
return true; return true;
} }
bool fpsi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
/**
* Convert from compile time int to any signed or unsigned int
* @return true unless the conversion was lossy.
*/
bool ixxxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
{ {
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); bool is_signed = canonical->type_kind < TYPE_U8;
if (left->expr_kind == EXPR_CONST) int bitsize = canonical->builtin.bitsize;
if (cast_is_implicit(cast_type) && !bigint_fits_in_bits(&left->const_expr.i, bitsize, is_signed))
{ {
assert(left->const_expr.type == CONST_FLOAT); SEMA_ERROR(left, "'%s' does not fit into '%s'", expr_const_to_error_string(&left->const_expr), canonical->name);
assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64); return false;
left->const_expr.i = (uint64_t)((int64_t)left->const_expr.f);
left->type = type;
return true;
} }
insert_cast(left, CAST_FPUI, canonical); BigInt temp;
bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, is_signed);
left->const_expr.i = temp;
left->const_expr.kind = canonical->type_kind;
left->type = type;
return true; return true;
} }
static uint64_t type_mask[4] = { 0xFF, 0xFFFF, 0xFFFFFFFFU, 0xFFFFFFFFFFFFFFFFLLU}; /**
static int64_t int_type_max[4] = { INT8_MAX, INT16_MAX, INT32_MAX, INT64_MAX }; * Cast signed int -> signed int
static uint64_t uint_type_max[4] = { UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX }; * @return true if this is a widening, an explicit cast or if it is an implicit assign add
static int64_t int_type_min[4] = { INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN }; */
bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{ {
bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize && from->type_kind != TYPE_IXX; bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH(); if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST)
{ RETURN_NON_CONST_CAST(CAST_SISI);
int64_t i = (int64_t)left->const_expr.i;
int index = canonical->type_kind - TYPE_I8; BigInt temp;
if (from->type_kind == TYPE_IXX) bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, true);
{ left->const_expr.i = temp;
if ((i > int_type_max[index]) || (i < int_type_min[index])) left->const_expr.kind = canonical->type_kind;
{ left->type = type;
SEMA_ERROR(left, "'%lld' does not fit into '%s'", i, canonical->name);
return false;
}
}
assert(left->const_expr.type == CONST_INT);
assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64);
uint64_t mask = type_mask[index];
if (i < 0)
{
left->const_expr.i = ~((~((uint64_t)i)) & mask);
}
else
{
left->const_expr.i &= mask;
}
left->type = type;
return true;
}
assert(from->type_kind != TYPE_IXX);
insert_cast(left, CAST_SISI, canonical);
return true;
}
bool siui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
bool is_narrowing = from->builtin.bytesize < canonical->builtin.bytesize && from->type_kind != TYPE_IXX;
if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH();
if (left->expr_kind == EXPR_CONST)
{
assert(left->const_expr.type == CONST_INT);
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64);
left->const_expr.i &= type_mask[canonical->type_kind - TYPE_U8];
left->type = type;
return true;
}
insert_cast(left, CAST_SIUI, canonical);
return true;
}
bool xiptr(Expr* left, Type *from, Type *canonical, Type *type)
{
if (left->expr_kind == EXPR_CONST)
{
assert(left->const_expr.type == CONST_INT);
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64);
assert(left->const_expr.i == 0);
left->const_expr.type = CONST_NIL;
left->type = type;
return true;
}
insert_cast(left, CAST_XIPTR, canonical);
return true;
}
bool sifp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
// TODO
if (left->expr_kind == EXPR_CONST)
{
assert(left->const_expr.type == CONST_INT);
assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_FXX);
if (left->const_expr.i > (uint64_t)INT64_MAX)
{
left->const_expr.f = -((long double)(~left->const_expr.i));
}
else
{
left->const_expr.f = left->const_expr.i;
}
left->const_expr.type = CONST_FLOAT;
left->type = type;
return true;
}
insert_cast(left, CAST_SIFP, canonical);
return true;
}
bool uisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
if (left->expr_kind == EXPR_CONST)
{
assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64);
int index = canonical->type_kind - TYPE_I8;
uint64_t mask = type_mask[index];
if (cast_type != CAST_TYPE_EXPLICIT && from->type_kind == TYPE_UXX)
{
if (left->const_expr.i > (uint64_t)int_type_max[index])
{
SEMA_ERROR(left, "Cannot implicitly convert value '%llu' into %s - it will not fit.", left->const_expr.i, type_to_error_string(type));
return false;
}
}
if (left->const_expr.i > (uint64_t)INT64_MAX)
{
left->const_expr.i = ~((~left->const_expr.i) & mask);
}
else
{
left->const_expr.i &= mask;
}
left->type = type;
return true;
}
insert_cast(left, CAST_UISI, canonical);
return true; return true;
} }
/**
* Cast unsigned int -> unsigned int
* @return true if this was not a narrowing implicit assign or narrowing implicit assign add
*/
bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{ {
if (left->expr_kind == EXPR_CONST) bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
{
assert(left->const_expr.type == CONST_INT && type_is_unsigned(from)); if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH();
assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64);
int index = canonical->type_kind - TYPE_U8; RETURN_NON_CONST_CAST(CAST_UIUI);
if (cast_type != CAST_TYPE_EXPLICIT && from->type_kind == TYPE_UXX)
{ BigInt temp;
if (left->const_expr.i > uint_type_max[index]) bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, false);
{ left->const_expr.i = temp;
SEMA_ERROR(left, "Cannot implicitly convert value '%llu' into %s - it will not fit.", type_to_error_string(type)); left->const_expr.kind = canonical->type_kind;
return false; left->type = type;
}
}
left->const_expr.i &= type_mask[index];
left->type = type;
return true;
}
insert_cast(left, CAST_UIUI, canonical);
return true; return true;
} }
bool uifp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) /**
* Cast unsigned int -> signed int
* @return true if this is an explicit cast or if it is an implicit assign add or if it is a widening cast.
*/
bool uisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{ {
TODO bool is_widening = from->builtin.bytesize < canonical->builtin.bytesize;
if (left->expr_kind == EXPR_CONST)
{ if (!is_widening && cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
assert(left->const_expr.type == CONST_INT && type_is_unsigned(from));
assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64); RETURN_NON_CONST_CAST(CAST_UISI);
left->const_expr.f = left->const_expr.i;
left->type = type; BigInt temp;
return true; bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, true);
} left->const_expr.i = temp;
insert_cast(left, CAST_UIFP, canonical); left->const_expr.kind = canonical->type_kind;
left->type = type;
return true; return true;
} }
/*
* Cast signed int -> unsigned int
* @return true if this was an implicit add or or explicit cast.
*/
bool siui(Expr *left, Type *canonical, Type *type, CastType cast_type)
{
if (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
RETURN_NON_CONST_CAST(CAST_SIUI);
BigInt temp;
bigint_truncate(&temp, &left->const_expr.i, canonical->builtin.bitsize, false);
left->const_expr.i = temp;
left->const_expr.kind = canonical->type_kind;
left->type = type;
return true;
}
/**
* Cast a signed or unsigned integer -> floating point
* @return true always
*/
bool sifp(Expr *left, Type *canonical, Type *type)
{
RETURN_NON_CONST_CAST(CAST_SIFP);
const_int_to_fp_cast(left, canonical, type);
return true;
}
/**
* Cast a signed or unsigned integer -> floating point
* @return true always
*/
bool uifp(Expr *left, Type *canonical, Type *type)
{
RETURN_NON_CONST_CAST(CAST_UIFP);
const_int_to_fp_cast(left, canonical, type);
return true;
}
bool ixxfp(Expr *left, Type *canonical, Type *type, CastType cast_type)
{
assert(type_is_float(canonical));
assert(left->expr_kind == EXPR_CONST);
const_int_to_fp_cast(left, canonical, type);
return true;
}
/**
* Convert a compile time into to a boolean.
* @return true always
*/
bool ixxbo(Expr *left, Type *type)
{
assert(left->expr_kind == EXPR_CONST);
expr_const_set_bool(&left->const_expr, bigint_cmp_zero(&left->const_expr.i) != CMP_EQ);
left->type = type;
return true;
}
bool ussi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) bool ussi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{ {
if (type->type_kind != TYPE_ENUM) return sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT); if (type->type_kind != TYPE_ENUM) return sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT);
@@ -451,7 +433,7 @@ bool ussi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
// TODO // TODO
Expr *value = left->identifier_expr.decl->enum_constant.expr; Expr *value = left->identifier_expr.decl->enum_constant.expr;
assert(value->expr_kind == EXPR_CONST); assert(value->expr_kind == EXPR_CONST);
assert(value->const_expr.type == CONST_INT); // assert(value->const_expr.type == CONST_INT);
left->const_expr.i = value->const_expr.i; left->const_expr.i = value->const_expr.i;
// TODO narrowing // TODO narrowing
} }
@@ -469,9 +451,21 @@ bool uius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
TODO TODO
} }
bool xipt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) /**
* Cast comptime, signed or unsigned -> pointer.
* @return true unless the constant value evaluates to zero.
*/
bool xipt(Expr *left, Type *canonical, Type *type)
{ {
TODO RETURN_NON_CONST_CAST(CAST_XIPTR);
if (bigint_cmp_zero(&left->const_expr.i) != CMP_EQ)
{
SEMA_ERROR(left, "Only constants evaluating to zero can be cast to pointers.");
return false;
}
expr_const_set_nil(&left->const_expr);
left->type = type;
return true;
} }
bool usus(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) bool usus(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
@@ -547,8 +541,6 @@ bool cast_to_runtime(Expr *expr)
{ {
case TYPE_IXX: case TYPE_IXX:
return cast(expr, type_long, CAST_TYPE_IMPLICIT); return cast(expr, type_long, CAST_TYPE_IMPLICIT);
case TYPE_UXX:
return cast(expr, type_ulong, CAST_TYPE_IMPLICIT);
case TYPE_FXX: case TYPE_FXX:
return cast(expr, type_double, CAST_TYPE_IMPLICIT); return cast(expr, type_double, CAST_TYPE_IMPLICIT);
default: default:
@@ -585,16 +577,15 @@ CastKind cast_to_bool_kind(Type *type)
return CAST_ERROR; return CAST_ERROR;
case TYPE_BOOL: case TYPE_BOOL:
UNREACHABLE UNREACHABLE
case TYPE_IXX:
case TYPE_I8: case TYPE_I8:
case TYPE_I16: case TYPE_I16:
case TYPE_I32: case TYPE_I32:
case TYPE_I64: case TYPE_I64:
case TYPE_IXX:
case TYPE_U8: case TYPE_U8:
case TYPE_U16: case TYPE_U16:
case TYPE_U32: case TYPE_U32:
case TYPE_U64: case TYPE_U64:
case TYPE_UXX:
return CAST_INTBOOL; return CAST_INTBOOL;
case TYPE_F32: case TYPE_F32:
case TYPE_F64: case TYPE_F64:
@@ -618,44 +609,49 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
case TYPE_META_TYPE: case TYPE_META_TYPE:
break; break;
case TYPE_BOOL: case TYPE_BOOL:
if (type_is_integer(canonical)) return boxi(expr, from_type, canonical, to_type, cast_type); // Bool may convert into integers and floats but only explicitly.
if (type_is_float(canonical)) return bofp(expr, from_type, canonical, to_type, cast_type); if (type_is_integer(canonical)) return boxi(expr, canonical, to_type, cast_type);
if (type_is_float(canonical)) return bofp(expr, canonical, to_type, cast_type);
break; break;
case TYPE_ERROR_UNION: case TYPE_ERROR_UNION:
TODO TODO
case TYPE_IXX:
// Compile time integers may convert into ints, floats, bools
if (type_is_integer(canonical)) return ixxxi(expr, canonical, to_type, cast_type);
if (type_is_float(canonical)) return ixxfp(expr, canonical, to_type, cast_type);
if (canonical == type_bool) return ixxbo(expr, to_type);
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, canonical, to_type);
break;
case TYPE_I8: case TYPE_I8:
case TYPE_I16: case TYPE_I16:
case TYPE_I32: case TYPE_I32:
case TYPE_I64: case TYPE_I64:
case TYPE_IXX: if (type_is_unsigned_integer(canonical)) return siui(expr, canonical, to_type, cast_type);
if (type_is_unsigned_integer(canonical)) return siui(expr, from_type, canonical, to_type, cast_type);
if (type_is_signed_integer(canonical)) return sisi(expr, from_type, canonical, to_type, cast_type); if (type_is_signed_integer(canonical)) return sisi(expr, from_type, canonical, to_type, cast_type);
if (type_is_float(canonical)) return sifp(expr, from_type, canonical, to_type, cast_type); if (type_is_float(canonical)) return sifp(expr, canonical, to_type);
if (canonical == type_bool) return xibo(expr, from_type, canonical, to_type, cast_type); if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_POINTER) return ptxi(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_POINTER) return xipt(expr, canonical, to_type);
break; break;
case TYPE_U8: case TYPE_U8:
case TYPE_U16: case TYPE_U16:
case TYPE_U32: case TYPE_U32:
case TYPE_U64: case TYPE_U64:
case TYPE_UXX:
if (type_is_unsigned_integer(canonical)) return uiui(expr, from_type, canonical, to_type, cast_type); if (type_is_unsigned_integer(canonical)) return uiui(expr, from_type, canonical, to_type, cast_type);
if (type_is_signed_integer(canonical)) return uisi(expr, from_type, canonical, to_type, cast_type); if (type_is_signed_integer(canonical)) return uisi(expr, from_type, canonical, to_type, cast_type);
if (type_is_float(canonical)) return uifp(expr, from_type, canonical, to_type, cast_type); if (type_is_float(canonical)) return uifp(expr, canonical, to_type);
if (canonical == type_bool) return xibo(expr, from_type, canonical, to_type, cast_type); if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_POINTER) return ptxi(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_POINTER) return xipt(expr, canonical, to_type);
break; break;
case TYPE_F32: case TYPE_F32:
case TYPE_F64: case TYPE_F64:
case TYPE_FXX: case TYPE_FXX:
if (type_is_unsigned_integer(canonical)) return fpui(expr, from_type, canonical, to_type, cast_type); if (type_is_integer(canonical)) return fpxi(expr, canonical, to_type, cast_type);
if (type_is_signed_integer(canonical)) return fpsi(expr, from_type, canonical, to_type, cast_type); if (canonical == type_bool) return fpbo(expr, canonical, to_type, cast_type);
if (canonical == type_bool) return fpbo(expr, from_type, canonical, to_type, cast_type);
if (type_is_float(canonical)) return fpfp(expr, from_type, canonical, to_type, cast_type); if (type_is_float(canonical)) return fpfp(expr, from_type, canonical, to_type, cast_type);
break; break;
case TYPE_POINTER: case TYPE_POINTER:
if (type_is_integer(canonical)) return ptxi(expr, from_type, canonical, to_type, cast_type); if (type_is_integer(canonical)) return ptxi(expr, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_BOOL) return ptbo(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_BOOL) return ptbo(expr, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_POINTER) return ptpt(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_POINTER) return ptpt(expr, from_type, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_FUNC) return ptfu(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_FUNC) return ptfu(expr, from_type, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_VARARRAY) return ptva(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_VARARRAY) return ptva(expr, from_type, canonical, to_type, cast_type);
@@ -667,7 +663,7 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
if (type_is_integer(canonical)) return erxi(expr, from_type, canonical, to_type, cast_type); if (type_is_integer(canonical)) return erxi(expr, from_type, canonical, to_type, cast_type);
break; break;
case TYPE_FUNC: case TYPE_FUNC:
if (type_is_integer(canonical)) return ptxi(expr, from_type, canonical, to_type, cast_type); if (type_is_integer(canonical)) return ptxi(expr, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_POINTER) return fupt(expr, from_type, canonical, to_type, cast_type); if (canonical->type_kind == TYPE_POINTER) return fupt(expr, from_type, canonical, to_type, cast_type);
break; break;
case TYPE_STRUCT: case TYPE_STRUCT:

View File

@@ -32,6 +32,33 @@ typedef struct _Type Type;
typedef bool(*CastFunc)(Expr *, Type *, Type *, Type *, CastType cast_type); typedef bool(*CastFunc)(Expr *, Type *, Type *, Type *, CastType cast_type);
typedef struct _BigInt
{
unsigned digit_count;
bool is_negative;
union {
uint64_t digit;
uint64_t *digits;
};
} BigInt;
typedef struct
{
union
{
long double f;
BigInt i;
bool b;
struct
{
char* chars;
int len;
} string;
};
TypeKind kind;
} ExprConst;
typedef struct typedef struct
{ {
SourceLoc loc; SourceLoc loc;
@@ -132,18 +159,24 @@ typedef struct
struct _Type struct _Type
{ {
TypeKind type_kind : 8; TypeKind type_kind : 8;
struct _Type *canonical; Type *canonical;
const char *name; const char *name;
struct _Type **type_cache; Type **type_cache;
void *backend_type; void *backend_type;
void *backend_debug_type; void *backend_debug_type;
union union
{ {
// Error, Struct, Union, Typedef
Decl *decl; Decl *decl;
// int, float, bool
TypeBuiltin builtin; TypeBuiltin builtin;
// Type[], Type[*], Type[123]
TypeArray array; TypeArray array;
// func Type1(Type2, Type3, ...) throws Err1, Err2, ...
TypeFunc func; TypeFunc func;
// Type*
Type *pointer; Type *pointer;
// Type.type
Type *child; Type *child;
}; };
}; };
@@ -153,6 +186,7 @@ struct _TypeInfo
ResolveStatus resolve_status : 2; ResolveStatus resolve_status : 2;
Type *type; Type *type;
TypeInfoKind kind; TypeInfoKind kind;
SourceRange span;
union union
{ {
TypeUnresolved unresolved; TypeUnresolved unresolved;
@@ -217,7 +251,6 @@ typedef struct
typedef struct typedef struct
{ {
Decl *parent;
Expr *expr; Expr *expr;
Expr **args; Expr **args;
uint64_t ordinal; uint64_t ordinal;
@@ -403,21 +436,7 @@ typedef struct
PostUnaryOp operator; PostUnaryOp operator;
} ExprPostUnary; } ExprPostUnary;
typedef struct
{
union
{
long double f;
uint64_t i;
bool b;
struct
{
char* chars;
int len;
} string;
};
ConstType type : 3;
} ExprConst;
typedef struct typedef struct
{ {
@@ -700,7 +719,6 @@ typedef struct _Ast
{ {
SourceRange span; SourceRange span;
AstKind ast_kind : 8; AstKind ast_kind : 8;
ExitType exit : 3;
union union
{ {
AstAttribute attribute; AstAttribute attribute;
@@ -872,7 +890,7 @@ extern Type *type_bool, *type_void, *type_string, *type_voidptr;
extern Type *type_float, *type_double; extern Type *type_float, *type_double;
extern Type *type_char, *type_short, *type_int, *type_long, *type_isize; extern Type *type_char, *type_short, *type_int, *type_long, *type_isize;
extern Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize; extern Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
extern Type *type_compint, *type_compuint, *type_compfloat; extern Type *type_compint, *type_compfloat;
extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong; extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
extern Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong; extern Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
@@ -899,7 +917,6 @@ static inline Ast *new_ast(AstKind kind, SourceRange range)
memset(ast, 0, sizeof(Ast)); memset(ast, 0, sizeof(Ast));
ast->span = range; ast->span = range;
ast->ast_kind = kind; ast->ast_kind = kind;
ast->exit = EXIT_NONE;
return ast; return ast;
} }
@@ -953,24 +970,22 @@ static inline bool builtin_may_bit_negate(Type *canonical)
case TYPE_U16: case TYPE_U16:
case TYPE_U32: case TYPE_U32:
case TYPE_U64: case TYPE_U64:
case TYPE_UXX:
return true; return true;
default: default:
return false; return false;
} }
} }
static inline ConstType sign_from_type(Type *type)
{
assert(type->canonical == type);
return (type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX) ? CONST_INT : CONST_INT;
}
bool cast_implicit(Expr *expr, Type *to_type); bool cast_implicit(Expr *expr, Type *to_type);
bool cast(Expr *expr, Type *to_type, CastType cast_type); bool cast(Expr *expr, Type *to_type, CastType cast_type);
bool cast_binary_arithmetic(Expr *left, Expr *right, const char *action); bool cast_binary_arithmetic(Expr *left, Expr *right, const char *action);
CastKind cast_to_bool_kind(Type *type); CastKind cast_to_bool_kind(Type *type);
bool cast_to_runtime(Expr *expr); bool cast_to_runtime(Expr *expr);
static inline bool cast_is_implicit(CastType cast_type)
{
return cast_type == CAST_TYPE_IMPLICIT_ASSIGN_ADD || cast_type == CAST_TYPE_IMPLICIT || cast_type == CAST_TYPE_IMPLICIT_ASSIGN;
}
void llvm_codegen(Context *context); void llvm_codegen(Context *context);
void llvm_set_struct_size_alignment(Decl *decl); void llvm_set_struct_size_alignment(Decl *decl);
@@ -1027,6 +1042,14 @@ static inline void expr_replace(Expr *expr, Expr *replacement)
*expr = *replacement; *expr = *replacement;
expr->span = loc; expr->span = loc;
} }
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind);
void expr_const_set_float(ExprConst *expr, long double d, TypeKind kind);
void expr_const_set_bool(ExprConst *expr, bool b);
void expr_const_set_nil(ExprConst *expr);
void expr_const_fprint(FILE *__restrict file, ExprConst *expr);
bool expr_const_int_overflowed(const ExprConst *expr);
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
const char *expr_const_to_error_string(const ExprConst *expr);
void fprint_ast(FILE *file, Ast *ast); void fprint_ast(FILE *file, Ast *ast);
void fprint_decl(FILE *file, Decl *dec); void fprint_decl(FILE *file, Decl *dec);
@@ -1131,27 +1154,35 @@ void type_append_signature_name(Type *type, char *dst, size_t *offset);
Type *type_find_max_type(Type *type, Type *other); Type *type_find_max_type(Type *type, Type *other);
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; } static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; }
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX; } static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; }
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_UXX; } static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; }
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I64; }
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U64; }
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; }
bool type_may_have_method_functions(Type *type); bool type_may_have_method_functions(Type *type);
static inline bool type_is_integer(Type *type) static inline bool type_is_integer(Type *type)
{ {
assert(type == type->canonical); assert(type == type->canonical);
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_UXX; return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_U64;
} }
static inline bool type_is_signed_integer(Type *type) static inline bool type_is_any_integer(Type *type)
{ {
assert(type == type->canonical); assert(type == type->canonical);
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX; return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX;
} }
static inline bool type_is_signed_integer(Type *type)
{
assert(type == type->canonical);
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I64;
}
static inline bool type_is_unsigned_integer(Type *type) static inline bool type_is_unsigned_integer(Type *type)
{ {
assert(type == type->canonical); assert(type == type->canonical);
return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_UXX; return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U64;
} }
static inline bool type_info_poison(TypeInfo *type) static inline bool type_info_poison(TypeInfo *type)
@@ -1167,22 +1198,24 @@ static inline bool type_is_float(Type *type)
return type->type_kind >= TYPE_F32 && type->type_kind <= TYPE_FXX; return type->type_kind >= TYPE_F32 && type->type_kind <= TYPE_FXX;
} }
static inline TypeInfo *type_info_new(TypeInfoKind kind) static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceRange range)
{ {
TypeInfo *type_info = malloc_arena(sizeof(TypeInfo)); TypeInfo *type_info = malloc_arena(sizeof(TypeInfo));
memset(type_info, 0, sizeof(TypeInfo)); memset(type_info, 0, sizeof(TypeInfo));
type_info->kind = kind; type_info->kind = kind;
type_info->span = range;
type_info->resolve_status = RESOLVE_NOT_DONE; type_info->resolve_status = RESOLVE_NOT_DONE;
return type_info; return type_info;
} }
static inline TypeInfo *type_info_new_base(Type *type) static inline TypeInfo *type_info_new_base(Type *type, SourceRange range)
{ {
TypeInfo *type_info = malloc_arena(sizeof(TypeInfo)); TypeInfo *type_info = malloc_arena(sizeof(TypeInfo));
memset(type_info, 0, sizeof(TypeInfo)); memset(type_info, 0, sizeof(TypeInfo));
type_info->kind = TYPE_INFO_IDENTIFIER; type_info->kind = TYPE_INFO_IDENTIFIER;
type_info->resolve_status = RESOLVE_DONE; type_info->resolve_status = RESOLVE_DONE;
type_info->type = type; type_info->type = type;
type_info->span = range;
return type_info; return type_info;
} }
@@ -1210,6 +1243,7 @@ static inline bool type_is_number(Type *type)
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX; return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX;
} }
#define TYPE_MODULE_UNRESOLVED(_module, _name) ({ Type *__type = type_new(TYPE_USER_DEFINED); \ #define TYPE_MODULE_UNRESOLVED(_module, _name) ({ Type *__type = type_new(TYPE_USER_DEFINED); \
__type->name_loc = _name; __type->unresolved.module = _module; __type; }) __type->name_loc = _name; __type->unresolved.module = _module; __type; })
#define TYPE_UNRESOLVED(_name) ({ TypeInfo *__type = type_new(TYPE_USER_DEFINED); __type->name_loc = _name; __type; }) #define TYPE_UNRESOLVED(_name) ({ TypeInfo *__type = type_new(TYPE_USER_DEFINED); __type->name_loc = _name; __type; })

View File

@@ -40,6 +40,7 @@ typedef enum
BINARYOP_BIT_AND, BINARYOP_BIT_AND,
BINARYOP_AND, BINARYOP_AND,
BINARYOP_OR, BINARYOP_OR,
// Don't change the ordering for GT to EQ or things will break
BINARYOP_GT, BINARYOP_GT,
BINARYOP_GE, BINARYOP_GE,
BINARYOP_LT, BINARYOP_LT,
@@ -178,14 +179,6 @@ typedef enum _CastType
CAST_TYPE_IMPLICIT_ASSIGN_ADD, CAST_TYPE_IMPLICIT_ASSIGN_ADD,
} CastType; } CastType;
typedef enum
{
CONST_NIL,
CONST_BOOL,
CONST_INT,
CONST_FLOAT,
CONST_STRING,
} ConstType;
typedef enum typedef enum
@@ -214,8 +207,9 @@ typedef enum
// Ordering here is in priority if two branches should have the same exit. // Ordering here is in priority if two branches should have the same exit.
typedef enum typedef enum
{ {
EXIT_NONE, EXIT_NONE = 0,
EXIT_BREAK, EXIT_BREAK,
EXIT_NEXT,
EXIT_GOTO, EXIT_GOTO,
EXIT_CONTINUE, EXIT_CONTINUE,
EXIT_THROW, EXIT_THROW,
@@ -507,12 +501,11 @@ typedef enum
TYPE_I16, TYPE_I16,
TYPE_I32, TYPE_I32,
TYPE_I64, TYPE_I64,
TYPE_IXX,
TYPE_U8, TYPE_U8,
TYPE_U16, TYPE_U16,
TYPE_U32, TYPE_U32,
TYPE_U64, TYPE_U64,
TYPE_UXX, TYPE_IXX,
TYPE_F32, TYPE_F32,
TYPE_F64, TYPE_F64,
TYPE_FXX, TYPE_FXX,
@@ -532,6 +525,12 @@ typedef enum
TYPE_LAST = TYPE_META_TYPE TYPE_LAST = TYPE_META_TYPE
} TypeKind; } TypeKind;
#define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: \
case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_IXX
#define ALL_SIGNED_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64
#define ALL_UNSIGNED_INTS TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64
#define ALL_FLOATS TYPE_F32: case TYPE_F64: case TYPE_FXX
#define TYPE_KINDS (TYPE_LAST + 1) #define TYPE_KINDS (TYPE_LAST + 1)
typedef enum typedef enum
@@ -540,6 +539,7 @@ typedef enum
UNARYOP_DEREF, UNARYOP_DEREF,
UNARYOP_ADDR, UNARYOP_ADDR,
UNARYOP_NEG, UNARYOP_NEG,
UNARYOP_NEGMOD,
UNARYOP_BITNEG, UNARYOP_BITNEG,
UNARYOP_NOT, UNARYOP_NOT,
UNARYOP_INC, UNARYOP_INC,

View File

@@ -318,11 +318,10 @@ static Token scan_binary(Lexer *lexer)
static inline Token scan_hex(Lexer *lexer) static inline Token scan_hex(Lexer *lexer)
{ {
char x = next(lexer); // skip the x
if (!is_hex(next(lexer))) if (!is_hex(next(lexer)))
{ {
return error_token(lexer, "'0%c' starts a hexadecimal number, " return error_token(lexer, "'0x' starts a hexadecimal number, "
"but it was followed by '%c' which is not part of a hexadecimal number.", x, prev(lexer)); "but it was followed by '%c' which is not part of a hexadecimal number.", prev(lexer));
} }
while (is_hex_or_(peek(lexer))) next(lexer); while (is_hex_or_(peek(lexer))) next(lexer);
bool is_float = false; bool is_float = false;

View File

@@ -107,7 +107,6 @@ LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type)
{ {
case TYPE_POISONED: case TYPE_POISONED:
case TYPE_IXX: case TYPE_IXX:
case TYPE_UXX:
case TYPE_FXX: case TYPE_FXX:
case TYPE_META_TYPE: case TYPE_META_TYPE:
UNREACHABLE UNREACHABLE

View File

@@ -4,6 +4,7 @@
#include "llvm_codegen_internal.h" #include "llvm_codegen_internal.h"
#include "compiler_internal.h" #include "compiler_internal.h"
#include "bigint.h"
static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *type, bool use_mod, LLVMValueRef left, LLVMValueRef right) static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *type, bool use_mod, LLVMValueRef left, LLVMValueRef right)
{ {
@@ -228,12 +229,20 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
return LLVMBuildXor(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), LLVMConstInt(type_bool->backend_type, 1, 0), "not"); return LLVMBuildXor(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), LLVMConstInt(type_bool->backend_type, 1, 0), "not");
case UNARYOP_BITNEG: case UNARYOP_BITNEG:
return LLVMBuildNot(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "bnot"); return LLVMBuildNot(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "bnot");
case UNARYOP_NEGMOD:
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "negmod");
case UNARYOP_NEG: case UNARYOP_NEG:
// TODO improve how unsigned numbers are negated.
if (type_is_float(expr->unary_expr.expr->type->canonical)) if (type_is_float(expr->unary_expr.expr->type->canonical))
{ {
return LLVMBuildFNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "fneg"); return LLVMBuildFNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "fneg");
} }
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "neg"); if (type_is_unsigned(expr->unary_expr.expr->type->canonical))
{
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "neg");
}
// TODO insert trap
return LLVMBuildNSWNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "neg");
case UNARYOP_ADDR: case UNARYOP_ADDR:
return gencontext_emit_address(context, expr->unary_expr.expr); return gencontext_emit_address(context, expr->unary_expr.expr);
case UNARYOP_DEREF: case UNARYOP_DEREF:
@@ -301,6 +310,128 @@ static inline LLVMValueRef gencontext_emit_struct_value_expr(GenContext *context
} }
static LLVMValueRef gencontext_emit_int_comparison(GenContext *context, Type *lhs_type, Type *rhs_type, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op)
{
bool lhs_signed = type_is_signed(lhs_type);
bool rhs_signed = type_is_signed(rhs_type);
if (lhs_signed != rhs_signed)
{
// Swap sides if needed.
if (!lhs_signed)
{
Type *temp = lhs_type;
lhs_type = rhs_type;
rhs_type = temp;
LLVMValueRef temp_val = lhs_value;
lhs_value = rhs_value;
rhs_value = temp_val;
switch (binary_op)
{
case BINARYOP_GE:
binary_op = BINARYOP_LE;
break;
case BINARYOP_GT:
binary_op = BINARYOP_LT;
break;
case BINARYOP_LE:
binary_op = BINARYOP_GE;
break;
case BINARYOP_LT:
binary_op = BINARYOP_GT;
break;
default:
break;
}
lhs_signed = true;
rhs_signed = false;
}
}
if (!lhs_signed)
{
assert(lhs_signed == rhs_signed);
// Right and left side are both unsigned.
switch (binary_op)
{
case BINARYOP_EQ:
return LLVMBuildICmp(context->builder, LLVMIntEQ, lhs_value, rhs_value, "eq");
case BINARYOP_NE:
return LLVMBuildICmp(context->builder, LLVMIntNE, lhs_value, rhs_value, "neq");
case BINARYOP_GE:
return LLVMBuildICmp(context->builder, LLVMIntUGE, lhs_value, rhs_value, "ge");
case BINARYOP_GT:
return LLVMBuildICmp(context->builder, LLVMIntUGT, lhs_value, rhs_value, "gt");
case BINARYOP_LE:
return LLVMBuildICmp(context->builder, LLVMIntULE, lhs_value, rhs_value, "le");
case BINARYOP_LT:
return LLVMBuildICmp(context->builder, LLVMIntULT, lhs_value, rhs_value, "lt");
default:
UNREACHABLE
}
}
// Left side is signed.
LLVMValueRef comp_value;
LLVMValueRef check_value;
switch (binary_op)
{
case BINARYOP_EQ:
comp_value = LLVMBuildICmp(context->builder, LLVMIntEQ, lhs_value, rhs_value, "eq");
break;
case BINARYOP_NE:
comp_value = LLVMBuildICmp(context->builder, LLVMIntNE, lhs_value, rhs_value, "neq");
break;
case BINARYOP_GE:
comp_value = LLVMBuildICmp(context->builder, LLVMIntSGE, lhs_value, rhs_value, "ge");
break;
case BINARYOP_GT:
comp_value = LLVMBuildICmp(context->builder, LLVMIntSGT, lhs_value, rhs_value, "gt");
break;
case BINARYOP_LE:
comp_value = LLVMBuildICmp(context->builder, LLVMIntSLE, lhs_value, rhs_value, "le");
break;
case BINARYOP_LT:
comp_value = LLVMBuildICmp(context->builder, LLVMIntSLT, lhs_value, rhs_value, "lt");
break;
default:
UNREACHABLE
}
// If right side is also signed then this is fine.
if (rhs_signed) return comp_value;
// Otherwise, special handling for left side signed, right side unsigned.
LLVMValueRef zero = LLVMConstInt(llvm_type(lhs_type), 0, true);
switch (binary_op)
{
case BINARYOP_EQ:
// Only true if lhs >= 0
check_value = LLVMBuildICmp(context->builder, LLVMIntSGE, lhs_value, zero, "check");
return LLVMBuildAnd(context->builder, check_value, comp_value, "siui-eq");
case BINARYOP_NE:
// Always true if lhs < 0
check_value = LLVMBuildICmp(context->builder, LLVMIntSLT, lhs_value, zero, "check");
return LLVMBuildOr(context->builder, check_value, comp_value, "siui-ne");
case BINARYOP_GE:
// Only true if rhs >= 0 when regarded as a signed integer
check_value = LLVMBuildICmp(context->builder, LLVMIntSGE, rhs_value, zero, "check");
return LLVMBuildAnd(context->builder, check_value, comp_value, "siui-ge");
case BINARYOP_GT:
// Only true if rhs >= 0 when regarded as a signed integer
check_value = LLVMBuildICmp(context->builder, LLVMIntSGE, rhs_value, zero, "check");
return LLVMBuildAnd(context->builder, check_value, comp_value, "siui-gt");
case BINARYOP_LE:
// Always true if rhs < 0 when regarded as a signed integer
check_value = LLVMBuildICmp(context->builder, LLVMIntSLT, rhs_value, zero, "check");
return LLVMBuildOr(context->builder, check_value, comp_value, "siui-le");
case BINARYOP_LT:
// Always true if rhs < 0 when regarded as a signed integer
check_value = LLVMBuildICmp(context->builder, LLVMIntSLT, rhs_value, zero, "check");
return LLVMBuildOr(context->builder, check_value, comp_value, "siui-lt");
default:
UNREACHABLE
}
}
static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVMValueRef lhs_addr, BinaryOp binary_op) static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVMValueRef lhs_addr, BinaryOp binary_op)
{ {
@@ -325,9 +456,12 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
} }
rhs_value = gencontext_emit_expr(context, rhs); rhs_value = gencontext_emit_expr(context, rhs);
Type *lhs_type = expr->binary_expr.left->type->canonical;
bool is_float = type_is_float(type); if (type_is_integer(lhs_type) && binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ)
{
return gencontext_emit_int_comparison(context, lhs_type, rhs->type->canonical, lhs_value, rhs_value, binary_op);
}
bool is_float = type_is_float(lhs_type);
switch (binary_op) switch (binary_op)
{ {
case BINARYOP_ERROR: case BINARYOP_ERROR:
@@ -335,7 +469,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
case BINARYOP_MULT: case BINARYOP_MULT:
if (is_float) return LLVMBuildFMul(context->builder, lhs_value, rhs_value, "fmul"); if (is_float) return LLVMBuildFMul(context->builder, lhs_value, rhs_value, "fmul");
// TODO insert trap // TODO insert trap
if (type_is_unsigned_integer(lhs->type->canonical)) if (type_is_unsigned_integer(lhs_type))
{ {
return LLVMBuildNUWMul(context->builder, lhs_value, rhs_value, "umul"); return LLVMBuildNUWMul(context->builder, lhs_value, rhs_value, "umul");
} }
@@ -347,7 +481,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
return LLVMBuildMul(context->builder, lhs_value, rhs_value, "mul"); return LLVMBuildMul(context->builder, lhs_value, rhs_value, "mul");
case BINARYOP_SUB: case BINARYOP_SUB:
case BINARYOP_SUB_MOD: case BINARYOP_SUB_MOD:
if (lhs->type->canonical->type_kind == TYPE_POINTER) if (lhs_type->type_kind == TYPE_POINTER)
{ {
if (lhs->type->canonical == rhs->type->canonical) return LLVMBuildPtrDiff(context->builder, lhs_value, rhs_value, "ptrdiff"); if (lhs->type->canonical == rhs->type->canonical) return LLVMBuildPtrDiff(context->builder, lhs_value, rhs_value, "ptrdiff");
rhs_value = LLVMBuildNeg(context->builder, rhs_value, ""); rhs_value = LLVMBuildNeg(context->builder, rhs_value, "");
@@ -357,24 +491,24 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
return gencontext_emit_sub_int(context, lhs->type->canonical, binary_op == BINARYOP_SUB_MOD, lhs_value, rhs_value); return gencontext_emit_sub_int(context, lhs->type->canonical, binary_op == BINARYOP_SUB_MOD, lhs_value, rhs_value);
case BINARYOP_ADD: case BINARYOP_ADD:
case BINARYOP_ADD_MOD: case BINARYOP_ADD_MOD:
if (lhs->type->canonical->type_kind == TYPE_POINTER) if (lhs_type->type_kind == TYPE_POINTER)
{ {
assert(type_is_integer(rhs->type->canonical)); assert(type_is_integer(rhs->type->canonical));
return LLVMBuildGEP2(context->builder, llvm_type(lhs->type), lhs_value, &rhs_value, 1, "ptradd"); return LLVMBuildGEP2(context->builder, llvm_type(lhs_type), lhs_value, &rhs_value, 1, "ptradd");
} }
if (is_float) return LLVMBuildFAdd(context->builder, lhs_value, rhs_value, "fadd"); if (is_float) return LLVMBuildFAdd(context->builder, lhs_value, rhs_value, "fadd");
return gencontext_emit_add_int(context, lhs->type->canonical, binary_op == BINARYOP_ADD_MOD, lhs_value, rhs_value); return gencontext_emit_add_int(context, lhs_type, binary_op == BINARYOP_ADD_MOD, lhs_value, rhs_value);
case BINARYOP_DIV: case BINARYOP_DIV:
if (is_float) return LLVMBuildFDiv(context->builder, lhs_value, rhs_value, "fdiv"); if (is_float) return LLVMBuildFDiv(context->builder, lhs_value, rhs_value, "fdiv");
return type_is_unsigned(type) return type_is_unsigned(lhs_type)
? LLVMBuildUDiv(context->builder, lhs_value, rhs_value, "udiv") ? LLVMBuildUDiv(context->builder, lhs_value, rhs_value, "udiv")
: LLVMBuildSDiv(context->builder, lhs_value, rhs_value, "sdiv"); : LLVMBuildSDiv(context->builder, lhs_value, rhs_value, "sdiv");
case BINARYOP_MOD: case BINARYOP_MOD:
return type_is_unsigned(type) return type_is_unsigned(lhs_type)
? LLVMBuildURem(context->builder, lhs_value, rhs_value, "umod") ? LLVMBuildURem(context->builder, lhs_value, rhs_value, "umod")
: LLVMBuildSRem(context->builder, lhs_value, rhs_value, "smod"); : LLVMBuildSRem(context->builder, lhs_value, rhs_value, "smod");
case BINARYOP_SHR: case BINARYOP_SHR:
return type_is_unsigned(type) return type_is_unsigned(lhs_type)
? LLVMBuildLShr(context->builder, lhs_value, rhs_value, "lshr") ? LLVMBuildLShr(context->builder, lhs_value, rhs_value, "lshr")
: LLVMBuildAShr(context->builder, lhs_value, rhs_value, "ashr"); : LLVMBuildAShr(context->builder, lhs_value, rhs_value, "ashr");
case BINARYOP_SHL: case BINARYOP_SHL:
@@ -386,33 +520,25 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
case BINARYOP_BIT_XOR: case BINARYOP_BIT_XOR:
return LLVMBuildXor(context->builder, lhs_value, rhs_value, "xor"); return LLVMBuildXor(context->builder, lhs_value, rhs_value, "xor");
case BINARYOP_EQ: case BINARYOP_EQ:
assert(!type_is_integer(lhs_type));
// Unordered? // Unordered?
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUEQ, lhs_value, rhs_value, "eq"); return LLVMBuildFCmp(context->builder, LLVMRealUEQ, lhs_value, rhs_value, "eq");
return LLVMBuildICmp(context->builder, LLVMIntEQ, lhs_value, rhs_value, "eq");
case BINARYOP_NE: case BINARYOP_NE:
assert(!type_is_integer(lhs_type));
// Unordered? // Unordered?
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUNE, lhs_value, rhs_value, "neq"); return LLVMBuildFCmp(context->builder, LLVMRealUNE, lhs_value, rhs_value, "neq");
return LLVMBuildICmp(context->builder, LLVMIntNE, lhs_value, rhs_value, "neq");
case BINARYOP_GE: case BINARYOP_GE:
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUGE, lhs_value, rhs_value, "ge"); assert(!type_is_integer(lhs_type));
return type_is_unsigned(type) return LLVMBuildFCmp(context->builder, LLVMRealUGE, lhs_value, rhs_value, "ge");
? LLVMBuildICmp(context->builder, LLVMIntUGE, lhs_value, rhs_value, "ge")
: LLVMBuildICmp(context->builder, LLVMIntSGE, lhs_value, rhs_value, "ge");
case BINARYOP_GT: case BINARYOP_GT:
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUGT, lhs_value, rhs_value, "gt"); assert(!type_is_integer(lhs_type));
return type_is_unsigned(type) return LLVMBuildFCmp(context->builder, LLVMRealUGT, lhs_value, rhs_value, "gt");
? LLVMBuildICmp(context->builder, LLVMIntUGT, lhs_value, rhs_value, "gt")
: LLVMBuildICmp(context->builder, LLVMIntSGT, lhs_value, rhs_value, "gt");
case BINARYOP_LE: case BINARYOP_LE:
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "le"); assert(!type_is_integer(lhs_type));
return type_is_unsigned(type) return LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "le");
? LLVMBuildICmp(context->builder, LLVMIntULE, lhs_value, rhs_value, "le")
: LLVMBuildICmp(context->builder, LLVMIntSLE, lhs_value, rhs_value, "le");
case BINARYOP_LT: case BINARYOP_LT:
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "lt"); assert(!type_is_integer(lhs_type));
return type_is_unsigned(type) return LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "lt");
? LLVMBuildICmp(context->builder, LLVMIntULT, lhs_value, rhs_value, "lt")
: LLVMBuildICmp(context->builder, LLVMIntSLT, lhs_value, rhs_value, "lt");
case BINARYOP_AND: case BINARYOP_AND:
case BINARYOP_OR: case BINARYOP_OR:
UNREACHABLE UNREACHABLE
@@ -543,17 +669,24 @@ static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *e
LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
{ {
LLVMTypeRef type = llvm_type(expr->type); LLVMTypeRef type = llvm_type(expr->type);
switch (expr->const_expr.type) switch (expr->const_expr.kind)
{ {
case CONST_INT: case ALL_INTS:
return LLVMConstInt(type, expr->const_expr.i, type_is_unsigned(expr->type->canonical) ? false : true); if (type_is_unsigned(expr->type->canonical))
case CONST_FLOAT: {
return LLVMConstInt(type, bigint_as_unsigned(&expr->const_expr.i), false);
}
else
{
return LLVMConstInt(type, (uint64_t)bigint_as_signed(&expr->const_expr.i), false);
}
case ALL_FLOATS:
return LLVMConstReal(type, (double) expr->const_expr.f); return LLVMConstReal(type, (double) expr->const_expr.f);
case CONST_NIL: case TYPE_POINTER:
return LLVMConstNull(type); return LLVMConstNull(type);
case CONST_BOOL: case TYPE_BOOL:
return LLVMConstInt(type, expr->const_expr.b ? 1 : 0, false); return LLVMConstInt(type, expr->const_expr.b ? 1 : 0, false);
case CONST_STRING: case TYPE_STRING:
{ {
LLVMValueRef global_name = LLVMAddGlobal(context->module, type, "string"); LLVMValueRef global_name = LLVMAddGlobal(context->module, type, "string");
LLVMSetLinkage(global_name, LLVMInternalLinkage); LLVMSetLinkage(global_name, LLVMInternalLinkage);
@@ -564,8 +697,9 @@ LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
0)); 0));
return global_name; return global_name;
} }
default:
UNREACHABLE
} }
UNREACHABLE
} }
LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr) LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)

View File

@@ -96,6 +96,7 @@ void gencontext_emit_implicit_return(GenContext *context)
void gencontext_emit_function_body(GenContext *context, Decl *decl) void gencontext_emit_function_body(GenContext *context, Decl *decl)
{ {
DEBUG_LOG("Generating function %s.", decl->external_name);
assert(decl->func.backend_value); assert(decl->func.backend_value);
LLVMValueRef prev_function = context->function; LLVMValueRef prev_function = context->function;
@@ -143,7 +144,7 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
gencontext_emit_stmt(context, decl->func.body->compound_stmt.stmts[i]); gencontext_emit_stmt(context, decl->func.body->compound_stmt.stmts[i]);
} }
if (!LLVMGetFirstInstruction(context->current_block) && !LLVMGetFirstUse(LLVMBasicBlockAsValue(context->current_block))) if (context->current_block && !LLVMGetFirstInstruction(context->current_block) && !LLVMGetFirstUse(LLVMBasicBlockAsValue(context->current_block)))
{ {
LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(context->current_block); LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(context->current_block);
LLVMDeleteBasicBlock(context->current_block); LLVMDeleteBasicBlock(context->current_block);
@@ -151,9 +152,8 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
LLVMPositionBuilderAtEnd(context->builder, context->current_block); LLVMPositionBuilderAtEnd(context->builder, context->current_block);
} }
// Insert a return (and defer) if needed. // Insert a return (and defer) if needed.
if (!LLVMGetBasicBlockTerminator(context->current_block)) if (context->current_block && !LLVMGetBasicBlockTerminator(context->current_block))
{ {
assert(decl->func.function_signature.rtype->type->type_kind == TYPE_VOID);
assert(decl->func.body->compound_stmt.defer_list.end == NULL); assert(decl->func.body->compound_stmt.defer_list.end == NULL);
gencontext_emit_defer(context, decl->func.body->compound_stmt.defer_list.start, NULL); gencontext_emit_defer(context, decl->func.body->compound_stmt.defer_list.start, NULL);
gencontext_emit_implicit_return(context); gencontext_emit_implicit_return(context);

View File

@@ -134,16 +134,18 @@ static inline void gencontext_emit_return(GenContext *context, Ast *ast)
if (!ret_value) if (!ret_value)
{ {
gencontext_emit_implicit_return(context); gencontext_emit_implicit_return(context);
return;
}
if (context->return_out)
{
LLVMBuildStore(context->builder, ret_value, context->return_out);
gencontext_emit_implicit_return(context);
} }
else else
{ {
LLVMBuildRet(context->builder, ret_value); if (context->return_out)
{
LLVMBuildStore(context->builder, ret_value, context->return_out);
gencontext_emit_implicit_return(context);
}
else
{
LLVMBuildRet(context->builder, ret_value);
}
} }
context->current_block = NULL; context->current_block = NULL;
LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret"); LLVMBasicBlockRef post_ret_block = gencontext_create_free_block(context, "ret");

View File

@@ -154,9 +154,6 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
switch (type->type_kind) switch (type->type_kind)
{ {
case TYPE_POISONED: case TYPE_POISONED:
case TYPE_IXX:
case TYPE_UXX:
case TYPE_FXX:
case TYPE_META_TYPE: case TYPE_META_TYPE:
UNREACHABLE; UNREACHABLE;
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
@@ -172,6 +169,7 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
case TYPE_VOID: case TYPE_VOID:
return type->backend_type = LLVMVoidTypeInContext(context); return type->backend_type = LLVMVoidTypeInContext(context);
case TYPE_F64: case TYPE_F64:
case TYPE_FXX:
return type->backend_type = LLVMDoubleTypeInContext(context); return type->backend_type = LLVMDoubleTypeInContext(context);
case TYPE_F32: case TYPE_F32:
return type->backend_type = LLVMFloatTypeInContext(context); return type->backend_type = LLVMFloatTypeInContext(context);
@@ -180,6 +178,7 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
return type->backend_type = LLVMIntTypeInContext(context, 64U); return type->backend_type = LLVMIntTypeInContext(context, 64U);
case TYPE_U32: case TYPE_U32:
case TYPE_I32: case TYPE_I32:
case TYPE_IXX:
return type->backend_type = LLVMIntTypeInContext(context, 32U); return type->backend_type = LLVMIntTypeInContext(context, 32U);
case TYPE_U16: case TYPE_U16:
case TYPE_I16: case TYPE_I16:

265
src/compiler/number.c Normal file
View File

@@ -0,0 +1,265 @@
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
#include "compiler_internal.h"
#include "bigint.h"
#define CHECK_SI_KIND(_kind) assert(_kind >= TYPE_I8 && _kind <= TYPE_I64)
#define CHECK_IXX_KIND(_kind) assert(_kind == TYPE_IXX)
#define CHECK_UI_KIND(_kind) assert(_kind >= TYPE_U8 && _kind <= TYPE_U64)
#define CHECK_INT_KIND(_kind) assert(_kind >= TYPE_I8 && _kind <= TYPE_U64)
#define CHECK_CONVERSION(_kind) assert(i->kind != _kind && "Unnecessary conversion")
#define TYPE_MATCH assert(left->kind == right->kind && left != res && right != res)
static uint64_t type_mask[TYPE_U64 + 1] = {
[TYPE_U8] = 0xFF,
[TYPE_I8] = 0xFF,
[TYPE_U16] = 0xFFFF,
[TYPE_I16] = 0xFFFF,
[TYPE_U32] = 0xFFFFFFFFU,
[TYPE_I32] = 0xFFFFFFFFU,
[TYPE_U64] = 0xFFFFFFFFFFFFFFFFLLU,
[TYPE_I64] = 0xFFFFFFFFFFFFFFFFLLU,
};
static int type_bits[TYPE_U64 + 1] = {
[TYPE_U8] = 8,
[TYPE_I8] = 8,
[TYPE_U16] = 16,
[TYPE_I16] = 16,
[TYPE_U32] = 32,
[TYPE_I32] = 32,
[TYPE_U64] = 64,
[TYPE_I64] = 64,
};
static int64_t int_type_max[TYPE_I64 + 1] = {
[TYPE_I8] = 0x7F,
[TYPE_I16] = 0x7FFF,
[TYPE_I32] = 0x7FFFFFFFLL,
[TYPE_I64] = 0x7FFFFFFFFFFFFFFFLL,
};
static int64_t int_type_min[TYPE_I64 + 1] = {
[TYPE_I8] = -0x80,
[TYPE_I16] = -0x8000L,
[TYPE_I32] = -0x80000000L,
[TYPE_I64] = -0x8000000000000000LL,
};
void expr_const_fprint(FILE *__restrict file, ExprConst *expr)
{
switch (expr->kind)
{
case TYPE_POINTER:
fprintf(file, "nil");
break;
case TYPE_BOOL:
fprintf(file, expr->b ? "true" : "false");
break;
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_U8:
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
case TYPE_IXX:
bigint_fprint(file, &expr->i, 10);
break;
case TYPE_F32:
case TYPE_F64:
case TYPE_FXX:
fprintf(file, "%Lf", expr->f);
break;
default:
UNREACHABLE
}
}
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind)
{
if (type_kind_is_signed(kind))
{
bigint_init_signed(&expr->i, (int64_t)v);
}
else
{
bigint_init_unsigned(&expr->i, v);
}
expr->kind = kind;
}
void expr_const_set_bool(ExprConst *expr, bool b)
{
expr->b = b;
expr->kind = TYPE_BOOL;
}
void expr_const_set_nil(ExprConst *expr)
{
expr->i.digit_count = 0;
expr->i.digit = 0;
expr->kind = TYPE_POINTER;
}
static inline bool compare_bool(bool left, bool right, BinaryOp op)
{
switch (op)
{
case BINARYOP_EQ:
return left == right;
case BINARYOP_NE:
return left != right;
case BINARYOP_GT:
return left > right;
case BINARYOP_LT:
return left < right;
case BINARYOP_GE:
return left >= right;
case BINARYOP_LE:
return left <= right;
default:
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(long double left, long double right, BinaryOp op)
{
switch (op)
{
case BINARYOP_GE:
return left >= right;
case BINARYOP_LE:
return left <= right;
case BINARYOP_NE:
return left != right;
case BINARYOP_GT:
return left > right;
case BINARYOP_LT:
return left < right;
case BINARYOP_EQ:
return left == right;
default:
UNREACHABLE
}
}
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op)
{
switch (left->kind)
{
case TYPE_BOOL:
return compare_bool(left->b, right->b, op);
case ALL_INTS:
return compare_ints(&left->i, &right->i, op);
case ALL_FLOATS:
return compare_fps(left->f, right->f, op);
case TYPE_POINTER:
return true;
case TYPE_STRING:
TODO
default:
UNREACHABLE
}
}
bool expr_const_int_overflowed(const ExprConst *expr)
{
switch (expr->kind)
{
case TYPE_I8:
return !bigint_fits_in_bits(&expr->i, 8, true);
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 !bigint_fits_in_bits(&expr->i, 8, false);
case TYPE_U16:
return !bigint_fits_in_bits(&expr->i, 16, false);
case TYPE_U32:
return !bigint_fits_in_bits(&expr->i, 32, false);
case TYPE_U64:
return !bigint_fits_in_bits(&expr->i, 64, false);
case TYPE_IXX:
return false;
default:
UNREACHABLE
}
}
const char *expr_const_to_error_string(const ExprConst *expr)
{
char *buff = NULL;
switch (expr->kind)
{
case TYPE_POINTER:
return "nil";
case TYPE_BOOL:
return expr->b ? "true" : "false";
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_U8:
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
case TYPE_IXX:
return bigint_to_error_string(&expr->i, 10);
case TYPE_F32:
case TYPE_F64:
case TYPE_FXX:
asprintf(&buff, "%Lf", expr->f);
return buff;
default:
UNREACHABLE
}
}
void expr_const_set_float(ExprConst *expr, long double d, TypeKind kind)
{
switch (kind)
{
case TYPE_F32:
expr->f = (float)d;
break;
case TYPE_F64:
expr->f = (double)d;
break;
default:
expr->f = d;
}
expr->kind = kind;
}

View File

@@ -4,6 +4,7 @@
#include "compiler_internal.h" #include "compiler_internal.h"
#include "parser_internal.h" #include "parser_internal.h"
#include "bigint.h"
typedef Expr *(*ParseFn)(Context *context, Expr *); typedef Expr *(*ParseFn)(Context *context, Expr *);
@@ -276,6 +277,7 @@ static Expr *parse_binary(Context *context, Expr *left_side)
expr->binary_expr.operator = binaryop_from_token(operator_type); expr->binary_expr.operator = binaryop_from_token(operator_type);
expr->binary_expr.left = left_side; expr->binary_expr.left = left_side;
expr->binary_expr.right = right_side; expr->binary_expr.right = right_side;
expr->span.end_loc = right_side->span.end_loc;
return expr; return expr;
} }
@@ -389,7 +391,6 @@ static Expr *parse_integer(Context *context, Expr *left)
Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
const char *string = context->tok.start; const char *string = context->tok.start;
const char *end = string + source_range_len(context->tok.span); const char *end = string + source_range_len(context->tok.span);
uint64_t i = 0;
if (string[0] == '\'') if (string[0] == '\'')
{ {
union union
@@ -431,27 +432,39 @@ static Expr *parse_integer(Context *context, Expr *left)
} }
bytes.b[pos++] = (unsigned)*string; bytes.b[pos++] = (unsigned)*string;
} }
switch (pos) switch (pos)
{ {
case 1: case 1:
expr_int->const_expr.i = bytes.u8; expr_const_set_int(&expr_int->const_expr, bytes.u8, TYPE_U8);
expr_int->type = type_byte;
break; break;
case 2: case 2:
expr_int->const_expr.i = bytes.u16; expr_const_set_int(&expr_int->const_expr, bytes.u8, TYPE_U16);
expr_int->type = type_ushort;
break; break;
case 4: case 4:
expr_int->const_expr.i = bytes.u32; expr_const_set_int(&expr_int->const_expr, bytes.u8, TYPE_U32);
expr_int->type = type_uint;
break; break;
case 8: case 8:
expr_int->const_expr.i = bytes.u64; expr_const_set_int(&expr_int->const_expr, bytes.u8, TYPE_U64);
expr_int->type = type_ulong;
break; break;
default:
UNREACHABLE
} }
expr_int->const_expr.type = CONST_INT;
expr_int->type = i > INT64_MAX ? type_compuint : type_compint;
expr_int->resolve_status = RESOLVE_DONE; expr_int->resolve_status = RESOLVE_DONE;
advance(context); advance(context);
return expr_int; return expr_int;
} }
BigInt *i = &expr_int->const_expr.i;
bigint_init_unsigned(i, 0);
BigInt diff;
bigint_init_unsigned(&diff, 0);
BigInt ten;
bigint_init_unsigned(&ten, 10);
BigInt res;
switch (source_range_len(context->tok.span) > 2 ? string[1] : '0') switch (source_range_len(context->tok.span) > 2 ? string[1] : '0')
{ {
case 'x': case 'x':
@@ -460,24 +473,20 @@ static Expr *parse_integer(Context *context, Expr *left)
{ {
char c = *(string++); char c = *(string++);
if (c == '_') continue; if (c == '_') continue;
if (i > (UINT64_MAX >> 4U)) bigint_shl_int(&res, i, 4);
{
SEMA_TOKEN_ERROR(context->tok, "Number is larger than an unsigned 64 bit number.");
return &poisoned_expr;
}
i <<= 4U;
if (c < 'A') if (c < 'A')
{ {
i += c - '0'; bigint_init_unsigned(&diff, c - '0');
} }
else if (c < 'a') else if (c < 'a')
{ {
i += c - 'A' + 10; bigint_init_unsigned(&diff, c - 'A' + 10);
} }
else else
{ {
i += c - 'a' + 10; bigint_init_unsigned(&diff, c - 'a' + 10);
} }
bigint_add(i, &res, &diff);
} }
break; break;
case 'o': case 'o':
@@ -486,13 +495,9 @@ static Expr *parse_integer(Context *context, Expr *left)
{ {
char c = *(string++); char c = *(string++);
if (c == '_') continue; if (c == '_') continue;
if (i > (UINT64_MAX >> 3U)) bigint_shl_int(&res, i, 4);
{ bigint_init_unsigned(&diff, c - '0');
SEMA_TOKEN_ERROR(context->tok, "Number is larger than an unsigned 64 bit number."); bigint_add(i, &res, &diff);
return &poisoned_expr;
}
i <<= (unsigned) 3;
i += c - '0';
} }
break; break;
case 'b': case 'b':
@@ -501,13 +506,9 @@ static Expr *parse_integer(Context *context, Expr *left)
{ {
char c = *(string++); char c = *(string++);
if (c == '_') continue; if (c == '_') continue;
if (i > (UINT64_MAX >> 1U)) bigint_shl_int(&res, i, 1);
{ bigint_init_unsigned(&diff, c - '0');
SEMA_TOKEN_ERROR(context->tok, "Number is larger than an unsigned 64 bit number."); bigint_add(i, &res, &diff);
return &poisoned_expr;
}
i <<= (unsigned) 1;
i += c - '0';
} }
break; break;
default: default:
@@ -515,20 +516,14 @@ static Expr *parse_integer(Context *context, Expr *left)
{ {
char c = *(string++); char c = *(string++);
if (c == '_') continue; if (c == '_') continue;
if (i > (UINT64_MAX / 10)) bigint_mul(&res, i, &ten);
{ bigint_init_unsigned(&diff, c - '0');
SEMA_TOKEN_ERROR(context->tok, "Number is larger than an unsigned 64 bit number."); bigint_add(i, &res, &diff);
return &poisoned_expr;
}
i *= 10;
i += c - '0';
} }
break; break;
} }
expr_int->const_expr.i = i; expr_int->const_expr.kind = TYPE_IXX;
expr_int->const_expr.type = CONST_INT; expr_int->type = type_compint;
expr_int->type = i > INT64_MAX ? type_compuint : type_compint;
advance(context); advance(context);
return expr_int; return expr_int;
} }
@@ -549,7 +544,7 @@ static Expr *parse_double(Context *context, Expr *left)
advance(context); advance(context);
number->const_expr.f = fval; number->const_expr.f = fval;
number->type = type_compfloat; number->type = type_compfloat;
number->const_expr.type = CONST_FLOAT; number->const_expr.kind = TYPE_FXX;
return number; return number;
} }
@@ -678,7 +673,7 @@ static Expr *parse_string_literal(Context *context, Expr *left)
expr_string->const_expr.string.chars = str; expr_string->const_expr.string.chars = str;
expr_string->const_expr.string.len = len; expr_string->const_expr.string.len = len;
expr_string->type = type_string; expr_string->type = type_string;
expr_string->const_expr.type = CONST_STRING; expr_string->const_expr.kind = TYPE_STRING;
return expr_string; return expr_string;
} }
@@ -686,7 +681,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 = context->tok.type == TOKEN_TRUE, .type = CONST_BOOL }; number->const_expr = (ExprConst) { .b = context->tok.type == TOKEN_TRUE, .kind = TYPE_BOOL };
number->type = type_bool; number->type = type_bool;
number->resolve_status = RESOLVE_DONE; number->resolve_status = RESOLVE_DONE;
advance(context); advance(context);
@@ -697,7 +692,7 @@ static Expr *parse_nil(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.type = CONST_NIL; number->const_expr.kind = TYPE_POINTER;
number->type = type_voidptr; number->type = type_voidptr;
advance(context); advance(context);
return number; return number;
@@ -734,7 +729,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
//[TOKEN_SIZEOF] = { parse_sizeof, NULL, PREC_NONE }, //[TOKEN_SIZEOF] = { parse_sizeof, NULL, PREC_NONE },
[TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL }, [TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL },
[TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE }, [TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
[TOKEN_MINUS_MOD] = { NULL, parse_binary, PREC_ADDITIVE }, [TOKEN_MINUS_MOD] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
[TOKEN_PLUS] = { NULL, parse_binary, PREC_ADDITIVE }, [TOKEN_PLUS] = { NULL, parse_binary, PREC_ADDITIVE },
[TOKEN_PLUS_MOD] = { NULL, parse_binary, PREC_ADDITIVE }, [TOKEN_PLUS_MOD] = { NULL, parse_binary, PREC_ADDITIVE },
[TOKEN_DIV] = { NULL, parse_binary, PREC_MULTIPLICATIVE }, [TOKEN_DIV] = { NULL, parse_binary, PREC_MULTIPLICATIVE },

View File

@@ -436,7 +436,6 @@ static inline Ast *parse_return_stmt(Context *context)
{ {
advance_and_verify(context, TOKEN_RETURN); advance_and_verify(context, TOKEN_RETURN);
Ast *ast = AST_NEW_TOKEN(AST_RETURN_STMT, context->tok); Ast *ast = AST_NEW_TOKEN(AST_RETURN_STMT, context->tok);
ast->exit = EXIT_RETURN;
ast->return_stmt.defer = NULL; ast->return_stmt.defer = NULL;
if (try_consume(context, TOKEN_EOS)) if (try_consume(context, TOKEN_EOS))
{ {

View File

@@ -312,13 +312,15 @@ Path *parse_path_prefix(Context *context)
*/ */
static inline TypeInfo *parse_base_type(Context *context) static inline TypeInfo *parse_base_type(Context *context)
{ {
SourceRange range = context->tok.span;
Path *path = parse_path_prefix(context); Path *path = parse_path_prefix(context);
if (path) if (path)
{ {
TypeInfo *type_info = type_info_new(TYPE_INFO_IDENTIFIER); TypeInfo *type_info = type_info_new(TYPE_INFO_IDENTIFIER, range);
type_info->unresolved.path = path; type_info->unresolved.path = path;
type_info->unresolved.name_loc = context->tok; type_info->unresolved.name_loc = context->tok;
if (!consume_type_name(context, "types")) return &poisoned_type_info; if (!consume_type_name(context, "types")) return &poisoned_type_info;
RANGE_EXTEND_PREV(type_info);
return type_info; return type_info;
} }
@@ -327,16 +329,17 @@ static inline TypeInfo *parse_base_type(Context *context)
switch (context->tok.type) switch (context->tok.type)
{ {
case TOKEN_TYPE_IDENT: case TOKEN_TYPE_IDENT:
type_info = type_info_new(TYPE_INFO_IDENTIFIER); type_info = type_info_new(TYPE_INFO_IDENTIFIER, context->tok.span);
type_info->unresolved.name_loc = context->tok; type_info->unresolved.name_loc = context->tok;
break; break;
case TOKEN_TYPE: case TOKEN_TYPE:
type_info = type_info_new(TYPE_INFO_IDENTIFIER); type_info = type_info_new(TYPE_INFO_IDENTIFIER, context->tok.span);
advance_and_verify(context, TOKEN_TYPE); advance_and_verify(context, TOKEN_TYPE);
CONSUME_OR(TOKEN_LPAREN, &poisoned_type_info); CONSUME_OR(TOKEN_LPAREN, &poisoned_type_info);
type_info->resolve_status = RESOLVE_NOT_DONE; type_info->resolve_status = RESOLVE_NOT_DONE;
type_info->unresolved_type_expr = TRY_EXPR_OR(parse_initializer(context), &poisoned_type_info); type_info->unresolved_type_expr = TRY_EXPR_OR(parse_initializer(context), &poisoned_type_info);
EXPECT_OR(TOKEN_RPAREN, &poisoned_type_info); EXPECT_OR(TOKEN_RPAREN, &poisoned_type_info);
RANGE_EXTEND_PREV(type_info);
break; break;
case TOKEN_VOID: case TOKEN_VOID:
type_found = type_void; type_found = type_void;
@@ -408,14 +411,15 @@ static inline TypeInfo *parse_base_type(Context *context)
SEMA_TOKEN_ERROR(context->tok, "A type name was expected here."); SEMA_TOKEN_ERROR(context->tok, "A type name was expected here.");
return &poisoned_type_info; return &poisoned_type_info;
} }
advance(context);
if (type_found) if (type_found)
{ {
assert(!type_info); assert(!type_info);
type_info = type_info_new(TYPE_INFO_IDENTIFIER); type_info = type_info_new(TYPE_INFO_IDENTIFIER, context->tok.span);
type_info->resolve_status = RESOLVE_DONE; type_info->resolve_status = RESOLVE_DONE;
type_info->type = type_found; type_info->type = type_found;
} }
advance(context);
RANGE_EXTEND_PREV(type_info);
return type_info; return type_info;
} }
@@ -437,21 +441,24 @@ static inline TypeInfo *parse_array_type_index(Context *context, TypeInfo *type)
if (try_consume(context, TOKEN_PLUS)) if (try_consume(context, TOKEN_PLUS))
{ {
CONSUME_OR(TOKEN_RBRACKET, &poisoned_type_info); CONSUME_OR(TOKEN_RBRACKET, &poisoned_type_info);
TypeInfo *incr_array = type_info_new(TYPE_INFO_INC_ARRAY); TypeInfo *incr_array = type_info_new(TYPE_INFO_INC_ARRAY, type->span);
incr_array->array.base = type; incr_array->array.base = type;
RANGE_EXTEND_PREV(incr_array);
return incr_array; return incr_array;
} }
if (try_consume(context, TOKEN_RBRACKET)) if (try_consume(context, TOKEN_RBRACKET))
{ {
TypeInfo *array = type_info_new(TYPE_INFO_ARRAY); TypeInfo *array = type_info_new(TYPE_INFO_ARRAY, type->span);
array->array.base = type; array->array.base = type;
array->array.len = NULL; array->array.len = NULL;
RANGE_EXTEND_PREV(array);
return array; return array;
} }
TypeInfo *array = type_info_new(TYPE_INFO_ARRAY); TypeInfo *array = type_info_new(TYPE_INFO_ARRAY, type->span);
array->array.base = type; array->array.base = type;
array->array.len = TRY_EXPR_OR(parse_expr(context), &poisoned_type_info); array->array.len = TRY_EXPR_OR(parse_expr(context), &poisoned_type_info);
CONSUME_OR(TOKEN_RBRACKET, &poisoned_type_info); CONSUME_OR(TOKEN_RBRACKET, &poisoned_type_info);
RANGE_EXTEND_PREV(array);
return array; return array;
} }
@@ -478,10 +485,11 @@ TypeInfo *parse_type_expression(Context *context)
case TOKEN_STAR: case TOKEN_STAR:
advance(context); advance(context);
{ {
TypeInfo *ptr_type = type_info_new(TYPE_INFO_POINTER); TypeInfo *ptr_type = type_info_new(TYPE_INFO_POINTER, type_info->span);
assert(type_info); assert(type_info);
ptr_type->pointer = type_info; ptr_type->pointer = type_info;
type_info = ptr_type; type_info = ptr_type;
RANGE_EXTEND_PREV(type_info);
} }
break; break;
default: default:
@@ -725,7 +733,7 @@ bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr)
CONSUME_OR(TOKEN_RPAREN, false); CONSUME_OR(TOKEN_RPAREN, false);
if (inner_expr) if (inner_expr)
{ {
*type_ptr = type_info_new(TYPE_INFO_EXPRESSION); *type_ptr = type_info_new(TYPE_INFO_EXPRESSION, inner_expr->span);
(**type_ptr).unresolved_type_expr = inner_expr; (**type_ptr).unresolved_type_expr = inner_expr;
return true; return true;
} }
@@ -863,7 +871,7 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili
{ {
TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), false); TypeInfo *type = TRY_TYPE_OR(parse_type_expression(context), false);
Decl *param = decl_new_var(context->tok, type, VARDECL_PARAM, parent_visibility); Decl *param = decl_new_var(context->tok, type, VARDECL_PARAM, parent_visibility);
param->span = type->span;
if (!try_consume(context, TOKEN_IDENT)) if (!try_consume(context, TOKEN_IDENT))
{ {
param->name = NULL; param->name = NULL;
@@ -873,7 +881,12 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili
if (!name && !type_only) if (!name && !type_only)
{ {
SEMA_TOKEN_ERROR(context->tok, "The function parameter must be named."); if (context->tok.type != TOKEN_COMMA && context->tok.type != TOKEN_RPAREN)
{
SEMA_TOKEN_ERROR(context->tok, "Unexpected end of the parameter list, did you forget an ')'?");
return false;
}
SEMA_ERROR(type, "The function parameter must be named.");
return false; return false;
} }
if (name && try_consume(context, TOKEN_EQ)) if (name && try_consume(context, TOKEN_EQ))
@@ -882,6 +895,7 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili
} }
*parameters = VECADD(*parameters, param); *parameters = VECADD(*parameters, param);
RANGE_EXTEND_PREV(param);
return true; return true;
} }
@@ -1365,7 +1379,6 @@ static inline bool parse_enum_spec(Context *context, TypeInfo **type_ref, Decl**
{ {
*type_ref = TRY_TYPE_OR(parse_base_type(context), false); *type_ref = TRY_TYPE_OR(parse_base_type(context), false);
if (!try_consume(context, TOKEN_LPAREN)) return true; if (!try_consume(context, TOKEN_LPAREN)) return true;
CONSUME_OR(TOKEN_LPAREN, false);
while (!try_consume(context, TOKEN_RPAREN)) while (!try_consume(context, TOKEN_RPAREN))
{ {
if (!parse_param_decl(context, parent_visibility, parameters_ref, false)) return false; if (!parse_param_decl(context, parent_visibility, parameters_ref, false)) return false;
@@ -1415,11 +1428,10 @@ static inline Decl *parse_enum_declaration(Context *context, Visibility visibili
CONSUME_OR(TOKEN_LBRACE, false); CONSUME_OR(TOKEN_LBRACE, false);
decl->enums.type_info = type ? type : type_info_new_base(type_int); decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span);
while (!try_consume(context, TOKEN_RBRACE)) while (!try_consume(context, TOKEN_RBRACE))
{ {
Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, context->tok, decl->visibility); Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, context->tok, decl->visibility);
enum_const->enum_constant.parent = decl;
VECEACH(decl->enums.values, i) VECEACH(decl->enums.values, i)
{ {
Decl *other_constant = decl->enums.values[i]; Decl *other_constant = decl->enums.values[i];
@@ -1491,12 +1503,14 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit
Decl *func = decl_new(DECL_FUNC, context->tok, visibility); Decl *func = decl_new(DECL_FUNC, context->tok, visibility);
func->func.function_signature.rtype = return_type; func->func.function_signature.rtype = return_type;
SourceRange start = context->tok.span;
Path *path = parse_path_prefix(context); Path *path = parse_path_prefix(context);
if (path || context->tok.type == TOKEN_TYPE_IDENT) if (path || context->tok.type == TOKEN_TYPE_IDENT)
{ {
// Special case, actually an extension // Special case, actually an extension
TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "A type was expected after '::'.", &poisoned_decl); TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "A type was expected after '::'.", &poisoned_decl);
TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER); // TODO span is incorrect
TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, start);
type->unresolved.path = path; type->unresolved.path = path;
type->unresolved.name_loc = context->tok; type->unresolved.name_loc = context->tok;
func->func.type_parent = type; func->func.type_parent = type;
@@ -1963,15 +1977,17 @@ static Expr *parse_type_access(Context *context, TypeInfo *type)
*/ */
Expr *parse_type_identifier_with_path(Context *context, Path *path) Expr *parse_type_identifier_with_path(Context *context, Path *path)
{ {
TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER); TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER, path ? path->span : context->tok.span );
type->unresolved.path = path; type->unresolved.path = path;
type->unresolved.name_loc = context->tok; type->unresolved.name_loc = context->tok;
advance_and_verify(context, TOKEN_TYPE_IDENT); advance_and_verify(context, TOKEN_TYPE_IDENT);
RANGE_EXTEND_PREV(type);
if (context->tok.type == TOKEN_LBRACE) if (context->tok.type == TOKEN_LBRACE)
{ {
Expr *expr = EXPR_NEW_TOKEN(EXPR_STRUCT_VALUE, context->tok); Expr *expr = EXPR_NEW_TOKEN(EXPR_STRUCT_VALUE, context->tok);
expr->struct_value_expr.type = type; expr->struct_value_expr.type = type;
expr->struct_value_expr.init_expr = TRY_EXPR_OR(parse_initializer_list(context), &poisoned_expr); expr->struct_value_expr.init_expr = TRY_EXPR_OR(parse_initializer_list(context), &poisoned_expr);
return expr; return expr;
} }
EXPECT_OR(TOKEN_DOT, &poisoned_expr); EXPECT_OR(TOKEN_DOT, &poisoned_expr);

View File

@@ -3,6 +3,7 @@
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include "sema_internal.h" #include "sema_internal.h"
#include "bigint.h"
static inline bool sema_analyse_error(Context *context __unused, Decl *decl) static inline bool sema_analyse_error(Context *context __unused, Decl *decl)
@@ -241,41 +242,81 @@ static inline bool sema_analyse_typedef(Context *context, Decl *decl)
static inline bool sema_analyse_enum(Context *context, Decl *decl) static inline bool sema_analyse_enum(Context *context, Decl *decl)
{ {
// Resolve the type of the enum.
if (!sema_resolve_type_info(context, decl->enums.type_info)) return false; if (!sema_resolve_type_info(context, decl->enums.type_info)) return false;
uint64_t value = 0;
Type *type = decl->enums.type_info->type; Type *type = decl->enums.type_info->type;
Type *canonical = decl->enums.type_info->type;
// Require an integer type
if (!type_is_integer(canonical))
{
SEMA_ERROR(decl->enums.type_info, "The enum type must be an integer type not '%s'.", type_to_error_string(type));
return false;
}
DEBUG_LOG("* Enum type resolved to %s.", type->name);
bool success = true; bool success = true;
VECEACH(decl->enums.values, i) unsigned enums = vec_size(decl->enums.values);
BigInt value;
BigInt add;
bigint_init_unsigned(&add, 1);
bigint_init_unsigned(&value, 0);
for (unsigned i = 0; i < enums; i++)
{ {
Decl *enum_value = decl->enums.values[i]; Decl *enum_value = decl->enums.values[i];
enum_value->type = decl->type;
DEBUG_LOG("* Checking enum constant %s.", enum_value->name);
enum_value->enum_constant.ordinal = i; enum_value->enum_constant.ordinal = i;
DEBUG_LOG("* Ordinal: %d", i);
assert(enum_value->resolve_status == RESOLVE_NOT_DONE); assert(enum_value->resolve_status == RESOLVE_NOT_DONE);
assert(enum_value->decl_kind == DECL_ENUM_CONSTANT); assert(enum_value->decl_kind == DECL_ENUM_CONSTANT);
// Start evaluating the constant
enum_value->resolve_status = RESOLVE_RUNNING; enum_value->resolve_status = RESOLVE_RUNNING;
Expr *expr = enum_value->enum_constant.expr; Expr *expr = enum_value->enum_constant.expr;
// Create a "fake" expression.
// This will be evaluated later to catch the case
if (!expr) if (!expr)
{ {
expr = expr_new(EXPR_CONST, INVALID_RANGE); expr = expr_new(EXPR_CONST, enum_value->name_span);
expr->type = type; expr->type = type;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_NOT_DONE;
expr->const_expr.type = CONST_INT; bigint_init_bigint(&expr->const_expr.i, &value);
expr->const_expr.i = value; expr->const_expr.kind = TYPE_IXX;
expr->type = type_compint;
enum_value->enum_constant.expr = expr; enum_value->enum_constant.expr = expr;
} }
// We try to convert to the desired type.
if (!sema_analyse_expr(context, type, expr)) if (!sema_analyse_expr(context, type, expr))
{ {
success = false; success = false;
enum_value->resolve_status = RESOLVE_DONE; enum_value->resolve_status = RESOLVE_DONE;
decl_poison(enum_value);
// Reset!
bigint_init_unsigned(&value, 0);
continue; continue;
} }
assert(type_is_integer(expr->type->canonical)); assert(type_is_integer(expr->type->canonical));
// Here we might have a non-constant value,
if (expr->expr_kind != EXPR_CONST) if (expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(expr, "Expected a constant expression for enum"); SEMA_ERROR(expr, "Expected a constant expression for enum.");
decl_poison(enum_value);
success = false; success = false;
// Skip one value.
continue;
} }
// Update the value
bigint_add(&value, &expr->const_expr.i, &add);
DEBUG_LOG("* Value: %s", expr_const_to_error_string(&expr->const_expr));
enum_value->resolve_status = RESOLVE_DONE; enum_value->resolve_status = RESOLVE_DONE;
enum_value->type = decl->type;
} }
return success; return success;
} }
@@ -393,7 +434,7 @@ bool sema_analyse_decl(Context *context, Decl *decl)
{ {
if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl); if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl);
DEBUG_LOG("Analyse %s", decl->name); DEBUG_LOG(">>> Analysing %s.", decl->name);
if (decl->resolve_status == RESOLVE_RUNNING) if (decl->resolve_status == RESOLVE_RUNNING)
{ {
SEMA_ERROR(decl, "Recursive dependency on %s.", decl->name); SEMA_ERROR(decl, "Recursive dependency on %s.", decl->name);
@@ -454,5 +495,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
UNREACHABLE UNREACHABLE
} }
decl->resolve_status = RESOLVE_DONE; decl->resolve_status = RESOLVE_DONE;
DEBUG_LOG("<<< Analysis of %s successful.", decl->name);
return true; return true;
} }

View File

@@ -3,6 +3,7 @@
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include "sema_internal.h" #include "sema_internal.h"
#include "bigint.h"
/* /*
* TODOs * TODOs
@@ -14,8 +15,8 @@
#define CONST_PROCESS(_op) \ #define CONST_PROCESS(_op) \
if (both_const(left, right)) { \ if (both_const(left, right)) { \
switch (left->const_expr.type) { \ switch (left->const_expr.type) { \
case CONST_INT: expr->const_expr.i = left->const_expr.i _op right->const_expr.i; break; \ case CONST_INT: int_##_op(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i); break; \
case CONST_FLOAT: expr->const_expr.f = left->const_expr.f _op right->const_expr.f; break; \ case CONST_FLOAT: float_##_op(&expr->const_expr.f, &left->const_expr.f, &right->const_expr.f); break; \
default: UNREACHABLE } \ default: UNREACHABLE } \
expr->expr_kind = EXPR_CONST; \ expr->expr_kind = EXPR_CONST; \
expr->const_expr.type = left->const_expr.type; \ expr->const_expr.type = left->const_expr.type; \
@@ -299,8 +300,7 @@ static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr
assert(error_constant->resolve_status == RESOLVE_DONE); assert(error_constant->resolve_status == RESOLVE_DONE);
expr->type = decl->type; expr->type = decl->type;
expr->expr_kind = EXPR_CONST; expr->expr_kind = EXPR_CONST;
expr->const_expr.type = CONST_INT; expr_const_set_int(&expr->const_expr, decl->error_constant.value, TYPE_U32);
expr->const_expr.i = decl->error_constant.value;
return true; return true;
} }
} }
@@ -440,6 +440,7 @@ static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr *
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return expr->identifier_expr.decl; return expr->identifier_expr.decl;
} }
static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr) static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr)
{ {
assert(access_expr->resolve_status == RESOLVE_NOT_DONE); assert(access_expr->resolve_status == RESOLVE_NOT_DONE);
@@ -823,6 +824,10 @@ static bool binary_arithmetic_promotion(Expr *left, Expr *right, Type *left_type
return max && type_is_number(max) && cast_implicit(left, max) && cast_implicit(right, max); return max && type_is_number(max) && cast_implicit(left, max) && cast_implicit(right, max);
} }
/**
* Analyse a - b
* @return true if analysis succeeded
*/
static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
{ {
if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false;
@@ -848,7 +853,23 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR;
CONST_PROCESS(-); if (both_const(left, right))
{
switch (left->const_expr.kind)
{
case ALL_INTS:
bigint_sub(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
break;
case ALL_FLOATS:
// IMPROVE precision.
expr->const_expr.f = left->const_expr.f - right->const_expr.f;
break;
default:
UNREACHABLE
}
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left->const_expr.kind;
}
expr->type = left->type; expr->type = left->type;
return true; return true;
@@ -885,7 +906,22 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *
if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR;
CONST_PROCESS(+); if (both_const(left, right))
{
switch (left->const_expr.kind)
{
case ALL_INTS:
bigint_add(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
break;
case ALL_FLOATS:
expr->const_expr.f = left->const_expr.f + right->const_expr.f;
break;
default:
UNREACHABLE
}
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left->const_expr.kind;
}
expr->type = left->type; expr->type = left->type;
return true; return true;
@@ -904,10 +940,40 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr
if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR;
CONST_PROCESS(*) bool is_mod = expr->binary_expr.operator == BINARYOP_MULT_MOD;
expr->type = left->type; expr->type = left->type;
return true;
// Might have changed
left_type = left->type->canonical;
if (is_mod && !type_is_any_integer(left_type))
{
SEMA_ERROR(expr, "You can only use *% with integer types.");
return false;
}
if (!both_const(left, right)) return true;
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left->const_expr.kind;
switch (left->const_expr.kind)
{
case ALL_SIGNED_INTS:
// Do mod mult
if (is_mod && left_type != type_compint)
{
bigint_mul_wrap(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i, is_mod, left_type->builtin.bitsize);
return true;
}
bigint_mul(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
return true;
case ALL_FLOATS:
expr->const_expr.f = left->const_expr.f * right->const_expr.f;
return true;
default:
UNREACHABLE
}
ERR: ERR:
SEMA_ERROR(expr, "Cannot multiply '%s' and '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); SEMA_ERROR(expr, "Cannot multiply '%s' and '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
@@ -923,19 +989,21 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr *
if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR; if (!binary_arithmetic_promotion(left, right, left_type, right_type)) goto ERR;
expr->type = left->type;
// Check null // Check null
if (right->expr_kind == EXPR_CONST) if (right->expr_kind == EXPR_CONST)
{ {
switch (right->const_expr.type) switch (right->const_expr.kind)
{ {
case CONST_INT: case ALL_INTS:
if (right->const_expr.i == 0) if (bigint_cmp_zero(&right->const_expr.i) == CMP_EQ)
{ {
SEMA_ERROR(right, "Division by zero not allowed."); SEMA_ERROR(right, "Division by zero not allowed.");
return false; return false;
} }
break; break;
case CONST_FLOAT: case ALL_FLOATS:
if (right->const_expr.f == 0) if (right->const_expr.f == 0)
{ {
SEMA_ERROR(right, "Division by zero not allowed."); SEMA_ERROR(right, "Division by zero not allowed.");
@@ -947,10 +1015,21 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr *
} }
} }
CONST_PROCESS(/)
expr->type = left->type; if (!both_const(left, right)) return true;
return true;
switch (left->const_expr.kind)
{
case ALL_INTS:
bigint_div_floor(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
return true;
case ALL_FLOATS:
expr->const_expr.f = left->const_expr.f / right->const_expr.f;
return true;
default:
UNREACHABLE
}
ERR: ERR:
SEMA_ERROR(expr, "Cannot divide '%s' by '%s'", type_to_error_string(left_type), type_to_error_string(right_type)); SEMA_ERROR(expr, "Cannot divide '%s' by '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
@@ -964,7 +1043,7 @@ static bool sema_expr_analyse_mod(Context *context, Type *to, Expr *expr, Expr *
if (!type_is_integer(right->type->canonical) || !type_is_integer(left->type->canonical)) return sema_type_error_on_binop(expr); if (!type_is_integer(right->type->canonical) || !type_is_integer(left->type->canonical)) return sema_type_error_on_binop(expr);
if (right->expr_kind == EXPR_CONST && right->const_expr.i == 0) if (right->expr_kind == EXPR_CONST && bigint_cmp_zero(&right->const_expr.i) == CMP_EQ)
{ {
SEMA_ERROR(expr->binary_expr.right, "Cannot perform mod by zero."); SEMA_ERROR(expr->binary_expr.right, "Cannot perform mod by zero.");
return false; return false;
@@ -974,7 +1053,7 @@ static bool sema_expr_analyse_mod(Context *context, Type *to, Expr *expr, Expr *
{ {
// TODO negative // TODO negative
expr_replace(expr, left); expr_replace(expr, left);
expr->const_expr.i %= right->const_expr.i; bigint_mod(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
return expr; return expr;
} }
@@ -990,7 +1069,8 @@ static bool sema_expr_analyse_mod(Context *context, Type *to, Expr *expr, Expr *
static bool sema_expr_analyse_mod_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) static bool sema_expr_analyse_mod_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
{ {
TODO } TODO
}
static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
@@ -1010,13 +1090,13 @@ static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr *
switch (expr->binary_expr.operator) switch (expr->binary_expr.operator)
{ {
case TOKEN_AMP: case TOKEN_AMP:
expr->const_expr.i &= right->const_expr.i; bigint_and(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
break; break;
case TOKEN_BIT_XOR: case TOKEN_BIT_XOR:
expr->const_expr.i ^= right->const_expr.i; bigint_xor(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
break; break;
case TOKEN_BIT_OR: case TOKEN_BIT_OR:
expr->const_expr.i |= right->const_expr.i; bigint_or(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
break; break;
default: default:
UNREACHABLE; UNREACHABLE;
@@ -1048,7 +1128,8 @@ static bool sema_expr_analyse_shr(Context *context, Type *to, Expr *expr, Expr *
if (right->expr_kind == EXPR_CONST) if (right->expr_kind == EXPR_CONST)
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) TODO
//if (int_exceeds(&right->const_expr.i, left->type->canonical->builtin.bitsize))
{ {
SEMA_ERROR(right, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type));
return false; return false;
@@ -1056,7 +1137,7 @@ static bool sema_expr_analyse_shr(Context *context, Type *to, Expr *expr, Expr *
if (left->expr_kind == EXPR_CONST) if (left->expr_kind == EXPR_CONST)
{ {
expr_replace(expr, left); expr_replace(expr, left);
expr->const_expr.i >>= right->const_expr.i; bigint_shr(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
return true; return true;
} }
} }
@@ -1083,7 +1164,8 @@ static bool sema_expr_analyse_shr_assign(Context *context, Type *to, Expr *expr,
if (right->expr_kind == EXPR_CONST) if (right->expr_kind == EXPR_CONST)
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) TODO
//if (int_exceeds(&right->const_expr.i, left->type->canonical->builtin.bitsize))
{ {
SEMA_ERROR(right, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type));
return false; return false;
@@ -1107,9 +1189,11 @@ static bool sema_expr_analyse_shl(Context *context, Type *to, Expr *expr, Expr *
// Next, cast to runtime types, this might be needed for runtime constants, e.g. x << 2 // Next, cast to runtime types, this might be needed for runtime constants, e.g. x << 2
if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false; if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false;
expr->type = left->type;
if (right->expr_kind == EXPR_CONST) if (right->expr_kind == EXPR_CONST)
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) TODO
//if (int_int_exceeds(&right->const_expr.i, left->type->canonical->builtin.bitsize))
{ {
SEMA_ERROR(right, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type));
return false; return false;
@@ -1117,12 +1201,20 @@ static bool sema_expr_analyse_shl(Context *context, Type *to, Expr *expr, Expr *
if (left->expr_kind == EXPR_CONST) if (left->expr_kind == EXPR_CONST)
{ {
expr_replace(expr, left); expr_replace(expr, left);
expr->const_expr.i <<= right->const_expr.i; if (left->const_expr.kind == TYPE_IXX)
{
bigint_shl(&expr->const_expr.i, &expr->const_expr.i, &right->const_expr.i);
}
else
{
int bit_count = left->type->canonical->builtin.bitsize;
bool is_signed = !type_kind_is_unsigned(left->const_expr.kind);
bigint_shl_trunc(&expr->const_expr.i, &expr->const_expr.i, &right->const_expr.i, bit_count, is_signed);
}
return true; return true;
} }
} }
expr->type = left->type;
return true; return true;
ERR: ERR:
@@ -1139,6 +1231,8 @@ static bool sema_expr_analyse_shl_assign(Context *context, Type *to, Expr *expr,
return false; return false;
} }
expr->type = left->type;
// Check that right side is integer and cast to a runtime type if needed. // Check that right side is integer and cast to a runtime type if needed.
if (!type_is_integer(right->type->canonical)) return sema_type_error_on_binop(expr); if (!type_is_integer(right->type->canonical)) return sema_type_error_on_binop(expr);
@@ -1146,14 +1240,20 @@ static bool sema_expr_analyse_shl_assign(Context *context, Type *to, Expr *expr,
if (right->expr_kind == EXPR_CONST) if (right->expr_kind == EXPR_CONST)
{ {
if (right->const_expr.i > left->type->canonical->builtin.bitsize) if (right->const_expr.i.is_negative)
{ {
SEMA_ERROR(right, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type)); SEMA_ERROR(right, "Leftshift constant was negative (%s). It must be zero or more.", expr_const_to_error_string(&right->const_expr));
return false; return false;
} }
BigInt max;
bigint_init_unsigned(&max, left->type->canonical->builtin.bitsize);
if (bigint_cmp(&right->const_expr.i, &max) == CMP_GT)
{
// IMPROVE suppress in macro?
SEMA_ERROR(right, "Leftshift exceeds bitsize of '%s', it cannot be higher.", type_to_error_string(left->type));
return expr_poison(right);
}
} }
expr->type = left->type;
return true; return true;
} }
@@ -1190,69 +1290,76 @@ static bool sema_expr_analyse_and_assign(Context *context, Type *to, Expr *expr,
static bool sema_expr_analyse_or_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { TODO } static bool sema_expr_analyse_or_assign(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { TODO }
static void cast_to_max_bit_size(Expr *left, Expr *right, Type *left_type, Type *right_type)
{
int bit_size_left = left_type->builtin.bitsize;
int bit_size_right = right_type->builtin.bitsize;
assert(bit_size_left && bit_size_right);
if (bit_size_left == bit_size_right) return;
if (bit_size_left < bit_size_right)
{
Type *to = left->type->type_kind < TYPE_U8
? type_signed_int_by_bitsize(bit_size_right)
: type_unsigned_int_by_bitsize(bit_size_right);
bool success = cast_implicit(left, to);
assert(success);
return;
}
Type *to = right->type->type_kind < TYPE_U8
? type_signed_int_by_bitsize(bit_size_right)
: type_unsigned_int_by_bitsize(bit_size_right);
bool success = cast_implicit(right, to);
assert(success);
}
static bool sema_expr_analyse_comp(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) static bool sema_expr_analyse_comp(Context *context, Type *to, Expr *expr, Expr *left, Expr *right)
{ {
if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false; if (!sema_expr_analyse_binary_sub_expr(context, left, right)) return false;
Type *left_type = left->type->canonical; Type *left_type = left->type->canonical;
Type *right_type = right->type->canonical; Type *right_type = right->type->canonical;
Type *max = type_find_max_type(left_type, right_type);
bool success = max && cast_implicit(left, max) && cast_implicit(right, max); // Handle the case of signed comparisons.
if (!success) if ((type_is_unsigned(left_type) && type_is_signed(right_type))
|| (type_is_signed(left_type) && type_is_unsigned(right_type)))
{ {
SEMA_ERROR(expr, "Cannot implicitly convert types to evaluate '%s' %s '%s'", type_to_error_string(left_type), token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), type_to_error_string(right_type)); cast_to_max_bit_size(left, right, left_type, right_type);
return false;
} }
else
{
// Alternatively, find and promote to max
Type *max = type_find_max_type(left_type, right_type);
bool success = max && cast_implicit(left, max) && cast_implicit(right, max);
if (!success)
{
SEMA_ERROR(expr, "Cannot implicitly convert types to evaluate '%s' %s '%s'", type_to_error_string(left_type), token_type_to_string(binaryop_to_token(expr->binary_expr.operator)), type_to_error_string(right_type));
return false;
}
}
if (both_const(left, right)) if (both_const(left, right))
{ {
#define COMP(_op_) \ switch (left->const_expr.kind)
switch (left->const_expr.type) { \
case CONST_FLOAT: expr->const_expr.b = left->const_expr.f _op_ right->const_expr.f; break; \
case CONST_BOOL: expr->const_expr.b = left->const_expr.b _op_ right->const_expr.b; break; \
case CONST_INT: expr->const_expr.b = left->const_expr.i _op_ right->const_expr.i; break; \
default: UNREACHABLE } break;
switch (expr->binary_expr.operator)
{ {
case BINARYOP_GT: case TYPE_BOOL:
COMP(>) SEMA_ERROR(expr, "Cannot compare booleans, convert them into integers first.");
case BINARYOP_GE: return false;
COMP(>=) case ALL_FLOATS:
case BINARYOP_LT: case ALL_INTS:
COMP(<) expr->const_expr.b = expr_const_compare(&left->const_expr, &right->const_expr, expr->binary_expr.operator);
case BINARYOP_LE: return true;
COMP(<=) case TYPE_STRING:
case BINARYOP_EQ: SEMA_ERROR(expr, "Cannot compare strings.");
// TODO elsewhere return false;
COMP(==)
case BINARYOP_NE:
// TODO elsewhere
COMP(!=)
default: default:
UNREACHABLE UNREACHABLE
} }
#undef COMP expr->const_expr.kind = TYPE_BOOL;
expr->const_expr.type = CONST_BOOL;
expr->expr_kind = EXPR_CONST; expr->expr_kind = EXPR_CONST;
} }
expr->type = type_bool; expr->type = type_bool;
return true; return true;
} }
#define SEMA_ANALYSE_CMP(op) { \
if (!cast_arithmetic(left, right, #op)) return false;\
if (!cast_arithmetic(right, left, #op)) return false;\
if (both_const(left, right)) { \
switch (left->const_expr.type) { \
case CONST_FLOAT: expr->const_expr.b = left->const_expr.f op right->const_expr.f; break; \
case CONST_BOOL: expr->const_expr.b = left->const_expr.b op right->const_expr.b; break; \
case CONST_INT: expr->const_expr.b = left->const_expr.i op right->const_expr.i; break; \
default: UNREACHABLE }\
expr->const_expr.type = CONST_BOOL;\
expr->expr_kind = EXPR_CONST;\
}\
if (!cast_to_runtime(left) || !cast_to_runtime(right)) return false;\
expr->type = type_bool;\
return true; }
static bool sema_expr_analyse_elvis(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { TODO } static bool sema_expr_analyse_elvis(Context *context, Type *to, Expr *expr, Expr *left, Expr *right) { TODO }
@@ -1298,41 +1405,74 @@ static bool sema_expr_analyse_neg(Context *context, Type *to, Expr *expr, Expr *
expr->type = inner->type; expr->type = inner->type;
return true; return true;
} }
// TODO UXX CAP bool is_negmod = expr->unary_expr.operator == UNARYOP_NEGMOD;
expr_replace(expr, inner); expr_replace(expr, inner);
switch (expr->const_expr.type) switch (expr->const_expr.kind)
{ {
case CONST_INT: case ALL_INTS:
expr->const_expr.i = ~expr->const_expr.i; if (is_negmod)
break; {
case CONST_FLOAT: if (inner->expr_kind != TYPE_IXX)
expr->const_expr.f = -expr->const_expr.i; {
SEMA_ERROR(expr, "Cannot use % on compile time integers, you need to first cast it to an integer type e.g. -%cast(-128, char).");
// Continue parsing, pretending this is a -
bigint_negate(&expr->const_expr.i, &inner->const_expr.i);
return true;
}
bigint_negate_wrap(&expr->const_expr.i,
&inner->const_expr.i,
inner->type->canonical->builtin.bitsize);
return true;
}
bigint_negate(&expr->const_expr.i, &inner->const_expr.i);
if (expr_const_int_overflowed(&expr->const_expr))
{
SEMA_ERROR(expr, "Negating %s overflows '%s'.", expr_const_to_error_string(&expr->const_expr), type_to_error_string(expr->type));
return false;
}
return true;
case ALL_FLOATS:
expr->const_expr.f = -expr->const_expr.f;
break; break;
default: default:
UNREACHABLE UNREACHABLE
} }
return true; return true;
} }
/**
* Analyse ~x and ~123
*
* @return
*/
static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Expr *inner) static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Expr *inner)
{ {
Type *canonical = inner->type->canonical; Type *canonical = inner->type->canonical;
if (!type_is_integer(canonical) && canonical != type_bool) if (!type_is_any_integer(canonical) && canonical != type_bool)
{ {
SEMA_ERROR(expr, "Cannot bit negate %s.", type_to_error_string(inner->type)); SEMA_ERROR(expr, "Cannot bit negate '%s'.", type_to_error_string(inner->type));
return false;
} }
// The simple case, non-const.
if (inner->expr_kind != EXPR_CONST) if (inner->expr_kind != EXPR_CONST)
{ {
expr->type = inner->type; expr->type = inner->type;
return true; return true;
} }
expr_replace(expr, inner); expr_replace(expr, inner);
// TODO UXX CAP switch (expr->const_expr.kind)
switch (expr->const_expr.type)
{ {
case CONST_INT: case ALL_SIGNED_INTS:
expr->const_expr.i = ~expr->const_expr.i; case ALL_UNSIGNED_INTS:
bigint_negate_wrap(&expr->const_expr.i, &inner->const_expr.i, canonical->builtin.bitsize);
break; break;
case CONST_BOOL: case TYPE_IXX:
bigint_negate(&expr->const_expr.i, &inner->const_expr.i);
break;
case TYPE_BOOL:
expr->const_expr.b = !expr->const_expr.b; expr->const_expr.b = !expr->const_expr.b;
break; break;
default: default:
@@ -1340,30 +1480,30 @@ static bool sema_expr_analyse_bit_not(Context *context, Type *to, Expr *expr, Ex
} }
return true; return true;
} }
static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *inner) static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *inner)
{ {
expr->type = type_bool; expr->type = type_bool;
if (inner->expr_kind == EXPR_CONST) if (inner->expr_kind == EXPR_CONST)
{ {
switch (expr->const_expr.type) switch (expr->const_expr.kind)
{ {
case CONST_NIL: case ALL_INTS:
expr->const_expr.b = true; expr->const_expr.b = bigint_cmp_zero(&inner->const_expr.i) == CMP_EQ;
break; break;
case CONST_BOOL: case TYPE_BOOL:
expr->const_expr.b = !inner->const_expr.b; expr->const_expr.b = !inner->const_expr.b;
break; break;
case CONST_INT: case ALL_FLOATS:
expr->const_expr.b = inner->const_expr.i == 0; expr->const_expr.b = inner->const_expr.f == 0.0;
break; break;
case CONST_FLOAT: case TYPE_STRING:
expr->const_expr.b = inner->const_expr.f == 0;
break;
case CONST_STRING:
expr->const_expr.b = !inner->const_expr.string.len; expr->const_expr.b = !inner->const_expr.string.len;
break; break;
default:
UNREACHABLE
} }
expr->const_expr.type = CONST_BOOL; expr->const_expr.kind = TYPE_BOOL;
expr->expr_kind = EXPR_CONST; expr->expr_kind = EXPR_CONST;
return true; return true;
} }
@@ -1372,7 +1512,6 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *
{ {
case TYPE_POISONED: case TYPE_POISONED:
case TYPE_IXX: case TYPE_IXX:
case TYPE_UXX:
case TYPE_FXX: case TYPE_FXX:
case TYPE_TYPEDEF: case TYPE_TYPEDEF:
case TYPE_ERROR_UNION: case TYPE_ERROR_UNION:
@@ -1411,12 +1550,12 @@ static inline bool sema_expr_analyse_incdec(Context *context, Type *to, Expr *ex
{ {
if (!expr_is_ltype(inner)) if (!expr_is_ltype(inner))
{ {
SEMA_ERROR(inner, "Expression cannot be assigned to"); SEMA_ERROR(inner, "Expression cannot be assigned to.");
return false; return false;
} }
if (!type_is_number(inner->type->canonical) && inner->type->canonical->type_kind != TYPE_POINTER) if (!type_is_number(inner->type->canonical) && inner->type->canonical->type_kind != TYPE_POINTER)
{ {
SEMA_ERROR(inner, "Expression must be a number or a pointer"); SEMA_ERROR(inner, "Expression must be a number or a pointer.");
return false; return false;
} }
expr->type = inner->type; expr->type = inner->type;
@@ -1436,7 +1575,6 @@ static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *ex
return sema_expr_analyse_assign(context, to, expr, left, right); return sema_expr_analyse_assign(context, to, expr, left, right);
case BINARYOP_MULT: case BINARYOP_MULT:
case BINARYOP_MULT_MOD: case BINARYOP_MULT_MOD:
// Todo treat mod differently
return sema_expr_analyse_mult(context, to, expr, left, right); return sema_expr_analyse_mult(context, to, expr, left, right);
case BINARYOP_MULT_ASSIGN: case BINARYOP_MULT_ASSIGN:
case BINARYOP_MULT_MOD_ASSIGN: case BINARYOP_MULT_MOD_ASSIGN:
@@ -1518,6 +1656,7 @@ static inline bool sema_expr_analyse_unary(Context *context, Type *to, Expr *exp
case UNARYOP_ADDR: case UNARYOP_ADDR:
return sema_expr_analyse_addr(context, to, expr, inner); return sema_expr_analyse_addr(context, to, expr, inner);
case UNARYOP_NEG: case UNARYOP_NEG:
case UNARYOP_NEGMOD:
return sema_expr_analyse_neg(context, to, expr, inner); return sema_expr_analyse_neg(context, to, expr, inner);
case UNARYOP_BITNEG: case UNARYOP_BITNEG:
return sema_expr_analyse_bit_not(context, to, expr, inner); return sema_expr_analyse_bit_not(context, to, expr, inner);
@@ -1923,7 +2062,7 @@ static inline bool sema_expr_analyse_macro_call2(Context *context, Type *to, Exp
TODO TODO
return success; return success;
}; }
static inline bool sema_expr_analyse_macro_expr(Context *context, Type *to, Expr *expr) static inline bool sema_expr_analyse_macro_expr(Context *context, Type *to, Expr *expr)
{ {

View File

@@ -3,6 +3,7 @@
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include "sema_internal.h" #include "sema_internal.h"
#include "bigint.h"
#pragma mark --- Context help functions #pragma mark --- Context help functions
@@ -48,10 +49,7 @@ static inline void context_pop_defers_to(Context *context, DeferList *list)
static inline void context_add_exit(Context *context, ExitType exit) static inline void context_add_exit(Context *context, ExitType exit)
{ {
if (context->current_scope->exit < exit) if (!context->current_scope->exit) context->current_scope->exit = exit;
{
context->current_scope->exit = exit;
}
} }
void context_pop_scope(Context *context) void context_pop_scope(Context *context)
@@ -61,7 +59,7 @@ void context_pop_scope(Context *context)
ExitType exit_type = context->current_scope->exit; ExitType exit_type = context->current_scope->exit;
assert (context->current_scope->defers.end == context->current_scope->defers.start); assert (context->current_scope->defers.end == context->current_scope->defers.start);
context->current_scope--; context->current_scope--;
if (context->current_scope->exit < exit_type) if (!context->current_scope->exit && exit_type)
{ {
context->current_scope->exit = exit_type; context->current_scope->exit = exit_type;
} }
@@ -125,7 +123,6 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
} }
UPDATE_EXIT(EXIT_RETURN); UPDATE_EXIT(EXIT_RETURN);
context->current_scope->exit = EXIT_RETURN;
Type *expected_rtype = context->rtype; Type *expected_rtype = context->rtype;
Expr *return_expr = statement->return_stmt.expr; Expr *return_expr = statement->return_stmt.expr;
@@ -145,6 +142,11 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
} }
return true; return true;
} }
if (expected_rtype == type_void)
{
SEMA_ERROR(statement, "You can't return a value from a void function, you need to add a return type.");
return false;
}
if (!sema_analyse_expr(context, expected_rtype, return_expr)) return false; if (!sema_analyse_expr(context, expected_rtype, return_expr)) return false;
if (!expected_rtype) if (!expected_rtype)
{ {
@@ -171,14 +173,6 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl)
return true; return true;
} }
static inline Ast *convert_expr_to_ast(Expr *expr)
{
Ast *ast = AST_NEW(AST_EXPR_STMT, expr->span);
ast->expr_stmt = expr;
return ast;
}
static inline bool sema_analyse_decl_expr_list(Context *context, Ast *stmt) static inline bool sema_analyse_decl_expr_list(Context *context, Ast *stmt)
{ {
@@ -305,11 +299,6 @@ static inline bool sema_analyse_defer_stmt(Context *context, Ast *statement)
return true; return true;
} }
static inline bool sema_analyse_default_stmt(Context *context __unused, Ast *statement)
{
SEMA_ERROR(statement, "Unexpected 'default' outside of switch");
return false;
}
static inline bool sema_analyse_for_stmt(Context *context, Ast *statement) static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
{ {
@@ -398,11 +387,17 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
success = false; success = false;
} }
} }
ExitType prev_exit = context->current_scope->exit;
success = success && sema_analyse_statement(context, statement->if_stmt.then_body); success = success && sema_analyse_statement(context, statement->if_stmt.then_body);
ExitType if_exit = context->current_scope->exit;
ExitType else_exit = prev_exit;
if (statement->if_stmt.else_body) if (statement->if_stmt.else_body)
{ {
context->current_scope->exit = prev_exit;
success = success && sema_analyse_statement(context, statement->if_stmt.else_body); success = success && sema_analyse_statement(context, statement->if_stmt.else_body);
else_exit = context->current_scope->exit;
} }
context->current_scope->exit = else_exit < if_exit ? else_exit : if_exit;
context_pop_defers_and_replace_ast(context, statement); context_pop_defers_and_replace_ast(context, statement);
context_pop_scope(context); context_pop_scope(context);
return success; return success;
@@ -423,6 +418,7 @@ static inline bool sema_analyse_label(Context *context, Ast *statement)
return false; return false;
} }
} }
context->current_scope->exit = EXIT_NONE;
vec_add(context->labels, statement); vec_add(context->labels, statement);
VECEACH(context->gotos, i) VECEACH(context->gotos, i)
{ {
@@ -456,6 +452,7 @@ static bool sema_analyse_break_stmt(Context *context, Ast *statement)
SEMA_ERROR(statement, "'break' is not allowed here."); SEMA_ERROR(statement, "'break' is not allowed here.");
return false; return false;
} }
UPDATE_EXIT(EXIT_BREAK);
DynamicScope *scope = context->current_scope; DynamicScope *scope = context->current_scope;
statement->break_stmt.defers.start = scope->defers.start; statement->break_stmt.defers.start = scope->defers.start;
while (!(scope->flags_created & SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise) while (!(scope->flags_created & SCOPE_BREAK)) // NOLINT(hicpp-signed-bitwise)
@@ -473,6 +470,7 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement)
SEMA_ERROR(statement, "'next' is not allowed here."); SEMA_ERROR(statement, "'next' is not allowed here.");
return false; return false;
} }
UPDATE_EXIT(EXIT_NEXT);
DynamicScope *scope = context->current_scope; DynamicScope *scope = context->current_scope;
statement->next_stmt.defers.start = scope->defers.start; statement->next_stmt.defers.start = scope->defers.start;
while (!(scope->flags_created & SCOPE_NEXT)) // NOLINT(hicpp-signed-bitwise) while (!(scope->flags_created & SCOPE_NEXT)) // NOLINT(hicpp-signed-bitwise)
@@ -483,11 +481,6 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement)
return true; return true;
} }
static bool sema_analyse_case_stmt(Context *context, Ast *statement)
{
SEMA_ERROR(statement, "Unexpected 'case' outside of switch");
return false;
}
static bool sema_analyse_continue_stmt(Context *context, Ast *statement) static bool sema_analyse_continue_stmt(Context *context, Ast *statement)
{ {
@@ -496,6 +489,7 @@ static bool sema_analyse_continue_stmt(Context *context, Ast *statement)
SEMA_ERROR(statement, "'continue' is not allowed here."); SEMA_ERROR(statement, "'continue' is not allowed here.");
return false; return false;
} }
UPDATE_EXIT(EXIT_CONTINUE);
DynamicScope *scope = context->current_scope; DynamicScope *scope = context->current_scope;
statement->continue_stmt.defers.start = scope->defers.start; statement->continue_stmt.defers.start = scope->defers.start;
while (!(scope->flags_created & SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise) while (!(scope->flags_created & SCOPE_CONTINUE)) // NOLINT(hicpp-signed-bitwise)
@@ -551,24 +545,39 @@ static bool sema_analyse_ct_if_stmt(Context *context, Ast *statement)
} }
static bool sema_analyse_case_expr(Context *context, Ast *case_stmt) static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_stmt)
{ {
Expr *case_expr = case_stmt->case_stmt.expr; Expr *case_expr = case_stmt->case_stmt.expr;
// TODO handle enums // TODO handle enums
if (!sema_analyse_expr(context, NULL, case_expr)) return false; // TODO string expr
if (!sema_analyse_expr(context, to_type, case_expr)) return false;
if (case_expr->expr_kind != EXPR_CONST) if (case_expr->expr_kind != EXPR_CONST)
{ {
SEMA_ERROR(case_expr, "This must be a constant expression."); SEMA_ERROR(case_expr, "This must be a constant expression.");
return false; return false;
} }
if (case_expr->const_expr.type != CONST_INT)
// As a special case, we handle bools, converting them to 0 / 1
if (case_expr->const_expr.kind == TYPE_BOOL)
{ {
SEMA_ERROR(case_expr, "The 'case' value must be an integer constant."); case_stmt->case_stmt.value_type = CASE_VALUE_UINT;
return false; case_stmt->case_stmt.val = case_expr->const_expr.b ? 1 : 0;
return true;
} }
assert(case_expr->const_expr.type == CONST_INT);
// TODO check for int
/*
if (case_expr->const_expr.kind < TYPE__!= CONST_INT && case_expr->const_expr.type != CONST_BOOL)
{
SEMA_ERROR(case_expr, "The 'case' value must be a boolean or integer constant.");
return false;
}*/
case_stmt->case_stmt.value_type = type_is_signed(case_expr->type->canonical) ? CASE_VALUE_INT : CASE_VALUE_UINT; case_stmt->case_stmt.value_type = type_is_signed(case_expr->type->canonical) ? CASE_VALUE_INT : CASE_VALUE_UINT;
uint64_t val = case_expr->const_expr.i; assert(case_expr->type->canonical->type_kind != TYPE_IXX);
// TODO this is incorrect
TODO
uint64_t val = (uint64_t)bigint_as_signed(&case_expr->const_expr.i);
case_stmt->case_stmt.val = val; case_stmt->case_stmt.val = val;
return true; return true;
} }
@@ -586,12 +595,6 @@ static inline bool sema_analyse_compound_statement_no_scope(Context *context, As
} }
} }
context_pop_defers_to(context, &compound_statement->compound_stmt.defer_list); context_pop_defers_to(context, &compound_statement->compound_stmt.defer_list);
/*
if (parent->exit < compound_statement->exit)
{
parent->exit = compound_statement->exit;
}*/
return all_ok; return all_ok;
} }
@@ -610,6 +613,7 @@ static inline Type *ast_cond_type(Ast *ast)
} }
} }
static bool sema_analyse_switch_stmt(Context *context, Ast *statement) static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
{ {
context_push_scope(context); context_push_scope(context);
@@ -617,20 +621,27 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
bool success = sema_analyse_cond(context, cond, false); bool success = sema_analyse_cond(context, cond, false);
Type *switch_type = ast_cond_type(cond)->canonical; Type *switch_type = ast_cond_type(cond)->canonical;
if (!type_is_integer(switch_type)) if (switch_type == type_bool || !type_is_integer(switch_type))
{ {
SEMA_ERROR(cond, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type)); SEMA_ERROR(cond, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type));
return false; return false;
} }
Ast *default_case = NULL; Ast *default_case = NULL;
assert(context->current_scope->defers.start == context->current_scope->defers.end); assert(context->current_scope->defers.start == context->current_scope->defers.end);
VECEACH(statement->switch_stmt.cases, i)
// TODO enum, exhaustive cases.
ExitType prev_exit = context->current_scope->exit;
bool exhaustive = false;
ExitType lowest_exit = EXIT_NONE;
unsigned cases = vec_size(statement->switch_stmt.cases);
for (unsigned i = 0; i < cases; i++)
{ {
context->current_scope->exit = prev_exit;
Ast *stmt = statement->switch_stmt.cases[i]; Ast *stmt = statement->switch_stmt.cases[i];
switch (stmt->ast_kind) switch (stmt->ast_kind)
{ {
case AST_CASE_STMT: case AST_CASE_STMT:
if (!sema_analyse_case_expr(context, stmt)) if (!sema_analyse_case_expr(context, switch_type, stmt))
{ {
success = false; success = false;
break; break;
@@ -647,6 +658,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
} }
break; break;
case AST_DEFAULT_STMT: case AST_DEFAULT_STMT:
exhaustive = true;
if (default_case) if (default_case)
{ {
SEMA_ERROR(stmt, "'default' may only appear once in a single 'switch', please remove one."); SEMA_ERROR(stmt, "'default' may only appear once in a single 'switch', please remove one.");
@@ -658,15 +670,41 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
default: default:
UNREACHABLE; UNREACHABLE;
} }
context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_NEXT); if (i == cases - 1)
{
context_push_scope_with_flags(context, SCOPE_BREAK);
}
else
{
context_push_scope_with_flags(context, SCOPE_NEXT | SCOPE_BREAK);
}
success = success && sema_analyse_compound_statement_no_scope(context, stmt->case_stmt.body); success = success && sema_analyse_compound_statement_no_scope(context, stmt->case_stmt.body);
ExitType case_exit = context->current_scope->exit;
if (case_exit != lowest_exit)
{
switch (case_exit)
{
case EXIT_NONE:
case EXIT_BREAK:
lowest_exit = EXIT_BREAK;
break;
case EXIT_NEXT:
// We ignore this completely
break;
default:
if (!lowest_exit || lowest_exit > case_exit) lowest_exit = case_exit;
break;
}
}
context_pop_scope(context); context_pop_scope(context);
} }
context_pop_defers_and_replace_ast(context, statement); context_pop_defers_and_replace_ast(context, statement);
if (lowest_exit <= EXIT_BREAK) lowest_exit = prev_exit;
context->current_scope->exit = exhaustive ? lowest_exit : EXIT_NONE;
context_pop_scope(context); context_pop_scope(context);
if (!success) return false; if (!success) return false;
// Is this a typeless switch value? // Is this a typeless switch value?
if (switch_type->type_kind == TYPE_UXX || switch_type->type_kind == TYPE_IXX) if (switch_type->type_kind == TYPE_IXX)
{ {
TODO TODO
@@ -701,6 +739,7 @@ static bool sema_analyse_try_stmt(Context *context, Ast *statement)
static bool sema_analyse_throw_stmt(Context *context, Ast *statement) static bool sema_analyse_throw_stmt(Context *context, Ast *statement)
{ {
Expr *throw_value = statement->throw_stmt.throw_value; Expr *throw_value = statement->throw_stmt.throw_value;
UPDATE_EXIT(EXIT_THROW);
if (!sema_analyse_expr(context, NULL, throw_value)) return false; if (!sema_analyse_expr(context, NULL, throw_value)) return false;
Type *type = throw_value->type->canonical; Type *type = throw_value->type->canonical;
if (type->type_kind != TYPE_ERROR) if (type->type_kind != TYPE_ERROR)
@@ -713,7 +752,7 @@ static bool sema_analyse_throw_stmt(Context *context, Ast *statement)
SEMA_ERROR(statement, "This 'throw' is not handled, please add a 'throws %s' clause to the function signature or use try-catch.", type->name); SEMA_ERROR(statement, "This 'throw' is not handled, please add a 'throws %s' clause to the function signature or use try-catch.", type->name);
return false; return false;
} }
VECADD(context->errors, type->decl); vec_add(context->errors, type->decl);
return true; return true;
} }
@@ -749,7 +788,8 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
case AST_BREAK_STMT: case AST_BREAK_STMT:
return sema_analyse_break_stmt(context, statement); return sema_analyse_break_stmt(context, statement);
case AST_CASE_STMT: case AST_CASE_STMT:
return sema_analyse_case_stmt(context, statement); SEMA_ERROR(statement, "Unexpected 'case' outside of switch");
return false;
case AST_CATCH_STMT: case AST_CATCH_STMT:
return sema_analyse_catch_stmt(context, statement); return sema_analyse_catch_stmt(context, statement);
case AST_COMPOUND_STMT: case AST_COMPOUND_STMT:
@@ -761,7 +801,8 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
case AST_DECLARE_STMT: case AST_DECLARE_STMT:
return sema_analyse_declare_stmt(context, statement); return sema_analyse_declare_stmt(context, statement);
case AST_DEFAULT_STMT: case AST_DEFAULT_STMT:
return sema_analyse_default_stmt(context, statement); SEMA_ERROR(statement, "Unexpected 'default' outside of switch");
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_DO_STMT: case AST_DO_STMT:
@@ -855,15 +896,18 @@ bool sema_analyse_function_body(Context *context, Decl *func)
func->func.annotations = CALLOCS(*func->func.annotations); func->func.annotations = CALLOCS(*func->func.annotations);
context_push_scope(context); context_push_scope(context);
Decl **params = func->func.function_signature.params; Decl **params = func->func.function_signature.params;
assert(context->current_scope == &context->scopes[1]);
VECEACH(params, i) VECEACH(params, i)
{ {
if (!sema_add_local(context, params[i])) return false; if (!sema_add_local(context, params[i])) return false;
} }
if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false; if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false;
if (context->current_scope->exit != EXIT_RETURN) assert(context->current_scope == &context->scopes[1]);
if (context->current_scope->exit != EXIT_RETURN && context->current_scope->exit != EXIT_THROW && context->current_scope->exit != EXIT_GOTO)
{ {
if (func->func.function_signature.rtype->type->canonical != type_void) if (func->func.function_signature.rtype->type->canonical != type_void)
{ {
// IMPROVE better pointer to end.
SEMA_ERROR(func, "Missing return statement at the end of the function."); SEMA_ERROR(func, "Missing return statement at the end of the function.");
return false; return false;
} }

View File

@@ -3,6 +3,8 @@
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
#include "sema_internal.h" #include "sema_internal.h"
#include "compiler_internal.h"
#include "bigint.h"
static inline bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info) static inline bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info)
@@ -23,6 +25,7 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type)
{ {
return type_info_poison(type); return type_info_poison(type);
} }
uint64_t len = 0;
if (type->array.len) if (type->array.len)
{ {
if (!sema_analyse_expr(context, type_usize, type->array.len)) return type_info_poison(type); if (!sema_analyse_expr(context, type_usize, type->array.len)) return type_info_poison(type);
@@ -31,9 +34,10 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type)
SEMA_ERROR(type->array.len, "Expected a constant value as array size."); SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
return type_info_poison(type); return type_info_poison(type);
} }
len = bigint_as_unsigned(&type->array.len->const_expr.i);
} }
assert(!type->array.len || type->array.len->expr_kind == EXPR_CONST); assert(!type->array.len || type->array.len->expr_kind == EXPR_CONST);
type->type = type_get_array(type->array.base->type, type->array.len ? type->array.len->const_expr.i : 0); type->type = type_get_array(type->array.base->type, len);
type->resolve_status = RESOLVE_DONE; type->resolve_status = RESOLVE_DONE;
return true; return true;
} }

View File

@@ -70,7 +70,6 @@ const char *type_to_error_string(Type *type)
case TYPE_U16: case TYPE_U16:
case TYPE_U32: case TYPE_U32:
case TYPE_U64: case TYPE_U64:
case TYPE_UXX:
case TYPE_F32: case TYPE_F32:
case TYPE_F64: case TYPE_F64:
case TYPE_FXX: case TYPE_FXX:
@@ -197,7 +196,7 @@ size_t type_size(Type *canonical)
case TYPE_F64: case TYPE_F64:
return canonical->builtin.bytesize; return canonical->builtin.bytesize;
case TYPE_IXX: case TYPE_IXX:
case TYPE_UXX: return 4;
case TYPE_FXX: case TYPE_FXX:
return 8; return 8;
case TYPE_FUNC: case TYPE_FUNC:
@@ -409,8 +408,7 @@ type_create(#_name, &_shortname, &type_ ## _name, _type, _bits, target->align_mi
create_type_cache(type_void); create_type_cache(type_void);
type_void->type_cache[0] = &t_voidstar; type_void->type_cache[0] = &t_voidstar;
t_voidstar.pointer = type_void; t_voidstar.pointer = type_void;
type_create("compint", &t_ixx, &type_compint, TYPE_IXX, 64, 0, 0); type_create("compint", &t_ixx, &type_compint, TYPE_IXX, 32, 0, 0);
type_create("compuint", &t_uxx, &type_compuint, TYPE_UXX, 64, 0, 0);
type_create("compfloat", &t_fxx, &type_compfloat, TYPE_FXX, 64, 0, 0); type_create("compfloat", &t_fxx, &type_compfloat, TYPE_FXX, 64, 0, 0);
type_create_alias("usize", &t_usz, &type_usize, type_unsigned_int_by_bitsize(target->width_pointer)); type_create_alias("usize", &t_usz, &type_usize, type_unsigned_int_by_bitsize(target->width_pointer));
@@ -471,46 +469,39 @@ bool type_may_have_method_functions(Type *type)
typedef enum typedef enum
{ {
L, L,
LS,
R, R,
RS,
FL, FL,
X,
} MaxType; } MaxType;
Type *type_find_max_num_type(Type *num_type, Type *other_num) Type *type_find_max_num_type(Type *num_type, Type *other_num)
{ {
if (other_num->type_kind < TYPE_BOOL || other_num->type_kind > TYPE_FXX) return NULL; if (other_num->type_kind < TYPE_I8 || other_num->type_kind > TYPE_FXX) return NULL;
assert(num_type->type_kind >= TYPE_BOOL && num_type->type_kind <= TYPE_FXX); assert(num_type->type_kind >= TYPE_I8 && num_type->type_kind <= TYPE_FXX);
static MaxType max_conv[TYPE_FXX - TYPE_BOOL + 1][TYPE_FXX - TYPE_BOOL + 1] = { static MaxType max_conv[TYPE_FXX - TYPE_I8 + 1][TYPE_FXX - TYPE_BOOL + 1] = {
//Bool I8 I16 I32 I64 IXX U8 U16 U32 U64 UXX F32 F64 FXX // I8 I16 I32 I64 U8 U16 U32 U64 IXX F32 F64 FXX
{ L, R, R, R, R, L, R, R, R, R, L, R, R, FL }, // Bool { L, R, R, R, X, X, X, X, L, R, R, FL }, // I8
{ L, L, R, R, R, L, L, RS, RS, RS, L, R, R, FL }, // I8 { L, L, R, R, L, X, X, X, L, R, R, FL }, // I16
{ L, L, L, R, R, L, L, L, RS, RS, L, R, R, FL }, // I16 { L, L, L, R, L, L, X, X, L, R, R, FL }, // I32
{ L, L, L, L, R, L, L, L, L, RS, L, R, R, FL }, // I32 { L, L, L, L, L, L, L, X, L, R, R, FL }, // I64
{ L, L, L, L, L, L, L, L, L, L, L, R, R, FL }, // I64 { X, R, R, R, L, R, R, R, L, R, R, FL }, // U8
{ R, R, R, R, R, L, RS, RS, RS, RS, L, R, R, R }, // IXX { X, X, R, R, L, L, R, R, L, R, R, FL }, // U16
{ L, R, R, R, R, LS, L, R, R, R, L, R, R, FL }, // U8 { X, X, X, R, L, L, L, R, L, R, R, FL }, // U32
{ L, LS, R, R, R, LS, L, L, R, R, L, R, R, FL }, // U16 { X, X, X, X, L, L, L, L, L, R, R, FL }, // U64
{ L, LS, LS, R, R, L, L, L, L, R, L, R, R, FL }, // U32 { R, R, R, R, R, R, R, R, L, R, R, R }, // IXX
{ L, LS, LS, LS, R, L, L, L, L, L, L, R, R, FL }, // U64 { L, L, L, L, L, L, L, L, L, L, R, L }, // F32
{ R, R, R, R, R, R, R, R, R, R, L, R, R, R }, // UXX { L, L, L, L, L, L, L, L, L, L, L, L }, // F64
{ L, L, L, L, L, L, L, L, L, L, L, L, R, L }, // F32 { FL, FL, FL, FL, FL, FL, FL, FL, FL, R, R, L }, // FXX
{ L, L, L, L, L, L, L, L, L, L, L, L, L, L }, // F32
{ FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, L, R, R, L }, // FXX
}; };
MaxType conversion = max_conv[num_type->type_kind - TYPE_BOOL][other_num->type_kind - TYPE_BOOL]; MaxType conversion = max_conv[num_type->type_kind - TYPE_I8][other_num->type_kind - TYPE_I8];
switch (conversion) switch (conversion)
{ {
case X:
return NULL;
case L: case L:
assert (num_type->type_kind != TYPE_FXX);
return num_type; return num_type;
case R: case R:
assert (other_num->type_kind != TYPE_FXX);
return other_num; return other_num;
case LS:
return type_signed_int_by_bitsize(num_type->builtin.bytesize * 8);
case RS:
return type_signed_int_by_bitsize(other_num->builtin.bytesize * 8);
case FL: case FL:
return type_double; return type_double;
default: default:
@@ -619,8 +610,8 @@ Type *type_find_max_type(Type *type, Type *other)
{ {
case TYPE_POISONED: case TYPE_POISONED:
case TYPE_VOID: case TYPE_VOID:
return NULL;
case TYPE_BOOL: case TYPE_BOOL:
return NULL;
case TYPE_I8: case TYPE_I8:
case TYPE_I16: case TYPE_I16:
case TYPE_I32: case TYPE_I32:
@@ -630,7 +621,6 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_U16: case TYPE_U16:
case TYPE_U32: case TYPE_U32:
case TYPE_U64: case TYPE_U64:
case TYPE_UXX:
case TYPE_F32: case TYPE_F32:
case TYPE_F64: case TYPE_F64:
case TYPE_FXX: case TYPE_FXX: