Merge pull request #20 from c3lang/develop

Some work towards automated testing. Fixes to bigint. Removed implici…
This commit is contained in:
Christoffer Lerno
2020-04-02 23:15:11 +02:00
committed by GitHub
25 changed files with 897 additions and 608 deletions

View File

@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.13)
project(c3c)
#set(CMAKE_BUILD_TYPE Release)
#set(CMAKE_CXX_FLAGS_RELEASE "-O3")
find_package(LLVM REQUIRED CONFIG)

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

View File

@@ -423,6 +423,21 @@ func int xxxx(int x)
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)
{
int efd = 9;
@@ -447,9 +462,12 @@ func int main(int x)
}
}
next;
case 1000 >> 2:
printf("case 1000 >> 2\n");
case (1 << 200) >> 197:
printf("case 1 << 3\n");
default:
printf("default\n");
break;
}
int aa = x++;
int bb = x--;
@@ -489,12 +507,12 @@ func int main(int x)
if (ef == 4) printf("Works5!\n");
if (ef == 4) printf("Works1!\n");
ef = 0;
/*
byte a = 2;
short b = 3;
int c = 4;
bool eok = true;
long deee = (eok ? a : b) + (eok ? b : c);*/
long deee = (eok ? a : b) + (eok ? b : c);
int i = 0;
JUMP:

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

View File

@@ -114,6 +114,7 @@ typedef enum
TARGET_TYPE_EXECUTABLE,
TARGET_TYPE_STATIC_LIB,
TARGET_TYPE_DYNAMIC_LIB,
TARGET_TYPE_TEST
} TargetType;
typedef struct

View File

@@ -236,8 +236,6 @@ static BinaryOp assign_binop[BINARYOP_LAST + 1] = {
[BINARYOP_SUB_MOD_ASSIGN] = BINARYOP_SUB_MOD,
[BINARYOP_DIV_ASSIGN] = BINARYOP_DIV,
[BINARYOP_MOD_ASSIGN] = BINARYOP_MOD,
[BINARYOP_AND_ASSIGN] = BINARYOP_AND,
[BINARYOP_OR_ASSIGN] = BINARYOP_OR,
[BINARYOP_BIT_AND_ASSIGN] = BINARYOP_BIT_AND,
[BINARYOP_BIT_OR_ASSIGN] = BINARYOP_BIT_OR,
[BINARYOP_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR,

View File

@@ -61,7 +61,7 @@ static char digit_to_char(uint8_t digit, bool upper)
}
if (digit <= 35)
{
return (char) (digit + (upper ? 'A' : 'a'));
return (char) (digit + (upper ? 'A' : 'a') - 10);
}
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);
return;
}
if (op1->digit_count == 0)
{
bigint_init_unsigned(dest, 0);
return;
}
const uint64_t *op1_digits = bigint_ptr(op1);
if (op1->digit_count == 1 && shift < 64)
{
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);
unsigned leftover_shift_count = (unsigned int) (shift % 64);
uint64_t digit_shift_count = shift / 64;
uint64_t leftover_shift_count = shift % 64;
dest->digits = alloc_digits(op1->digit_count + digit_shift_count + 1);
dest->digit_count = digit_shift_count;
uint64_t carry = 0;
for (size_t i = 0; i < op1->digit_count; i += 1)
{
uint64_t
digit = op1_digits[i];
uint64_t digit = op1_digits[i];
dest->digits[dest->digit_count] = carry | (digit << leftover_shift_count);
dest->digit_count += 1;
dest->digit_count++;
if (leftover_shift_count > 0)
{
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)
{
dest->digit = op1_digits[0] >> shift_amt;
dest->digit = shift_amt < 64 ? op1_digits[0] >> shift_amt : 0;
dest->digit_count = 1;
dest->is_negative = op1->is_negative;
normalize(dest);
return;
}
unsigned digit_shift_count = (unsigned int) (shift_amt / 64);
unsigned leftover_shift_count = (unsigned int) (shift_amt % 64);
uint64_t digit_shift_count = shift_amt / 64;
uint64_t leftover_shift_count = shift_amt % 64;
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->digits = alloc_digits(dest->digit_count);
uint64_t
carry = 0;
uint64_t *digits;
if (dest->digit_count == 1)
{
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;;)
{
uint64_t
digit = op1_digits[op_digit_index];
uint64_t digit = op1_digits[op_digit_index];
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);
if (dest_digit_index == 0)
{ break; }
if (dest_digit_index == 0) break;
op_digit_index -= 1;
}
dest->is_negative = op1->is_negative;
@@ -1851,7 +1860,7 @@ void bigint_print(BigInt *bigint, uint64_t base)
bigint_init_bigint(a, bigint);
BigInt base_bi = { 0 };
bigint_init_unsigned(&base_bi, 10);
bigint_init_unsigned(&base_bi, base);
for (;;)
{
@@ -1903,7 +1912,7 @@ const char *bigint_to_error_string(const BigInt *bigint, uint64_t base)
bigint_init_bigint(a, bigint);
BigInt base_bi = { 0 };
bigint_init_unsigned(&base_bi, 10);
bigint_init_unsigned(&base_bi, base);
for (;;)
{
@@ -1934,7 +1943,7 @@ const char *bigint_to_error_string(const BigInt *bigint, uint64_t base)
*(current++) = *ptr;
}
*(current++) = '\0';
return current;
return out;
}
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 base_bi = { 0 };
bigint_init_unsigned(&base_bi, 10);
bigint_init_unsigned(&base_bi, base);
for (;;)
{

View File

@@ -7,7 +7,7 @@
#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)
#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)
{
@@ -34,11 +34,8 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type)
case CAST_TYPE_IMPLICIT:
action = "implicitly cast";
break;
case CAST_TYPE_IMPLICIT_ASSIGN:
case CAST_TYPE_IMPLICIT_ASSIGN_ADD:
action = "assign";
break;
case CAST_TYPE_OPTIONAL_IMPLICIT:
UNREACHABLE
}
SEMA_ERROR(expr, "Cannot %s '%s' to '%s'.", action, type_to_error_string(expr->type), type_to_error_string(type));
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)
{
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);
assert(left->const_expr.kind == TYPE_POINTER);
@@ -62,9 +63,9 @@ bool ptxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
return true;
}
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);
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)
{
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);
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)
{
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);
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)
{
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);
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;
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);
@@ -287,8 +288,9 @@ bool ixxxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
{
bool is_signed = canonical->type_kind < TYPE_U8;
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);
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;
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);
@@ -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;
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);
@@ -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;
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);
@@ -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)
{
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);
@@ -455,17 +469,20 @@ bool uius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
* Cast comptime, signed or unsigned -> pointer.
* @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 (bigint_cmp_zero(&left->const_expr.i) != CMP_EQ)
if (cast_type == CAST_TYPE_EXPLICIT && left->expr_kind == EXPR_CONST)
{
SEMA_ERROR(left, "Only constants evaluating to zero can be cast to pointers.");
return false;
RETURN_NON_CONST_CAST(CAST_XIPTR);
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);
left->type = type;
return true;
return cast(left, type_is_unsigned(from) ? type_usize : type_isize, 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)
{
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_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);
if (canonical->type_kind == TYPE_POINTER) return xipt(expr, from_type, canonical, to_type, cast_type);
break;
case TYPE_I8:
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_float(canonical)) return sifp(expr, canonical, to_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;
case TYPE_U8:
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_float(canonical)) return uifp(expr, canonical, to_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;
case TYPE_F32:
case TYPE_F64:

View File

@@ -582,16 +582,7 @@ typedef struct
typedef struct
{
union
{
Expr *expr;
struct
{
uint64_t val;
CaseValueType value_type : 3;
bool has_next;
};
};
Expr *expr; // NULL == DEFAULT
Ast *body;
void *backend_value;
} 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);
CastKind cast_to_bool_kind(Type *type);
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 cast_to_smallest_runtime(Expr *expr);
void llvm_codegen(Context *context);
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_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;
}
static inline bool type_is_number(Type *type)
static inline bool type_is_numeric(Type *type)
{
assert(type == type->canonical);
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_FXX;

View File

@@ -14,11 +14,6 @@ void diag_reset(void)
diagnostics.warnings = 0;
}
void reset_panic_mode(void)
{
diagnostics.panic_mode = false;
}
typedef enum
{
PRINT_TYPE_ERROR,

View File

@@ -57,8 +57,6 @@ typedef enum
BINARYOP_SUB_MOD_ASSIGN,
BINARYOP_DIV_ASSIGN,
BINARYOP_MOD_ASSIGN,
BINARYOP_AND_ASSIGN,
BINARYOP_OR_ASSIGN,
BINARYOP_BIT_AND_ASSIGN,
BINARYOP_BIT_OR_ASSIGN,
BINARYOP_BIT_XOR_ASSIGN,
@@ -113,12 +111,6 @@ typedef enum
ATTR_UNRESOLVED,
} AttrKind;
typedef enum
{
CASE_VALUE_INT,
CASE_VALUE_UINT,
CASE_VALUE_DEFAULT
} CaseValueType;
typedef enum
{
@@ -175,8 +167,7 @@ typedef enum _CastType
{
CAST_TYPE_EXPLICIT,
CAST_TYPE_IMPLICIT,
CAST_TYPE_IMPLICIT_ASSIGN,
CAST_TYPE_IMPLICIT_ASSIGN_ADD,
CAST_TYPE_OPTIONAL_IMPLICIT,
} CastType;
@@ -355,7 +346,7 @@ typedef enum
TOKEN_RPARBRA, // })
TOKEN_SCOPE, // ::
TOKEN_SHR, // >>
TOKEN_SHL, // >>
TOKEN_SHL, // <<
// Three or more
TOKEN_ELIPSIS, // ...
@@ -459,16 +450,6 @@ typedef enum
TOKEN_VOLATILE,
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_DEFAULT, // $default
TOKEN_CT_FOR, // $for

View File

@@ -519,7 +519,7 @@ Token lexer_scan_token(Lexer *lexer)
if (match(lexer, '+')) return parse_nested_comment(lexer);
return match(lexer, '=') ? make_token(lexer, TOKEN_DIV_ASSIGN, "/=") : make_token(lexer, TOKEN_DIV, "/");
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, "*");
case '=':
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->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);
}

View File

@@ -551,8 +551,6 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, LLVM
case BINARYOP_SUB_MOD_ASSIGN:
case BINARYOP_DIV_ASSIGN:
case BINARYOP_MOD_ASSIGN:
case BINARYOP_AND_ASSIGN:
case BINARYOP_OR_ASSIGN:
case BINARYOP_BIT_AND_ASSIGN:
case BINARYOP_BIT_OR_ASSIGN:
case BINARYOP_BIT_XOR_ASSIGN:

View File

@@ -426,7 +426,6 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
// TODO check defer correctness
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);
size_t cases = vec_size(ast->switch_stmt.cases);
if (!cases)
{
@@ -438,7 +437,7 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
VECEACH(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)
{
@@ -494,7 +493,7 @@ void gencontext_emit_switch(GenContext *context, Ast *ast)
LLVMBasicBlockRef block = case_stmt->case_stmt.backend_value;
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);
}

View File

@@ -162,6 +162,7 @@ static Expr *parse_unary_expr(Context *context, Expr *left)
CHECK_EXPR(right_side);
unary->unary_expr.expr = right_side;
unary->span.end_loc = right_side->span.end_loc;
return unary;
}

View File

@@ -197,7 +197,7 @@ static inline Ast *parse_default_stmt(Context *context)
TRY_CONSUME_OR(TOKEN_COLON, "Expected ':' after 'default'.", &poisoned_ast);
extend_ast_with_prev_token(context, ast);
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;
}
@@ -796,15 +796,6 @@ Ast *parse_stmt(Context *context)
case TOKEN_UNTIL:
case TOKEN_ATTRIBUTE:
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_END:
case TOKEN_DOCS_EOL:

View File

@@ -514,6 +514,7 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type)
SEMA_TOKEN_ERROR(context->tok, "Expected '{'.");
return &poisoned_decl;
}
EXPECT_IDENT_FOR_OR("variable_name", &poisoned_decl);
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);
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 (try_consume(context, TOKEN_EQ))

View File

@@ -121,7 +121,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo
if (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)
{
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.
if (!sema_analyse_expr(context, type, expr))
if (!sema_analyse_expr_of_required_type(context, type, expr))
{
success = false;
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 (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)
{
SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value.");

File diff suppressed because it is too large Load Diff

View File

@@ -109,7 +109,13 @@ static inline bool sema_analyse_block_return_stmt(Context *context, Ast *stateme
{
assert(context->current_scope->flags & SCOPE_EXPR_BLOCK);
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);
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.");
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)
{
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;
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);
return true;
@@ -262,7 +268,7 @@ static inline bool sema_analyse_do_stmt(Context *context, Ast *statement)
context_pop_scope(context);
if (!success) return false;
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);
context_pop_scope(context);
return success;
@@ -315,7 +321,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
// Conditional scope start
context_push_scope(context);
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);
// Conditional scope end
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;
// TODO handle enums
// 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)
{
SEMA_ERROR(case_expr, "This must be a constant expression.");
return false;
}
// As a special case, we handle bools, converting them to 0 / 1
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;
}
if (!cast_to_runtime(case_expr)) return false;
// TODO check for int
/*
if (case_expr->const_expr.kind < TYPE__!= CONST_INT && case_expr->const_expr.type != CONST_BOOL)
if (case_expr->const_expr.kind == TYPE_BOOL) return true;
if (!type_is_integer(case_expr->type))
{
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;
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;
}
@@ -649,7 +642,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
for (unsigned j = 0; j < i; 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_PREV(other, "Here is the previous use of that value.");

View File

@@ -28,7 +28,7 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type)
uint64_t len = 0;
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)
{
SEMA_ERROR(type->array.len, "Expected a constant value as array size.");

View File

@@ -316,26 +316,6 @@ const char *token_type_to_string(TokenType type)
case TOKEN_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:
return "$case";
case TOKEN_CT_DEFAULT:

View File

@@ -8,7 +8,7 @@ Type *type_bool, *type_void, *type_string, *type_voidptr;
Type *type_float, *type_double;
Type *type_char, *type_short, *type_int, *type_long, *type_isize;
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_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
@@ -196,7 +196,7 @@ size_t type_size(Type *canonical)
case TYPE_F64:
return canonical->builtin.bytesize;
case TYPE_IXX:
return 4;
return 8;
case TYPE_FXX:
return 8;
case TYPE_FUNC:

View File

@@ -18,7 +18,7 @@ static void test_lexer(void)
printf("Begin lexer testing.\n");
printf("-- Check number of keywords...\n");
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];
int len[TOKEN_EOF];
Lexer lexer;
@@ -26,7 +26,7 @@ static void test_lexer(void)
{
const char* token = token_type_to_string((TokenType)i);
tokens[i] = token;
len[i] = strlen(token);
len[i] = (int)strlen(token);
TokenType lookup = TOKEN_IDENT;
const char* interned = symtab_add(token, len[i], fnv1a(token, len[i]), &lookup);
if (lookup != TOKEN_IDENT)
@@ -48,7 +48,7 @@ static void test_lexer(void)
printf("-> %d keywords found.\n", tokens_found);
EXPECT("Keywords", tokens_found, EXPECTED_TOKENS);
const int BENCH_REPEATS = 100000;
const int BENCH_REPEATS = 10000;
printf("-- Test keyword lexing speed...\n");
bench_begin();
@@ -56,7 +56,10 @@ static void test_lexer(void)
{
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;
#pragma clang diagnostic pop
}
}
@@ -95,7 +98,27 @@ static void test_lexer(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)

View File

@@ -10,6 +10,9 @@ int main(int argc, const char *argv[])
// First setup memory
memory_init();
// Init the compiler
compiler_init();
// Parse arguments.
parse_arguments(argc, argv);