mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Merge pull request #20 from c3lang/develop
Some work towards automated testing. Fixes to bigint. Removed implici…
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(c3c)
|
project(c3c)
|
||||||
|
|
||||||
|
#set(CMAKE_BUILD_TYPE Release)
|
||||||
#set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
#set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||||
|
|
||||||
find_package(LLVM REQUIRED CONFIG)
|
find_package(LLVM REQUIRED CONFIG)
|
||||||
|
|||||||
48
resources/testfragments/conversion.c3
Normal file
48
resources/testfragments/conversion.c3
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
module conversion;
|
||||||
|
|
||||||
|
func int test(int a0, uint b0, ushort c0, short d0)
|
||||||
|
{
|
||||||
|
int a = 0;
|
||||||
|
uint b = 0;
|
||||||
|
ushort c = 0;
|
||||||
|
short d = 0;
|
||||||
|
a = a0;
|
||||||
|
b = b0;
|
||||||
|
c = c0;
|
||||||
|
d = d0;
|
||||||
|
b += 1;
|
||||||
|
a += 2;
|
||||||
|
// a += b; Error
|
||||||
|
a += c;
|
||||||
|
b += c;
|
||||||
|
a += d;
|
||||||
|
// b += d; Error
|
||||||
|
b = b + b;
|
||||||
|
a = c + c;
|
||||||
|
a = c - c;
|
||||||
|
a = c * c;
|
||||||
|
a = c / c;
|
||||||
|
a = c % c;
|
||||||
|
a = c +% c;
|
||||||
|
a = c -% c;
|
||||||
|
a = c *% c;
|
||||||
|
a = d + cast(c + c, ushort);
|
||||||
|
// a = c << 2; TODO
|
||||||
|
//a = c << c;
|
||||||
|
//a <<= c;
|
||||||
|
//a >>= c;
|
||||||
|
//a = c >> c;
|
||||||
|
// a = 2 << c; TODO
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func int test_top_down(int a0, uint b0, ushort c0, short d0)
|
||||||
|
{
|
||||||
|
int a = 0;
|
||||||
|
uint b = 0;
|
||||||
|
ushort c = 0;
|
||||||
|
short d = 0;
|
||||||
|
a = d + cast(c +% c, ushort);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@@ -423,6 +423,21 @@ func int xxxx(int x)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func int testPointers(int x)
|
||||||
|
{
|
||||||
|
1 ? 1 : 2;
|
||||||
|
int y = 0;
|
||||||
|
int* z = &y;
|
||||||
|
int d = *(z + y);
|
||||||
|
isize e = z - &y;
|
||||||
|
int* eff = &y + 1;
|
||||||
|
short x1 = 2;
|
||||||
|
float f = x1 +% x1 + 1.0;
|
||||||
|
float f2 = x1 -% x1 + 1.0;
|
||||||
|
usize ef = z - &y > 0 ? 1 : z - &y;
|
||||||
|
z - &y > 0 ? 1 : z - &y;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
func int main(int x)
|
func int main(int x)
|
||||||
{
|
{
|
||||||
int efd = 9;
|
int efd = 9;
|
||||||
@@ -447,9 +462,12 @@ func int main(int x)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
next;
|
next;
|
||||||
|
case 1000 >> 2:
|
||||||
|
printf("case 1000 >> 2\n");
|
||||||
|
case (1 << 200) >> 197:
|
||||||
|
printf("case 1 << 3\n");
|
||||||
default:
|
default:
|
||||||
printf("default\n");
|
printf("default\n");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
int aa = x++;
|
int aa = x++;
|
||||||
int bb = x--;
|
int bb = x--;
|
||||||
@@ -489,12 +507,12 @@ func int main(int x)
|
|||||||
if (ef == 4) printf("Works5!\n");
|
if (ef == 4) printf("Works5!\n");
|
||||||
if (ef == 4) printf("Works1!\n");
|
if (ef == 4) printf("Works1!\n");
|
||||||
ef = 0;
|
ef = 0;
|
||||||
/*
|
|
||||||
byte a = 2;
|
byte a = 2;
|
||||||
short b = 3;
|
short b = 3;
|
||||||
int c = 4;
|
int c = 4;
|
||||||
bool eok = true;
|
bool eok = true;
|
||||||
long deee = (eok ? a : b) + (eok ? b : c);*/
|
long deee = (eok ? a : b) + (eok ? b : c);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
JUMP:
|
JUMP:
|
||||||
|
|||||||
38
resources/tests/arithmetics.c3
Normal file
38
resources/tests/arithmetics.c3
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
module arithmetics;
|
||||||
|
|
||||||
|
func void testAdd(int a, int b)
|
||||||
|
{
|
||||||
|
a = a + b;
|
||||||
|
a = a +% b;
|
||||||
|
a +%= b;
|
||||||
|
a += b;
|
||||||
|
a += 1;
|
||||||
|
a +%= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
func void testSub(int a, int b)
|
||||||
|
{
|
||||||
|
a = a - b;
|
||||||
|
a = a -% b;
|
||||||
|
a -%= b;
|
||||||
|
a -= b;
|
||||||
|
a -%= 1;
|
||||||
|
a -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
func void testMult(int a, int b)
|
||||||
|
{
|
||||||
|
a = a * b;
|
||||||
|
a = a *% b;
|
||||||
|
a *%= b;
|
||||||
|
/*a *= b;
|
||||||
|
a *%= 1;
|
||||||
|
a *= 1;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
func void testDiv(int a, int b)
|
||||||
|
{
|
||||||
|
a = a / b;
|
||||||
|
a /= b;
|
||||||
|
a /= 1;
|
||||||
|
}
|
||||||
@@ -114,6 +114,7 @@ typedef enum
|
|||||||
TARGET_TYPE_EXECUTABLE,
|
TARGET_TYPE_EXECUTABLE,
|
||||||
TARGET_TYPE_STATIC_LIB,
|
TARGET_TYPE_STATIC_LIB,
|
||||||
TARGET_TYPE_DYNAMIC_LIB,
|
TARGET_TYPE_DYNAMIC_LIB,
|
||||||
|
TARGET_TYPE_TEST
|
||||||
} TargetType;
|
} TargetType;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|||||||
@@ -236,8 +236,6 @@ static BinaryOp assign_binop[BINARYOP_LAST + 1] = {
|
|||||||
[BINARYOP_SUB_MOD_ASSIGN] = BINARYOP_SUB_MOD,
|
[BINARYOP_SUB_MOD_ASSIGN] = BINARYOP_SUB_MOD,
|
||||||
[BINARYOP_DIV_ASSIGN] = BINARYOP_DIV,
|
[BINARYOP_DIV_ASSIGN] = BINARYOP_DIV,
|
||||||
[BINARYOP_MOD_ASSIGN] = BINARYOP_MOD,
|
[BINARYOP_MOD_ASSIGN] = BINARYOP_MOD,
|
||||||
[BINARYOP_AND_ASSIGN] = BINARYOP_AND,
|
|
||||||
[BINARYOP_OR_ASSIGN] = BINARYOP_OR,
|
|
||||||
[BINARYOP_BIT_AND_ASSIGN] = BINARYOP_BIT_AND,
|
[BINARYOP_BIT_AND_ASSIGN] = BINARYOP_BIT_AND,
|
||||||
[BINARYOP_BIT_OR_ASSIGN] = BINARYOP_BIT_OR,
|
[BINARYOP_BIT_OR_ASSIGN] = BINARYOP_BIT_OR,
|
||||||
[BINARYOP_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR,
|
[BINARYOP_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR,
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ static char digit_to_char(uint8_t digit, bool upper)
|
|||||||
}
|
}
|
||||||
if (digit <= 35)
|
if (digit <= 35)
|
||||||
{
|
{
|
||||||
return (char) (digit + (upper ? 'A' : 'a'));
|
return (char) (digit + (upper ? 'A' : 'a') - 10);
|
||||||
}
|
}
|
||||||
FATAL_ERROR("Can't reach");
|
FATAL_ERROR("Can't reach");
|
||||||
}
|
}
|
||||||
@@ -1579,12 +1579,15 @@ void bigint_shl_int(BigInt *dest, const BigInt *op1, uint64_t shift)
|
|||||||
bigint_init_bigint(dest, op1);
|
bigint_init_bigint(dest, op1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op1->digit_count == 0)
|
if (op1->digit_count == 0)
|
||||||
{
|
{
|
||||||
bigint_init_unsigned(dest, 0);
|
bigint_init_unsigned(dest, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t *op1_digits = bigint_ptr(op1);
|
const uint64_t *op1_digits = bigint_ptr(op1);
|
||||||
|
|
||||||
if (op1->digit_count == 1 && shift < 64)
|
if (op1->digit_count == 1 && shift < 64)
|
||||||
{
|
{
|
||||||
dest->digit = op1_digits[0] << shift;
|
dest->digit = op1_digits[0] << shift;
|
||||||
@@ -1596,18 +1599,17 @@ void bigint_shl_int(BigInt *dest, const BigInt *op1, uint64_t shift)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned digit_shift_count = (unsigned int) (shift / 64);
|
uint64_t digit_shift_count = shift / 64;
|
||||||
unsigned leftover_shift_count = (unsigned int) (shift % 64);
|
uint64_t leftover_shift_count = shift % 64;
|
||||||
|
|
||||||
dest->digits = alloc_digits(op1->digit_count + digit_shift_count + 1);
|
dest->digits = alloc_digits(op1->digit_count + digit_shift_count + 1);
|
||||||
dest->digit_count = digit_shift_count;
|
dest->digit_count = digit_shift_count;
|
||||||
uint64_t carry = 0;
|
uint64_t carry = 0;
|
||||||
for (size_t i = 0; i < op1->digit_count; i += 1)
|
for (size_t i = 0; i < op1->digit_count; i += 1)
|
||||||
{
|
{
|
||||||
uint64_t
|
uint64_t digit = op1_digits[i];
|
||||||
digit = op1_digits[i];
|
|
||||||
dest->digits[dest->digit_count] = carry | (digit << leftover_shift_count);
|
dest->digits[dest->digit_count] = carry | (digit << leftover_shift_count);
|
||||||
dest->digit_count += 1;
|
dest->digit_count++;
|
||||||
if (leftover_shift_count > 0)
|
if (leftover_shift_count > 0)
|
||||||
{
|
{
|
||||||
carry = digit >> (64 - leftover_shift_count);
|
carry = digit >> (64 - leftover_shift_count);
|
||||||
@@ -1654,15 +1656,15 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2)
|
|||||||
|
|
||||||
if (op1->digit_count == 1)
|
if (op1->digit_count == 1)
|
||||||
{
|
{
|
||||||
dest->digit = op1_digits[0] >> shift_amt;
|
dest->digit = shift_amt < 64 ? op1_digits[0] >> shift_amt : 0;
|
||||||
dest->digit_count = 1;
|
dest->digit_count = 1;
|
||||||
dest->is_negative = op1->is_negative;
|
dest->is_negative = op1->is_negative;
|
||||||
normalize(dest);
|
normalize(dest);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned digit_shift_count = (unsigned int) (shift_amt / 64);
|
uint64_t digit_shift_count = shift_amt / 64;
|
||||||
unsigned leftover_shift_count = (unsigned int) (shift_amt % 64);
|
uint64_t leftover_shift_count = shift_amt % 64;
|
||||||
|
|
||||||
if (digit_shift_count >= op1->digit_count)
|
if (digit_shift_count >= op1->digit_count)
|
||||||
{
|
{
|
||||||
@@ -1670,19 +1672,26 @@ void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dest->digit_count = op1->digit_count - digit_shift_count;
|
dest->digit_count = op1->digit_count - digit_shift_count;
|
||||||
dest->digits = alloc_digits(dest->digit_count);
|
uint64_t *digits;
|
||||||
uint64_t
|
if (dest->digit_count == 1)
|
||||||
carry = 0;
|
{
|
||||||
|
digits = &dest->digit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
digits = alloc_digits(dest->digit_count);
|
||||||
|
dest->digits = digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t carry = 0;
|
||||||
for (size_t op_digit_index = op1->digit_count - 1;;)
|
for (size_t op_digit_index = op1->digit_count - 1;;)
|
||||||
{
|
{
|
||||||
uint64_t
|
uint64_t digit = op1_digits[op_digit_index];
|
||||||
digit = op1_digits[op_digit_index];
|
|
||||||
size_t dest_digit_index = op_digit_index - digit_shift_count;
|
size_t dest_digit_index = op_digit_index - digit_shift_count;
|
||||||
dest->digits[dest_digit_index] = carry | (digit >> leftover_shift_count);
|
digits[dest_digit_index] = carry | (digit >> leftover_shift_count);
|
||||||
carry = digit << (64 - leftover_shift_count);
|
carry = digit << (64 - leftover_shift_count);
|
||||||
|
|
||||||
if (dest_digit_index == 0)
|
if (dest_digit_index == 0) break;
|
||||||
{ break; }
|
|
||||||
op_digit_index -= 1;
|
op_digit_index -= 1;
|
||||||
}
|
}
|
||||||
dest->is_negative = op1->is_negative;
|
dest->is_negative = op1->is_negative;
|
||||||
@@ -1851,7 +1860,7 @@ void bigint_print(BigInt *bigint, uint64_t base)
|
|||||||
bigint_init_bigint(a, bigint);
|
bigint_init_bigint(a, bigint);
|
||||||
|
|
||||||
BigInt base_bi = { 0 };
|
BigInt base_bi = { 0 };
|
||||||
bigint_init_unsigned(&base_bi, 10);
|
bigint_init_unsigned(&base_bi, base);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -1903,7 +1912,7 @@ const char *bigint_to_error_string(const BigInt *bigint, uint64_t base)
|
|||||||
bigint_init_bigint(a, bigint);
|
bigint_init_bigint(a, bigint);
|
||||||
|
|
||||||
BigInt base_bi = { 0 };
|
BigInt base_bi = { 0 };
|
||||||
bigint_init_unsigned(&base_bi, 10);
|
bigint_init_unsigned(&base_bi, base);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -1934,7 +1943,7 @@ const char *bigint_to_error_string(const BigInt *bigint, uint64_t base)
|
|||||||
*(current++) = *ptr;
|
*(current++) = *ptr;
|
||||||
}
|
}
|
||||||
*(current++) = '\0';
|
*(current++) = '\0';
|
||||||
return current;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base)
|
void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base)
|
||||||
@@ -1966,7 +1975,7 @@ void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base)
|
|||||||
bigint_init_bigint(a, bigint);
|
bigint_init_bigint(a, bigint);
|
||||||
|
|
||||||
BigInt base_bi = { 0 };
|
BigInt base_bi = { 0 };
|
||||||
bigint_init_unsigned(&base_bi, 10);
|
bigint_init_unsigned(&base_bi, base);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#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 IS_EXPLICT()
|
||||||
#define RETURN_NON_CONST_CAST(kind) do { if (left->expr_kind == EXPR_CONST) { insert_cast(left, kind, canonical); return true; } } while (0)
|
#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)
|
||||||
{
|
{
|
||||||
@@ -34,11 +34,8 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type)
|
|||||||
case CAST_TYPE_IMPLICIT:
|
case CAST_TYPE_IMPLICIT:
|
||||||
action = "implicitly cast";
|
action = "implicitly cast";
|
||||||
break;
|
break;
|
||||||
case CAST_TYPE_IMPLICIT_ASSIGN:
|
case CAST_TYPE_OPTIONAL_IMPLICIT:
|
||||||
case CAST_TYPE_IMPLICIT_ASSIGN_ADD:
|
UNREACHABLE
|
||||||
action = "assign";
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
SEMA_ERROR(expr, "Cannot %s '%s' to '%s'.", action, type_to_error_string(expr->type), type_to_error_string(type));
|
SEMA_ERROR(expr, "Cannot %s '%s' to '%s'.", action, type_to_error_string(expr->type), type_to_error_string(type));
|
||||||
return false;
|
return false;
|
||||||
@@ -52,7 +49,11 @@ bool erro(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
|||||||
|
|
||||||
bool ptxi(Expr *left, 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)
|
||||||
|
{
|
||||||
|
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
|
||||||
|
EXIT_T_MISMATCH();
|
||||||
|
}
|
||||||
RETURN_NON_CONST_CAST(CAST_PTRXI);
|
RETURN_NON_CONST_CAST(CAST_PTRXI);
|
||||||
|
|
||||||
assert(left->const_expr.kind == TYPE_POINTER);
|
assert(left->const_expr.kind == TYPE_POINTER);
|
||||||
@@ -62,9 +63,9 @@ bool ptxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ptbo(Expr *left, 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();
|
|
||||||
RETURN_NON_CONST_CAST(CAST_PTRBOOL);
|
RETURN_NON_CONST_CAST(CAST_PTRBOOL);
|
||||||
|
|
||||||
assert(left->const_expr.kind == TYPE_POINTER);
|
assert(left->const_expr.kind == TYPE_POINTER);
|
||||||
@@ -196,7 +197,7 @@ bool boxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
|||||||
*/
|
*/
|
||||||
bool bofp(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
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();
|
||||||
RETURN_NON_CONST_CAST(CAST_BOOLFP);
|
RETURN_NON_CONST_CAST(CAST_BOOLFP);
|
||||||
|
|
||||||
assert(left->const_expr.kind == TYPE_BOOL);
|
assert(left->const_expr.kind == TYPE_BOOL);
|
||||||
@@ -211,7 +212,7 @@ bool bofp(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
|||||||
*/
|
*/
|
||||||
bool xibo(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
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();
|
||||||
RETURN_NON_CONST_CAST(CAST_INTBOOL);
|
RETURN_NON_CONST_CAST(CAST_INTBOOL);
|
||||||
|
|
||||||
expr_const_set_bool(&left->const_expr, bigint_cmp_zero(&left->const_expr.i) != CMP_EQ);
|
expr_const_set_bool(&left->const_expr, bigint_cmp_zero(&left->const_expr.i) != CMP_EQ);
|
||||||
@@ -225,7 +226,7 @@ bool xibo(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
|||||||
*/
|
*/
|
||||||
bool fpbo(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
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();
|
||||||
RETURN_NON_CONST_CAST(CAST_FPBOOL);
|
RETURN_NON_CONST_CAST(CAST_FPBOOL);
|
||||||
|
|
||||||
expr_const_set_bool(&left->const_expr, left->const_expr.f != 0.0);
|
expr_const_set_bool(&left->const_expr, left->const_expr.f != 0.0);
|
||||||
@@ -242,7 +243,7 @@ bool fpfp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
|||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
// if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH();
|
||||||
|
|
||||||
RETURN_NON_CONST_CAST(CAST_FPFP);
|
RETURN_NON_CONST_CAST(CAST_FPFP);
|
||||||
|
|
||||||
@@ -287,8 +288,9 @@ bool ixxxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
|||||||
{
|
{
|
||||||
bool is_signed = canonical->type_kind < TYPE_U8;
|
bool is_signed = canonical->type_kind < TYPE_U8;
|
||||||
int bitsize = canonical->builtin.bitsize;
|
int bitsize = canonical->builtin.bitsize;
|
||||||
if (cast_is_implicit(cast_type) && !bigint_fits_in_bits(&left->const_expr.i, bitsize, is_signed))
|
if (cast_type != CAST_TYPE_EXPLICIT && !bigint_fits_in_bits(&left->const_expr.i, bitsize, is_signed))
|
||||||
{
|
{
|
||||||
|
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
|
||||||
SEMA_ERROR(left, "'%s' does not fit into '%s'", expr_const_to_error_string(&left->const_expr), canonical->name);
|
SEMA_ERROR(left, "'%s' does not fit into '%s'", expr_const_to_error_string(&left->const_expr), canonical->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -308,7 +310,11 @@ bool sisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
|||||||
{
|
{
|
||||||
bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
|
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_EXPLICIT)
|
||||||
|
{
|
||||||
|
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
|
||||||
|
EXIT_T_MISMATCH();
|
||||||
|
}
|
||||||
|
|
||||||
RETURN_NON_CONST_CAST(CAST_SISI);
|
RETURN_NON_CONST_CAST(CAST_SISI);
|
||||||
|
|
||||||
@@ -328,7 +334,11 @@ bool uiui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
|||||||
{
|
{
|
||||||
bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize;
|
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_EXPLICIT)
|
||||||
|
{
|
||||||
|
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
|
||||||
|
EXIT_T_MISMATCH();
|
||||||
|
}
|
||||||
|
|
||||||
RETURN_NON_CONST_CAST(CAST_UIUI);
|
RETURN_NON_CONST_CAST(CAST_UIUI);
|
||||||
|
|
||||||
@@ -349,7 +359,11 @@ bool uisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
|||||||
{
|
{
|
||||||
bool is_widening = from->builtin.bytesize < canonical->builtin.bytesize;
|
bool is_widening = from->builtin.bytesize < canonical->builtin.bytesize;
|
||||||
|
|
||||||
if (!is_widening && cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
|
if (!is_widening && cast_type != CAST_TYPE_EXPLICIT)
|
||||||
|
{
|
||||||
|
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
|
||||||
|
EXIT_T_MISMATCH();
|
||||||
|
}
|
||||||
|
|
||||||
RETURN_NON_CONST_CAST(CAST_UISI);
|
RETURN_NON_CONST_CAST(CAST_UISI);
|
||||||
|
|
||||||
@@ -367,7 +381,7 @@ bool uisi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
|||||||
*/
|
*/
|
||||||
bool siui(Expr *left, Type *canonical, Type *type, CastType cast_type)
|
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();
|
if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH();
|
||||||
|
|
||||||
RETURN_NON_CONST_CAST(CAST_SIUI);
|
RETURN_NON_CONST_CAST(CAST_SIUI);
|
||||||
|
|
||||||
@@ -455,17 +469,20 @@ bool uius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
|
|||||||
* Cast comptime, signed or unsigned -> pointer.
|
* Cast comptime, signed or unsigned -> pointer.
|
||||||
* @return true unless the constant value evaluates to zero.
|
* @return true unless the constant value evaluates to zero.
|
||||||
*/
|
*/
|
||||||
bool xipt(Expr *left, Type *canonical, Type *type)
|
bool xipt(Expr *left, Type *from, Type *canonical, Type *type, CastType cast_type)
|
||||||
{
|
{
|
||||||
RETURN_NON_CONST_CAST(CAST_XIPTR);
|
if (cast_type == CAST_TYPE_EXPLICIT && left->expr_kind == EXPR_CONST)
|
||||||
if (bigint_cmp_zero(&left->const_expr.i) != CMP_EQ)
|
|
||||||
{
|
{
|
||||||
SEMA_ERROR(left, "Only constants evaluating to zero can be cast to pointers.");
|
RETURN_NON_CONST_CAST(CAST_XIPTR);
|
||||||
return false;
|
if (bigint_cmp_zero(&left->const_expr.i) != CMP_EQ)
|
||||||
|
{
|
||||||
|
SEMA_ERROR(left, "Cannot cast non zero constants into pointers.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
expr_const_set_nil(&left->const_expr);
|
||||||
|
left->type = type;
|
||||||
}
|
}
|
||||||
expr_const_set_nil(&left->const_expr);
|
return cast(left, type_is_unsigned(from) ? type_usize : type_isize, cast_type);
|
||||||
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)
|
||||||
@@ -548,6 +565,24 @@ bool cast_to_runtime(Expr *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cast_to_smallest_runtime(Expr *expr)
|
||||||
|
{
|
||||||
|
Type *canonical = expr->type->canonical;
|
||||||
|
int success;
|
||||||
|
switch (canonical->type_kind)
|
||||||
|
{
|
||||||
|
case TYPE_IXX:
|
||||||
|
success = cast(expr, type_long, CAST_TYPE_IMPLICIT);
|
||||||
|
break;
|
||||||
|
case TYPE_FXX:
|
||||||
|
success = cast(expr, type_double, CAST_TYPE_IMPLICIT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(success && "This should always work");
|
||||||
|
}
|
||||||
|
|
||||||
bool cast_implicit(Expr *expr, Type *to_type)
|
bool cast_implicit(Expr *expr, Type *to_type)
|
||||||
{
|
{
|
||||||
if (!to_type) return true;
|
if (!to_type) return true;
|
||||||
@@ -620,7 +655,7 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
|
|||||||
if (type_is_integer(canonical)) return ixxxi(expr, canonical, to_type, cast_type);
|
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 (type_is_float(canonical)) return ixxfp(expr, canonical, to_type, cast_type);
|
||||||
if (canonical == type_bool) return ixxbo(expr, to_type);
|
if (canonical == type_bool) return ixxbo(expr, to_type);
|
||||||
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, canonical, to_type);
|
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type);
|
||||||
break;
|
break;
|
||||||
case TYPE_I8:
|
case TYPE_I8:
|
||||||
case TYPE_I16:
|
case TYPE_I16:
|
||||||
@@ -630,7 +665,7 @@ bool cast(Expr *expr, Type *to_type, CastType 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, canonical, to_type);
|
if (type_is_float(canonical)) return sifp(expr, canonical, to_type);
|
||||||
if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type);
|
if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type);
|
||||||
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, canonical, to_type);
|
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type);
|
||||||
break;
|
break;
|
||||||
case TYPE_U8:
|
case TYPE_U8:
|
||||||
case TYPE_U16:
|
case TYPE_U16:
|
||||||
@@ -640,7 +675,7 @@ bool cast(Expr *expr, Type *to_type, CastType 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, canonical, to_type);
|
if (type_is_float(canonical)) return uifp(expr, canonical, to_type);
|
||||||
if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type);
|
if (canonical == type_bool) return xibo(expr, canonical, to_type, cast_type);
|
||||||
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, canonical, to_type);
|
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type);
|
||||||
break;
|
break;
|
||||||
case TYPE_F32:
|
case TYPE_F32:
|
||||||
case TYPE_F64:
|
case TYPE_F64:
|
||||||
|
|||||||
@@ -582,16 +582,7 @@ typedef struct
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
union
|
Expr *expr; // NULL == DEFAULT
|
||||||
{
|
|
||||||
Expr *expr;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint64_t val;
|
|
||||||
CaseValueType value_type : 3;
|
|
||||||
bool has_next;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
Ast *body;
|
Ast *body;
|
||||||
void *backend_value;
|
void *backend_value;
|
||||||
} AstCaseStmt;
|
} AstCaseStmt;
|
||||||
@@ -982,15 +973,13 @@ 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)
|
void cast_to_smallest_runtime(Expr *expr);
|
||||||
{
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
||||||
|
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr);
|
||||||
bool sema_analyse_expr(Context *context, Type *to, Expr *expr);
|
bool sema_analyse_expr(Context *context, Type *to, Expr *expr);
|
||||||
bool sema_analyse_decl(Context *context, Decl *decl);
|
bool sema_analyse_decl(Context *context, Decl *decl);
|
||||||
|
|
||||||
@@ -1237,7 +1226,7 @@ static inline bool type_convert_will_trunc(Type *destination, Type *source)
|
|||||||
return (unsigned)destination->canonical->builtin.bitsize < (unsigned)source->canonical->builtin.bitsize;
|
return (unsigned)destination->canonical->builtin.bitsize < (unsigned)source->canonical->builtin.bitsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_number(Type *type)
|
static inline bool type_is_numeric(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX;
|
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX;
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ void diag_reset(void)
|
|||||||
diagnostics.warnings = 0;
|
diagnostics.warnings = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_panic_mode(void)
|
|
||||||
{
|
|
||||||
diagnostics.panic_mode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
PRINT_TYPE_ERROR,
|
PRINT_TYPE_ERROR,
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ typedef enum
|
|||||||
BINARYOP_SUB_MOD_ASSIGN,
|
BINARYOP_SUB_MOD_ASSIGN,
|
||||||
BINARYOP_DIV_ASSIGN,
|
BINARYOP_DIV_ASSIGN,
|
||||||
BINARYOP_MOD_ASSIGN,
|
BINARYOP_MOD_ASSIGN,
|
||||||
BINARYOP_AND_ASSIGN,
|
|
||||||
BINARYOP_OR_ASSIGN,
|
|
||||||
BINARYOP_BIT_AND_ASSIGN,
|
BINARYOP_BIT_AND_ASSIGN,
|
||||||
BINARYOP_BIT_OR_ASSIGN,
|
BINARYOP_BIT_OR_ASSIGN,
|
||||||
BINARYOP_BIT_XOR_ASSIGN,
|
BINARYOP_BIT_XOR_ASSIGN,
|
||||||
@@ -113,12 +111,6 @@ typedef enum
|
|||||||
ATTR_UNRESOLVED,
|
ATTR_UNRESOLVED,
|
||||||
} AttrKind;
|
} AttrKind;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
CASE_VALUE_INT,
|
|
||||||
CASE_VALUE_UINT,
|
|
||||||
CASE_VALUE_DEFAULT
|
|
||||||
} CaseValueType;
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -175,8 +167,7 @@ typedef enum _CastType
|
|||||||
{
|
{
|
||||||
CAST_TYPE_EXPLICIT,
|
CAST_TYPE_EXPLICIT,
|
||||||
CAST_TYPE_IMPLICIT,
|
CAST_TYPE_IMPLICIT,
|
||||||
CAST_TYPE_IMPLICIT_ASSIGN,
|
CAST_TYPE_OPTIONAL_IMPLICIT,
|
||||||
CAST_TYPE_IMPLICIT_ASSIGN_ADD,
|
|
||||||
} CastType;
|
} CastType;
|
||||||
|
|
||||||
|
|
||||||
@@ -355,7 +346,7 @@ typedef enum
|
|||||||
TOKEN_RPARBRA, // })
|
TOKEN_RPARBRA, // })
|
||||||
TOKEN_SCOPE, // ::
|
TOKEN_SCOPE, // ::
|
||||||
TOKEN_SHR, // >>
|
TOKEN_SHR, // >>
|
||||||
TOKEN_SHL, // >>
|
TOKEN_SHL, // <<
|
||||||
|
|
||||||
// Three or more
|
// Three or more
|
||||||
TOKEN_ELIPSIS, // ...
|
TOKEN_ELIPSIS, // ...
|
||||||
@@ -459,16 +450,6 @@ typedef enum
|
|||||||
TOKEN_VOLATILE,
|
TOKEN_VOLATILE,
|
||||||
TOKEN_WHILE,
|
TOKEN_WHILE,
|
||||||
|
|
||||||
TOKEN_AT_PARAM, // @param
|
|
||||||
TOKEN_AT_THROWS, // @throws
|
|
||||||
TOKEN_AT_RETURN, // @return
|
|
||||||
TOKEN_AT_ENSURE, // @ensure
|
|
||||||
TOKEN_AT_REQUIRE, // @require
|
|
||||||
TOKEN_AT_PURE, // @pure
|
|
||||||
TOKEN_AT_CONST, // @const
|
|
||||||
TOKEN_AT_REQPARSE, // @reqparse
|
|
||||||
TOKEN_AT_DEPRECATED, // @deprecated
|
|
||||||
|
|
||||||
TOKEN_CT_CASE, // $case
|
TOKEN_CT_CASE, // $case
|
||||||
TOKEN_CT_DEFAULT, // $default
|
TOKEN_CT_DEFAULT, // $default
|
||||||
TOKEN_CT_FOR, // $for
|
TOKEN_CT_FOR, // $for
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ Token lexer_scan_token(Lexer *lexer)
|
|||||||
if (match(lexer, '+')) return parse_nested_comment(lexer);
|
if (match(lexer, '+')) return parse_nested_comment(lexer);
|
||||||
return match(lexer, '=') ? make_token(lexer, TOKEN_DIV_ASSIGN, "/=") : make_token(lexer, TOKEN_DIV, "/");
|
return match(lexer, '=') ? make_token(lexer, TOKEN_DIV_ASSIGN, "/=") : make_token(lexer, TOKEN_DIV, "/");
|
||||||
case '*':
|
case '*':
|
||||||
if (match(lexer, '%')) return match(lexer, '=') ? make_token(lexer, TOKEN_MINUS_MOD_ASSIGN, "*%=") : make_token(lexer, TOKEN_MULT_MOD, "*%");
|
if (match(lexer, '%')) return match(lexer, '=') ? make_token(lexer, TOKEN_MULT_MOD_ASSIGN, "*%=") : make_token(lexer, TOKEN_MULT_MOD, "*%");
|
||||||
return match(lexer, '=') ? make_token(lexer, TOKEN_MULT_ASSIGN, "*=") : make_token(lexer, TOKEN_STAR, "*");
|
return match(lexer, '=') ? make_token(lexer, TOKEN_MULT_ASSIGN, "*=") : make_token(lexer, TOKEN_STAR, "*");
|
||||||
case '=':
|
case '=':
|
||||||
return match(lexer, '=') ? make_token(lexer, TOKEN_EQEQ, "==") : make_token(lexer, TOKEN_EQ, "=");
|
return match(lexer, '=') ? make_token(lexer, TOKEN_EQEQ, "==") : make_token(lexer, TOKEN_EQ, "=");
|
||||||
@@ -607,5 +607,15 @@ Token lexer_scan_ident_test(Lexer *lexer, const char *scan)
|
|||||||
lexer->current_file->end_id = 1000;
|
lexer->current_file->end_id = 1000;
|
||||||
lexer->current_file->name = "Foo";
|
lexer->current_file->name = "Foo";
|
||||||
|
|
||||||
|
if (scan[0] == '$')
|
||||||
|
{
|
||||||
|
next(lexer);
|
||||||
|
return scan_prefixed_ident(lexer, TOKEN_CT_IDENT, TOKEN_DOLLAR, false, "$");
|
||||||
|
}
|
||||||
|
if (scan[0] == '#')
|
||||||
|
{
|
||||||
|
next(lexer);
|
||||||
|
return scan_prefixed_ident(lexer, TOKEN_HASH_IDENT, TOKEN_HASH, false, "#");
|
||||||
|
}
|
||||||
return scan_ident(lexer);
|
return scan_ident(lexer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -551,8 +551,6 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
|
|||||||
case BINARYOP_SUB_MOD_ASSIGN:
|
case BINARYOP_SUB_MOD_ASSIGN:
|
||||||
case BINARYOP_DIV_ASSIGN:
|
case BINARYOP_DIV_ASSIGN:
|
||||||
case BINARYOP_MOD_ASSIGN:
|
case BINARYOP_MOD_ASSIGN:
|
||||||
case BINARYOP_AND_ASSIGN:
|
|
||||||
case BINARYOP_OR_ASSIGN:
|
|
||||||
case BINARYOP_BIT_AND_ASSIGN:
|
case BINARYOP_BIT_AND_ASSIGN:
|
||||||
case BINARYOP_BIT_OR_ASSIGN:
|
case BINARYOP_BIT_OR_ASSIGN:
|
||||||
case BINARYOP_BIT_XOR_ASSIGN:
|
case BINARYOP_BIT_XOR_ASSIGN:
|
||||||
|
|||||||
@@ -426,7 +426,6 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
|
|||||||
// TODO check defer correctness
|
// TODO check defer correctness
|
||||||
if (ast->switch_stmt.decl) gencontext_emit_decl_expr_list_ignore_result(context, ast->switch_stmt.decl);
|
if (ast->switch_stmt.decl) gencontext_emit_decl_expr_list_ignore_result(context, ast->switch_stmt.decl);
|
||||||
LLVMValueRef switch_value = gencontext_emit_decl_expr_list(context, ast->switch_stmt.cond, false);
|
LLVMValueRef switch_value = gencontext_emit_decl_expr_list(context, ast->switch_stmt.cond, false);
|
||||||
|
|
||||||
size_t cases = vec_size(ast->switch_stmt.cases);
|
size_t cases = vec_size(ast->switch_stmt.cases);
|
||||||
if (!cases)
|
if (!cases)
|
||||||
{
|
{
|
||||||
@@ -438,7 +437,7 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
|
|||||||
VECEACH(ast->switch_stmt.cases, i)
|
VECEACH(ast->switch_stmt.cases, i)
|
||||||
{
|
{
|
||||||
Ast *case_stmt = ast->switch_stmt.cases[i];
|
Ast *case_stmt = ast->switch_stmt.cases[i];
|
||||||
if (case_stmt->case_stmt.value_type == CASE_VALUE_DEFAULT)
|
if (!case_stmt->case_stmt.expr)
|
||||||
{
|
{
|
||||||
if (case_stmt->case_stmt.body)
|
if (case_stmt->case_stmt.body)
|
||||||
{
|
{
|
||||||
@@ -494,7 +493,7 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
|
|||||||
LLVMBasicBlockRef block = case_stmt->case_stmt.backend_value;
|
LLVMBasicBlockRef block = case_stmt->case_stmt.backend_value;
|
||||||
if (case_stmt != default_case)
|
if (case_stmt != default_case)
|
||||||
{
|
{
|
||||||
LLVMValueRef case_value = LLVMConstInt(LLVMTypeOf(switch_value), case_stmt->case_stmt.val, case_stmt->case_stmt.value_type == CASE_VALUE_INT);
|
LLVMValueRef case_value = gencontext_emit_expr(context, case_stmt->case_stmt.expr);
|
||||||
LLVMAddCase(switch_stmt, case_value, block);
|
LLVMAddCase(switch_stmt, case_value, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ static Expr *parse_unary_expr(Context *context, Expr *left)
|
|||||||
CHECK_EXPR(right_side);
|
CHECK_EXPR(right_side);
|
||||||
|
|
||||||
unary->unary_expr.expr = right_side;
|
unary->unary_expr.expr = right_side;
|
||||||
|
unary->span.end_loc = right_side->span.end_loc;
|
||||||
return unary;
|
return unary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ static inline Ast *parse_default_stmt(Context *context)
|
|||||||
TRY_CONSUME_OR(TOKEN_COLON, "Expected ':' after 'default'.", &poisoned_ast);
|
TRY_CONSUME_OR(TOKEN_COLON, "Expected ':' after 'default'.", &poisoned_ast);
|
||||||
extend_ast_with_prev_token(context, ast);
|
extend_ast_with_prev_token(context, ast);
|
||||||
ast->case_stmt.body = TRY_AST(parse_case_stmts(context));
|
ast->case_stmt.body = TRY_AST(parse_case_stmts(context));
|
||||||
ast->case_stmt.value_type = CASE_VALUE_DEFAULT;
|
ast->case_stmt.expr = NULL;
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,15 +796,6 @@ Ast *parse_stmt(Context *context)
|
|||||||
case TOKEN_UNTIL:
|
case TOKEN_UNTIL:
|
||||||
case TOKEN_ATTRIBUTE:
|
case TOKEN_ATTRIBUTE:
|
||||||
case TOKEN_VAR:
|
case TOKEN_VAR:
|
||||||
case TOKEN_AT_PARAM:
|
|
||||||
case TOKEN_AT_THROWS:
|
|
||||||
case TOKEN_AT_RETURN:
|
|
||||||
case TOKEN_AT_ENSURE:
|
|
||||||
case TOKEN_AT_REQUIRE:
|
|
||||||
case TOKEN_AT_PURE:
|
|
||||||
case TOKEN_AT_CONST:
|
|
||||||
case TOKEN_AT_REQPARSE:
|
|
||||||
case TOKEN_AT_DEPRECATED:
|
|
||||||
case TOKEN_DOCS_START:
|
case TOKEN_DOCS_START:
|
||||||
case TOKEN_DOCS_END:
|
case TOKEN_DOCS_END:
|
||||||
case TOKEN_DOCS_EOL:
|
case TOKEN_DOCS_EOL:
|
||||||
|
|||||||
@@ -514,6 +514,7 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type)
|
|||||||
SEMA_TOKEN_ERROR(context->tok, "Expected '{'.");
|
SEMA_TOKEN_ERROR(context->tok, "Expected '{'.");
|
||||||
return &poisoned_decl;
|
return &poisoned_decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_IDENT_FOR_OR("variable_name", &poisoned_decl);
|
EXPECT_IDENT_FOR_OR("variable_name", &poisoned_decl);
|
||||||
|
|
||||||
Token name = context->tok;
|
Token name = context->tok;
|
||||||
@@ -607,6 +608,13 @@ static inline Decl *parse_global_declaration(Context *context, Visibility visibi
|
|||||||
|
|
||||||
Decl *decl = decl_new_var(context->tok, type, VARDECL_GLOBAL, visibility);
|
Decl *decl = decl_new_var(context->tok, type, VARDECL_GLOBAL, visibility);
|
||||||
|
|
||||||
|
if (context->tok.type == TOKEN_FUNC)
|
||||||
|
{
|
||||||
|
SEMA_TOKEN_ERROR(context->tok, "'func' can't appear here, maybe you intended to put 'func' the type?");
|
||||||
|
advance(context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!consume_ident(context, "global variable")) return &poisoned_decl;
|
if (!consume_ident(context, "global variable")) return &poisoned_decl;
|
||||||
|
|
||||||
if (try_consume(context, TOKEN_EQ))
|
if (try_consume(context, TOKEN_EQ))
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
|
|||||||
if (param->var.init_expr)
|
if (param->var.init_expr)
|
||||||
{
|
{
|
||||||
Expr *expr = param->var.init_expr;
|
Expr *expr = param->var.init_expr;
|
||||||
if (!sema_analyse_expr(context, param->type, expr)) return false;
|
if (!sema_analyse_expr_of_required_type(context, param->type, expr)) return false;
|
||||||
if (expr->expr_kind != EXPR_CONST)
|
if (expr->expr_kind != EXPR_CONST)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(expr, "Only constant expressions may be used as default values.");
|
SEMA_ERROR(expr, "Only constant expressions may be used as default values.");
|
||||||
@@ -291,7 +291,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We try to convert to the desired type.
|
// We try to convert to the desired type.
|
||||||
if (!sema_analyse_expr(context, type, expr))
|
if (!sema_analyse_expr_of_required_type(context, type, expr))
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
enum_value->resolve_status = RESOLVE_DONE;
|
enum_value->resolve_status = RESOLVE_DONE;
|
||||||
@@ -404,7 +404,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
|
|||||||
if (!sema_resolve_type_info(context, decl->var.type_info)) return false;
|
if (!sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||||
if (decl->var.init_expr)
|
if (decl->var.init_expr)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, decl->type, decl->var.init_expr)) return false;
|
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr)) return false;
|
||||||
if (decl->var.init_expr->expr_kind != EXPR_CONST)
|
if (decl->var.init_expr->expr_kind != EXPR_CONST)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value.");
|
SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value.");
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -109,7 +109,13 @@ static inline bool sema_analyse_block_return_stmt(Context *context, Ast *stateme
|
|||||||
{
|
{
|
||||||
assert(context->current_scope->flags & SCOPE_EXPR_BLOCK);
|
assert(context->current_scope->flags & SCOPE_EXPR_BLOCK);
|
||||||
UPDATE_EXIT(EXIT_RETURN);
|
UPDATE_EXIT(EXIT_RETURN);
|
||||||
if (statement->return_stmt.expr && !sema_analyse_expr(context, context->expected_block_type, statement->return_stmt.expr)) return false;
|
if (statement->return_stmt.expr
|
||||||
|
&& !sema_analyse_expr_of_required_type(context,
|
||||||
|
context->expected_block_type,
|
||||||
|
statement->return_stmt.expr))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
vec_add(context->returns, statement);
|
vec_add(context->returns, statement);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -147,7 +153,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
|
|||||||
SEMA_ERROR(statement, "You can't return a value from a void function, you need to add a return type.");
|
SEMA_ERROR(statement, "You can't return a value from a void function, you need to add a return type.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!sema_analyse_expr(context, expected_rtype, return_expr)) return false;
|
if (!sema_analyse_expr_of_required_type(context, expected_rtype, return_expr)) return false;
|
||||||
if (!expected_rtype)
|
if (!expected_rtype)
|
||||||
{
|
{
|
||||||
assert(context->evaluating_macro);
|
assert(context->evaluating_macro);
|
||||||
@@ -167,7 +173,7 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl)
|
|||||||
decl->type = decl->var.type_info->type;
|
decl->type = decl->var.type_info->type;
|
||||||
if (decl->var.init_expr)
|
if (decl->var.init_expr)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, decl->type, decl->var.init_expr)) return decl_poison(decl);
|
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr)) return decl_poison(decl);
|
||||||
}
|
}
|
||||||
if (!sema_add_local(context, decl)) return decl_poison(decl);
|
if (!sema_add_local(context, decl)) return decl_poison(decl);
|
||||||
return true;
|
return true;
|
||||||
@@ -262,7 +268,7 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
|
|||||||
context_pop_scope(context);
|
context_pop_scope(context);
|
||||||
if (!success) return false;
|
if (!success) return false;
|
||||||
context_push_scope(context);
|
context_push_scope(context);
|
||||||
success = sema_analyse_expr(context, type_bool, expr);
|
success = sema_analyse_expr_of_required_type(context, type_bool, expr);
|
||||||
statement->do_stmt.expr = context_pop_defers_and_wrap_expr(context, expr);
|
statement->do_stmt.expr = context_pop_defers_and_wrap_expr(context, expr);
|
||||||
context_pop_scope(context);
|
context_pop_scope(context);
|
||||||
return success;
|
return success;
|
||||||
@@ -315,7 +321,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
|
|||||||
// Conditional scope start
|
// Conditional scope start
|
||||||
context_push_scope(context);
|
context_push_scope(context);
|
||||||
Expr *cond = statement->for_stmt.cond;
|
Expr *cond = statement->for_stmt.cond;
|
||||||
success = sema_analyse_expr(context, type_bool, cond);
|
success = sema_analyse_expr_of_required_type(context, type_bool, cond);
|
||||||
statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond);
|
statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond);
|
||||||
// Conditional scope end
|
// Conditional scope end
|
||||||
context_pop_scope(context);
|
context_pop_scope(context);
|
||||||
@@ -550,35 +556,22 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st
|
|||||||
Expr *case_expr = case_stmt->case_stmt.expr;
|
Expr *case_expr = case_stmt->case_stmt.expr;
|
||||||
// TODO handle enums
|
// TODO handle enums
|
||||||
// TODO string expr
|
// TODO string expr
|
||||||
if (!sema_analyse_expr(context, to_type, case_expr)) return false;
|
if (!sema_analyse_expr_of_required_type(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// As a special case, we handle bools, converting them to 0 / 1
|
if (!cast_to_runtime(case_expr)) return false;
|
||||||
if (case_expr->const_expr.kind == TYPE_BOOL)
|
|
||||||
{
|
|
||||||
case_stmt->case_stmt.value_type = CASE_VALUE_UINT;
|
|
||||||
case_stmt->case_stmt.val = case_expr->const_expr.b ? 1 : 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO check for int
|
if (case_expr->const_expr.kind == TYPE_BOOL) return true;
|
||||||
/*
|
|
||||||
if (case_expr->const_expr.kind < TYPE__!= CONST_INT && case_expr->const_expr.type != CONST_BOOL)
|
if (!type_is_integer(case_expr->type))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(case_expr, "The 'case' value must be a boolean or integer constant.");
|
SEMA_ERROR(case_expr, "The 'case' value must be a boolean or integer constant.");
|
||||||
return false;
|
return false;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
case_stmt->case_stmt.value_type = type_is_signed(case_expr->type->canonical) ? CASE_VALUE_INT : CASE_VALUE_UINT;
|
|
||||||
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;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,7 +642,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
|
|||||||
for (unsigned j = 0; j < i; j++)
|
for (unsigned j = 0; j < i; j++)
|
||||||
{
|
{
|
||||||
Ast *other = statement->switch_stmt.cases[j];
|
Ast *other = statement->switch_stmt.cases[j];
|
||||||
if (other->ast_kind == AST_CASE_STMT && other->case_stmt.val == stmt->case_stmt.val)
|
if (other->ast_kind == AST_CASE_STMT && expr_const_compare(&other->case_stmt.expr->const_expr, &stmt->case_stmt.expr->const_expr, BINARYOP_EQ))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(stmt, "The same case value appears more than once.");
|
SEMA_ERROR(stmt, "The same case value appears more than once.");
|
||||||
SEMA_PREV(other, "Here is the previous use of that value.");
|
SEMA_PREV(other, "Here is the previous use of that value.");
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type)
|
|||||||
uint64_t len = 0;
|
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_of_required_type(context, type_usize, type->array.len)) return type_info_poison(type);
|
||||||
if (type->array.len->expr_kind != EXPR_CONST)
|
if (type->array.len->expr_kind != EXPR_CONST)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
|
SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
|
||||||
|
|||||||
@@ -316,26 +316,6 @@ const char *token_type_to_string(TokenType type)
|
|||||||
case TOKEN_DOCS_LINE:
|
case TOKEN_DOCS_LINE:
|
||||||
return "DOCS_LINE";
|
return "DOCS_LINE";
|
||||||
|
|
||||||
|
|
||||||
case TOKEN_AT_CONST:
|
|
||||||
return "@const";
|
|
||||||
case TOKEN_AT_DEPRECATED:
|
|
||||||
return "@deprecated";
|
|
||||||
case TOKEN_AT_ENSURE:
|
|
||||||
return "@ensure";
|
|
||||||
case TOKEN_AT_PARAM:
|
|
||||||
return "@param";
|
|
||||||
case TOKEN_AT_PURE:
|
|
||||||
return "@pure";
|
|
||||||
case TOKEN_AT_RETURN:
|
|
||||||
return "@return";
|
|
||||||
case TOKEN_AT_REQUIRE:
|
|
||||||
return "@require";
|
|
||||||
case TOKEN_AT_THROWS:
|
|
||||||
return "@throws";
|
|
||||||
case TOKEN_AT_REQPARSE:
|
|
||||||
return "@reqparse";
|
|
||||||
|
|
||||||
case TOKEN_CT_CASE:
|
case TOKEN_CT_CASE:
|
||||||
return "$case";
|
return "$case";
|
||||||
case TOKEN_CT_DEFAULT:
|
case TOKEN_CT_DEFAULT:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Type *type_bool, *type_void, *type_string, *type_voidptr;
|
|||||||
Type *type_float, *type_double;
|
Type *type_float, *type_double;
|
||||||
Type *type_char, *type_short, *type_int, *type_long, *type_isize;
|
Type *type_char, *type_short, *type_int, *type_long, *type_isize;
|
||||||
Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
||||||
Type *type_compint, *type_compuint, *type_compfloat;
|
Type *type_compint, *type_compfloat;
|
||||||
Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
|
Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
|
||||||
Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
|
Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
|
||||||
|
|
||||||
@@ -196,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:
|
||||||
return 4;
|
return 8;
|
||||||
case TYPE_FXX:
|
case TYPE_FXX:
|
||||||
return 8;
|
return 8;
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ static void test_lexer(void)
|
|||||||
printf("Begin lexer testing.\n");
|
printf("Begin lexer testing.\n");
|
||||||
printf("-- Check number of keywords...\n");
|
printf("-- Check number of keywords...\n");
|
||||||
int tokens_found = 0;
|
int tokens_found = 0;
|
||||||
const int EXPECTED_TOKENS = 12 + 73 + 9;
|
const int EXPECTED_TOKENS = TOKEN_CT_SWITCH - TOKEN_ALIAS + 1 + TOKEN_C_ULONGLONG - TOKEN_VOID + 1;
|
||||||
const char* tokens[TOKEN_EOF];
|
const char* tokens[TOKEN_EOF];
|
||||||
int len[TOKEN_EOF];
|
int len[TOKEN_EOF];
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
@@ -26,7 +26,7 @@ static void test_lexer(void)
|
|||||||
{
|
{
|
||||||
const char* token = token_type_to_string((TokenType)i);
|
const char* token = token_type_to_string((TokenType)i);
|
||||||
tokens[i] = token;
|
tokens[i] = token;
|
||||||
len[i] = strlen(token);
|
len[i] = (int)strlen(token);
|
||||||
TokenType lookup = TOKEN_IDENT;
|
TokenType lookup = TOKEN_IDENT;
|
||||||
const char* interned = symtab_add(token, len[i], fnv1a(token, len[i]), &lookup);
|
const char* interned = symtab_add(token, len[i], fnv1a(token, len[i]), &lookup);
|
||||||
if (lookup != TOKEN_IDENT)
|
if (lookup != TOKEN_IDENT)
|
||||||
@@ -48,7 +48,7 @@ static void test_lexer(void)
|
|||||||
printf("-> %d keywords found.\n", tokens_found);
|
printf("-> %d keywords found.\n", tokens_found);
|
||||||
EXPECT("Keywords", tokens_found, EXPECTED_TOKENS);
|
EXPECT("Keywords", tokens_found, EXPECTED_TOKENS);
|
||||||
|
|
||||||
const int BENCH_REPEATS = 100000;
|
const int BENCH_REPEATS = 10000;
|
||||||
|
|
||||||
printf("-- Test keyword lexing speed...\n");
|
printf("-- Test keyword lexing speed...\n");
|
||||||
bench_begin();
|
bench_begin();
|
||||||
@@ -56,7 +56,10 @@ static void test_lexer(void)
|
|||||||
{
|
{
|
||||||
for (int i = 1; i < TOKEN_EOF; i++)
|
for (int i = 1; i < TOKEN_EOF; i++)
|
||||||
{
|
{
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||||
volatile TokenType t = lexer_scan_ident_test(&lexer, tokens[i]).type;
|
volatile TokenType t = lexer_scan_ident_test(&lexer, tokens[i]).type;
|
||||||
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +98,27 @@ static void test_lexer(void)
|
|||||||
|
|
||||||
void test_compiler(void)
|
void test_compiler(void)
|
||||||
{
|
{
|
||||||
compiler_init();
|
const char **files = NULL;
|
||||||
|
file_add_wildcard_files(&files, "tests", true);
|
||||||
|
if (!vec_size(files))
|
||||||
|
{
|
||||||
|
error_exit("No test files could be found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char **single_file = VECNEW(const char *, 1);
|
||||||
|
vec_add(single_file, files[0]);
|
||||||
|
|
||||||
|
VECEACH(files, i)
|
||||||
|
{
|
||||||
|
printf("Running %s...\n", files[i]);
|
||||||
|
char *res = NULL;
|
||||||
|
asprintf(&res, "tests/%s", files[i]);
|
||||||
|
single_file[0] = res;
|
||||||
|
BuildTarget target = { .type = TARGET_TYPE_EXECUTABLE, .sources = single_file, .name = "a.out" };
|
||||||
|
compile_files(&target);
|
||||||
|
free(res);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_file(void)
|
void test_file(void)
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ int main(int argc, const char *argv[])
|
|||||||
// First setup memory
|
// First setup memory
|
||||||
memory_init();
|
memory_init();
|
||||||
|
|
||||||
|
// Init the compiler
|
||||||
|
compiler_init();
|
||||||
|
|
||||||
// Parse arguments.
|
// Parse arguments.
|
||||||
parse_arguments(argc, argv);
|
parse_arguments(argc, argv);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user