diff --git a/resources/testfragments/compiletest.c3 b/resources/testfragments/compiletest.c3 index 71e3ee439..bb6130e95 100644 --- a/resources/testfragments/compiletest.c3 +++ b/resources/testfragments/compiletest.c3 @@ -1,5 +1,8 @@ module foo; +int oefk = 1; +int bob = 'HELO'; + struct Foo { int i; @@ -10,8 +13,19 @@ struct Bar { Foo foo; Foo* fooPtr; + struct bar + { + int a; + } } +union Xyz +{ + int x; + int y; +} + + $if (1) { struct Ogg @@ -29,13 +43,31 @@ $if (1) } + func int boo() { Zed zfe; + //zfe = { 1, 2 }; + //Zed zfed = { 1 }; int eok = 0; { eok = 2; } + eok = eok * 2 + 1 * 2; + eok = eok / 2 + 32 / 2; + eok = eok % 2 - 32 % 45; + + int de = eok; + de++; + de = de << 1; + de = de >> 1; + de = de ^ cast(byte, 1); + de = de & 1; + de = de | 1; + if (de > 100 || de < 10 || de <= 1000 || de >= 1921 || de == 100 || de != 2) + { + return boo(); + } switch (eok) { case 1: diff --git a/src/compiler/codegen.c b/src/compiler/codegen.c index eaf1506b4..7b242efcf 100644 --- a/src/compiler/codegen.c +++ b/src/compiler/codegen.c @@ -140,12 +140,10 @@ static inline int codegen_emit_identifier_expr(Context *context, Expr *expr, int return context->unique_index; } - -static inline int codegen_emit_const_expr(Context *context, Expr *expr, int indent) +static inline void codegen_emit_const_expr_raw(Context *context, Expr *expr) { assert(expr->expr_kind == EXPR_CONST); Type *canonical = expr->type->canonical; - INDENT(); switch (canonical->type_kind) { case TYPE_POISONED: @@ -155,50 +153,44 @@ static inline int codegen_emit_const_expr(Context *context, Expr *expr, int inde break; case TYPE_BOOL: assert(expr->const_expr.type == CONST_BOOL); - PRINTTYPE(expr->type); - PRINTF(" _%d = %s;\n", ++context->unique_index, expr->const_expr.b ? "true" : "false"); - return context->unique_index; + PRINTF(expr->const_expr.b ? "true" : "false"); + return; case TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_IXX: assert(expr->const_expr.type == CONST_INT); - PRINTTYPE(expr->type); - PRINTF(" _%d = (", ++context->unique_index); + PRINTF("("); PRINTTYPE(canonical); PRINTF(")"); - PRINTF("%lld;\n", (long long)expr->const_expr.i); - return context->unique_index; + PRINTF("%lld", (long long)expr->const_expr.i); + return; case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_UXX: assert(expr->const_expr.type == CONST_INT); - PRINTTYPE(expr->type); - PRINTF(" _%d = (", ++context->unique_index); + PRINTF("("); PRINTTYPE(canonical); PRINTF(")"); - PRINTF("%llu;\n", expr->const_expr.i); - return context->unique_index; + PRINTF("%llu", (long long)expr->const_expr.i); + return; case TYPE_F32: case TYPE_F64: case TYPE_FXX: - assert(expr->const_expr.type == CONST_FLOAT); - PRINTTYPE(expr->type); - PRINTF(" _%d = (", ++context->unique_index); + assert(expr->const_expr.type == CONST_INT); + PRINTF("("); PRINTTYPE(canonical); PRINTF(")"); - PRINTF("%Lf;\n", expr->const_expr.f); - return context->unique_index; + PRINTF("%Lf", expr->const_expr.f); + return; case TYPE_POINTER: - assert(expr->const_expr.type == CONST_NIL); - PRINTTYPE(expr->type); - PRINTF(" _%d = ((", ++context->unique_index); + PRINTF("(("); PRINTTYPE(canonical); - PRINTF("0);\n"); - return context->unique_index; + PRINTF("0)"); + return; case TYPE_STRING: TODO case TYPE_ARRAY: @@ -209,6 +201,17 @@ static inline int codegen_emit_const_expr(Context *context, Expr *expr, int inde } } +static inline int codegen_emit_const_expr(Context *context, Expr *expr, int indent) +{ + assert(expr->expr_kind == EXPR_CONST); + INDENT(); + PRINTTYPE(expr->type); + PRINTF(" _%d = ", ++context->unique_index); + codegen_emit_const_expr_raw(context, expr); + PRINTF(";\n"); + return context->unique_index; +} + static inline int codegen_emit_cast_expr(Context *context, Expr *expr, int indent) { int index = codegen_emit_expr(context, expr->expr_cast.expr, indent); @@ -263,14 +266,15 @@ static int codegen_emit_binary_expr(Context *context, Expr *expr, int indent) case TOKEN_NOT_EQUAL: case TOKEN_MOD: case TOKEN_DIV: + case TOKEN_AND: + case TOKEN_OR: case TOKEN_STAR: - return codegen_emit_simple_binary_expr(context, expr, indent); case TOKEN_BIT_OR: case TOKEN_AMP: case TOKEN_BIT_XOR: case TOKEN_SHL: case TOKEN_SHR: - TODO + return codegen_emit_simple_binary_expr(context, expr, indent); case TOKEN_MULT_ASSIGN: case TOKEN_DIV_ASSIGN: case TOKEN_MINUS_ASSIGN: @@ -830,7 +834,16 @@ static inline void codegen_top_level_decl_header(Context *context, Decl *decl) codegen_top_level_func(context, decl); return; case DECL_VAR: - break; + if (decl->visibility != VISIBLE_PUBLIC) PRINTF("static "); + PRINTTYPE(decl->var.type); + PRINTF(" %s", decl->name.string); + if (decl->var.init_expr) + { + PRINTF(" = "); + codegen_emit_const_expr_raw(context, decl->var.init_expr); + } + PRINTF(";\n"); + return; case DECL_TYPEDEF: TODO case DECL_STRUCT: @@ -873,7 +886,7 @@ static inline void codegen_top_level_decl(Context *context, Decl *decl) codegen_func(context, decl); return; case DECL_VAR: - break; + return; case DECL_ENUM_CONSTANT: break; case DECL_TYPEDEF: diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index f77f5bc51..6a3560685 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -55,6 +55,7 @@ void compiler_compile() diag_reset(); parse_file(file); sema_analysis(current_context); + if (diagnostics.errors > 0) exit(EXIT_FAILURE); FILE *f = fopen("test.c","w"); fprintf(f, "#include \n#include \n"); current_context->codegen_output = f; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index c5b1e6972..a83af23ea 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -600,6 +600,7 @@ typedef struct _Context Decl **vars; Decl **ct_ifs; Decl *active_function_for_analysis; + Type *left_type_in_assignment; FILE *codegen_output; Decl **last_local; Ast **labels; @@ -620,6 +621,7 @@ extern Decl poisoned_decl; extern Expr poisoned_expr; extern Type poisoned_type; extern Module poisoned_module; +extern Diagnostics diagnostics; extern Token next_tok; extern Token tok; @@ -726,7 +728,8 @@ Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility); Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility); Decl *decl_new_var(Token name, Type *type, VarDeclKind kind, Visibility visibility); static inline bool decl_ok(Decl *decl) { return decl->decl_kind != DECL_POISONED; } -static inline Decl *decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return decl; } +static inline bool decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return false; } +static inline bool decl_is_struct_type(Decl *decl) { return decl->decl_kind == DECL_UNION || decl->decl_kind == DECL_STRUCT; } static inline DeclKind decl_from_token(TokenType type) { if (type == TOKEN_STRUCT) return DECL_STRUCT; diff --git a/src/compiler/expr_analysis.c b/src/compiler/expr_analysis.c index fd2ab375f..9dd47f117 100644 --- a/src/compiler/expr_analysis.c +++ b/src/compiler/expr_analysis.c @@ -144,17 +144,37 @@ static inline bool sema_expr_analyse_method_ref(Context *context, Expr *expr) TODO } - -static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *expr) +static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Expr *expr) { TODO } +static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *expr) +{ + assert(context->left_type_in_assignment); + Type *assigned = context->left_type_in_assignment->canonical; + assert(assigned); + switch (assigned->type_kind) + { + case TYPE_USER_DEFINED: + if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer_list(context, expr); + break; + case TYPE_ARRAY: + TODO + case TYPE_VARARRAY: + TODO + default: + break; + } + SEMA_ERROR(expr->loc, "Cannot assign expression to '%s'.", type_to_error_string(context->left_type_in_assignment)); + return false; +} static inline bool sema_expr_analyse_sizeof(Context *context, Expr *expr) { TODO } + static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) { Expr *inner = expr->expr_cast.expr; @@ -174,8 +194,25 @@ static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, Expr *right) { + if (!sema_analyse_expr(context, left)) return false; + + if (!expr_is_ltype(left)) + { + SEMA_ERROR(left->loc, "Expression is not assignable."); + return false; + } + + Type *prev_type = context->left_type_in_assignment; + context->left_type_in_assignment = left->type; + + bool success = sema_analyse_expr(context, right); + + context->left_type_in_assignment = prev_type; + + if (!success) return false; + if (!cast(right, left->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; - // Check assignable + return true; } @@ -184,6 +221,14 @@ static inline bool both_const(Expr *left, Expr *right) return left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST; } +static bool sema_expr_analyse_bit_and_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_bit_or_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_bit_xor_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_div_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_add_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_sub_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_mult_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } + static bool sema_expr_analyse_add(Context *context, Expr *expr, Expr *left, Expr *right) { Type *left_type = left->type->canonical; @@ -228,14 +273,115 @@ static bool sema_expr_analyse_add(Context *context, Expr *expr, Expr *left, Expr expr->type = left->type; return true; } -static bool sema_expr_analyse_add_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_sub(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_sub_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_mult(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_mult_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_sub(Context *context, Expr *expr, Expr *left, Expr *right) +{ + Type *left_type = left->type->canonical; + Type *right_type = right->type->canonical; + if (left_type->type_kind == TYPE_POINTER) + { + if (right_type->type_kind == TYPE_POINTER) + { + if (!cast(right, left_type, CAST_TYPE_IMPLICIT)) return false; + expr->type = type_isize; + return true; + } + if (!cast_arithmetic(right, left, "-")) return false; + expr->type = left->type; + return true; + } + if (!cast_arithmetic(left, right, "-")) return false; + if (!cast_arithmetic(right, left, "-")) return false; + + Type *canonical = left->type->canonical; + if (!type_is_number(canonical)) + { + SEMA_ERROR(expr->loc, "- is not allowed"); + return false; + } + if (both_const(left, right)) + { + switch (left->const_expr.type) + { + case CONST_INT: + expr->const_expr.i = left->const_expr.i - right->const_expr.i; + break; + case CONST_FLOAT: + expr->const_expr.f = left->const_expr.f - right->const_expr.f; + break; + default: + UNREACHABLE + } + expr->expr_kind = EXPR_CONST; + expr->const_expr.type = left->const_expr.type; + } + expr->type = left->type; + return true; +} + +static bool sema_expr_analyse_mult(Context *context, Expr *expr, Expr *left, Expr *right) +{ + if (!cast_arithmetic(left, right, "*")) return false; + if (!cast_arithmetic(right, left, "*")) return false; + + Type *canonical = left->type->canonical; + if (!type_is_number(canonical)) + { + SEMA_ERROR(expr->loc, "* is not allowed"); + return false; + } + if (both_const(left, right)) + { + switch (left->const_expr.type) + { + case CONST_INT: + expr->const_expr.i = left->const_expr.i * right->const_expr.i; + break; + case CONST_FLOAT: + expr->const_expr.f = left->const_expr.f * right->const_expr.f; + break; + default: + UNREACHABLE + } + expr->expr_kind = EXPR_CONST; + expr->const_expr.type = left->const_expr.type; + } + expr->type = left->type; + return true; +} + static bool sema_expr_analyse_div(Context *context, Expr *expr, Expr *left, Expr *right) { + if (!cast_arithmetic(left, right, "/")) return false; + if (!cast_arithmetic(right, left, "/")) return false; + + Type *canonical = left->type->canonical; + if (!type_is_number(canonical)) + { + SEMA_ERROR(expr->loc, "/ is not allowed"); + return false; + } + if (both_const(left, right)) + { + switch (left->const_expr.type) + { + case CONST_INT: + expr->const_expr.i = left->const_expr.i / right->const_expr.i; + break; + case CONST_FLOAT: + expr->const_expr.f = left->const_expr.f / right->const_expr.f; + break; + default: + UNREACHABLE + } + expr->expr_kind = EXPR_CONST; + expr->const_expr.type = left->const_expr.type; + } + expr->type = left->type; + return true; +} + + /* switch (left->type) { @@ -261,51 +407,136 @@ static bool sema_expr_analyse_div(Context *context, Expr *expr, Expr *left, Expr expr->const_expr.type = CONST_FLOAT; break; }*/ - return false; -} -static bool sema_expr_analyse_div_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } static bool sema_expr_analyse_mod(Context *context, Expr *expr, Expr *left, Expr *right) { - if (!cast_arithmetic(left, right, "%")) return false; + if (!cast_arithmetic(left, right, "%") || !cast_arithmetic(right, left, "%")) return false; 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) + if (right->expr_kind == EXPR_CONST && right->const_expr.i == 0) { - if (right->const_expr.i == 0) - { - SEMA_ERROR(expr->binary_expr.right->loc, "Cannot perform mod by zero."); - return false; - } - if (left->expr_kind == EXPR_CONST) - { - // TODO negative - expr->const_expr.i = left->const_expr.i / right->const_expr.i; - expr->type = right->type; - expr->expr_kind = EXPR_CONST; - expr->const_expr.type = CONST_INT; - } + SEMA_ERROR(expr->binary_expr.right->loc, "Cannot perform mod by zero."); + return false; } + if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST) + { + // TODO negative + expr_replace(expr, left); + expr->const_expr.i %= right->const_expr.i; + return true; + } + + expr->type = left->type; return true; } static bool sema_expr_analyse_mod_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_and(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_and_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_or(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_or_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_xor(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_bit_xor_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +#define SEMA_ANALYSE_BIT(op) \ +{ if (!cast_arithmetic(left, right, #op) || !cast_arithmetic(right, left, #op)) return false; \ +if (left->type->canonical->type_kind != TYPE_BOOL && !type_is_integer(left->type)) sema_type_error_on_binop(#op, expr); \ +if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST)\ +{ expr_replace(expr, left); \ +if (left->const_expr.type == CONST_BOOL) \ +{ expr->const_expr.b |= right->const_expr.b; } \ +else { expr->const_expr.i |= expr->const_expr.i; } \ +return true; } \ +expr->type = left->type; \ +return true; } + +static bool sema_expr_analyse_bit_or(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_BIT(|) +static bool sema_expr_analyse_bit_xor(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_BIT(^) +static bool sema_expr_analyse_bit_and(Context *context, Expr *expr, Expr *left, Expr *right) SEMA_ANALYSE_BIT(&) + static bool sema_expr_analyse_shr(Context *context, Expr *expr, Expr *left, Expr *right) -{ TODO } +{ + // Todo: proper handling of signed / unsigned. Proper reduction of constants. + if (!type_is_integer(left->type) || !type_is_integer(right->type)) return sema_type_error_on_binop(">>", expr); + if (type_is_signed(right->type->canonical)) + { + cast(right, type_long, CAST_TYPE_IMPLICIT); + } + else + { + cast(left, type_ulong, CAST_TYPE_IMPLICIT); + } + if (right->expr_kind == EXPR_CONST) + { + if (right->const_expr.i > left->type->canonical->builtin.bitsize) + { + SEMA_ERROR(right->loc, "Rightshift exceeds bitsize of '%s'", type_to_error_string(left->type)); + return false; + } + if (left->expr_kind == EXPR_CONST) + { + expr_replace(expr, left); + expr->const_expr.i >>= right->const_expr.i; + return true; + } + } + expr->type = left->type; + return true; +} + +static bool sema_expr_analyse_shl(Context *context, Expr *expr, Expr *left, Expr *right) +{ + // Todo: proper handling of signed / unsigned. Proper reduction of constants. + if (!type_is_integer(left->type) || !type_is_integer(right->type)) return sema_type_error_on_binop("<<", expr); + if (type_is_signed(right->type->canonical)) + { + cast(right, type_long, CAST_TYPE_IMPLICIT); + } + else + { + cast(left, type_ulong, CAST_TYPE_IMPLICIT); + } + if (right->expr_kind == EXPR_CONST) + { + if (right->const_expr.i > left->type->canonical->builtin.bitsize) + { + SEMA_ERROR(right->loc, "Leftshift exceeds bitsize of '%s'", type_to_error_string(left->type)); + return false; + } + if (left->expr_kind == EXPR_CONST) + { + expr_replace(expr, left); + expr->const_expr.i <<= right->const_expr.i; + return true; + } + } + expr->type = left->type; + return true; +} + static bool sema_expr_analyse_shr_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_shl(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } static bool sema_expr_analyse_shl_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } +static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr *right) +{ + if (!cast(left, type_bool, CAST_TYPE_IMPLICIT)) return false; + if (!cast(right, type_bool, CAST_TYPE_IMPLICIT)) return false; + if (both_const(left, right)) + { + expr_replace(expr, left); + expr->const_expr.b &= right->const_expr.b; + } + return true; +} + +static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr *right) +{ + if (!cast(left, type_bool, CAST_TYPE_IMPLICIT)) return false; + if (!cast(right, type_bool, CAST_TYPE_IMPLICIT)) return false; + if (both_const(left, right)) + { + expr_replace(expr, left); + expr->const_expr.b |= right->const_expr.b; + } + expr->type = type_bool; + return true; +} + static bool sema_expr_analyse_and_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } -static bool sema_expr_analyse_or(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } static bool sema_expr_analyse_or_assign(Context *context, Expr *expr, Expr *left, Expr *right) { TODO } #define SEMA_ANALYSE_CMP(op) { \ @@ -516,9 +747,17 @@ static inline bool sema_expr_analyse_binary(Context *context, Expr *expr) Expr *left = expr->binary_expr.left; Expr *right = expr->binary_expr.right; + // Special handling due to initalizer lists + if (expr->binary_expr.operator == TOKEN_EQ) + { + return sema_expr_analyse_assign(context, expr, left, right); + } + if (!sema_analyse_expr(context, left)) return false; if (!sema_analyse_expr(context, right)) return false; + assert(left->type); + assert(right->type); return BINOP_ANALYSIS[expr->binary_expr.operator](context, expr, left, right); } @@ -565,7 +804,7 @@ static inline bool sema_expr_analyse_type(Context *context, Expr *expr) static ExprBinopAnalysis BINOP_ANALYSIS[TOKEN_EOF] = { - [TOKEN_EQ] = &sema_expr_analyse_assign, + [TOKEN_EQ] = NULL, // Explicitly dispatched [TOKEN_STAR] = &sema_expr_analyse_mult, [TOKEN_MULT_ASSIGN] = &sema_expr_analyse_mult_assign, [TOKEN_PLUS] = &sema_expr_analyse_add, @@ -578,7 +817,7 @@ static ExprBinopAnalysis BINOP_ANALYSIS[TOKEN_EOF] = { [TOKEN_MOD_ASSIGN] = &sema_expr_analyse_mod_assign, [TOKEN_AND] = &sema_expr_analyse_and, [TOKEN_AND_ASSIGN] = &sema_expr_analyse_and_assign, - [TOKEN_OR] = &sema_expr_analyse_bit_or, + [TOKEN_OR] = &sema_expr_analyse_or, [TOKEN_OR_ASSIGN] = &sema_expr_analyse_or_assign, [TOKEN_AMP] = &sema_expr_analyse_bit_and, [TOKEN_BIT_AND_ASSIGN] = &sema_expr_analyse_bit_and_assign, diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 4fecff458..c19f5d0da 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -12,6 +12,7 @@ static Expr *parse_expr(void); static Expr *parse_paren_expr(void); static Expr *parse_precedence(Precedence precedence); static Expr *parse_initializer_list(void); +static Expr *parse_initializer(void); static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr); static Decl *parse_top_level(void); @@ -245,7 +246,7 @@ static inline Type *parse_base_type(void) CONSUME_OR(TOKEN_LPAREN, &poisoned_type); { type = type_new(TYPE_EXPRESSION); - type->unresolved_type_expr = TRY_EXPR_OR(parse_expr(), &poisoned_type); + type->unresolved_type_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_type); } EXPECT_OR(TOKEN_RPAREN, &poisoned_type); break; @@ -461,7 +462,7 @@ static inline Decl *parse_decl_after_type(bool local, Type *type) return &poisoned_decl; } advance_and_verify(TOKEN_EQ); - decl->var.init_expr = TRY_EXPR_OR(parse_expr(), &poisoned_decl); + decl->var.init_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_decl); decl = NULL; if (try_consume(TOKEN_COMMA)) continue; return main_decl; @@ -949,7 +950,6 @@ static inline Ast* parse_ct_if_stmt(void) static inline Ast* parse_ct_each_stmt(void) { - LOG_FUNC TODO } @@ -1620,7 +1620,7 @@ static inline Decl *parse_const_declaration(Visibility visibility) CONSUME_OR(TOKEN_EQ, &poisoned_decl); - decl->var.init_expr = TRY_EXPR_OR(parse_expr(), &poisoned_decl); + decl->var.init_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_decl); CONSUME_OR(TOKEN_EOS, &poisoned_decl); return decl; @@ -1637,7 +1637,6 @@ static inline Decl *parse_const_declaration(Visibility visibility) */ static inline Decl *parse_global_declaration(Visibility visibility) { - Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); Decl *decl = decl_new_var(tok, type, VARDECL_GLOBAL, visibility); @@ -1646,8 +1645,9 @@ static inline Decl *parse_global_declaration(Visibility visibility) if (try_consume(TOKEN_EQ)) { - decl->var.init_expr = TRY_EXPR_OR(parse_expr(), &poisoned_decl); + decl->var.init_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_decl); } + TRY_CONSUME_EOS_OR(&poisoned_decl); return decl; } @@ -1859,7 +1859,6 @@ static inline Ast *parse_generics_statements(void) */ static inline Decl *parse_generics_declaration(Visibility visibility) { - LOG_FUNC advance_and_verify(TOKEN_GENERIC); Type *rtype = NULL; if (tok.type != TOKEN_IDENT) @@ -1933,8 +1932,6 @@ static inline Decl *parse_generics_declaration(Visibility visibility) */ static inline bool parse_param_decl(Decl *parent, Decl*** parameters, bool type_only) { - LOG_FUNC - Type *type = TRY_TYPE_OR(parse_type_expression(), false); Decl *param = decl_new_var(tok, type, VARDECL_PARAM, parent->visibility); @@ -1952,7 +1949,7 @@ static inline bool parse_param_decl(Decl *parent, Decl*** parameters, bool type_ } if (name && try_consume(TOKEN_EQ)) { - param->var.init_expr = TRY_EXPR_OR(parse_expr(), false); + param->var.init_expr = TRY_EXPR_OR(parse_initializer(), false); } if (param->name.string) { @@ -2073,7 +2070,6 @@ static inline bool parse_opt_parameter_type_list(Decl *decl, FunctionSignature * */ static inline bool parse_func_typedef(Decl *decl, Visibility visibility) { - LOG_FUNC decl->typedef_decl.is_func = true; advance_and_verify(TOKEN_FUNC); Type *type = TRY_TYPE_OR(parse_type_expression(), false); @@ -2088,7 +2084,6 @@ static inline bool parse_func_typedef(Decl *decl, Visibility visibility) static inline Decl *parse_typedef_declaration(Visibility visibility) { - LOG_FUNC Decl *decl = decl_new(DECL_TYPEDEF, tok, visibility); advance_and_verify(TOKEN_TYPEDEF); if (tok.type == TOKEN_FUNC) @@ -2109,8 +2104,6 @@ static inline Decl *parse_typedef_declaration(Visibility visibility) static inline Decl *parse_macro_declaration(Visibility visibility) { - LOG_FUNC - advance_and_verify(TOKEN_MACRO); Type *rtype = NULL; @@ -2180,8 +2173,6 @@ static inline Decl *parse_macro_declaration(Visibility visibility) */ static inline Decl *parse_func_definition(Visibility visibility, bool is_interface) { - LOG_FUNC - advance_and_verify(TOKEN_FUNC); Type *return_type = TRY_TYPE_OR(parse_type_expression(), false); @@ -2355,6 +2346,7 @@ static inline bool parse_conditional_top_level(Decl ***decls) while (tok.type != TOKEN_RBRACE && tok.type != TOKEN_EOF) { Decl *decl = parse_top_level(); + if (decl == NULL) continue; if (decl_ok(decl)) { vec_add(*decls, decl); @@ -2396,6 +2388,30 @@ static inline Decl *parse_ct_if_top_level(void) return ct; } +static inline Decl *parse_incremental_array(void) +{ + Token name = tok; + advance_and_verify(TOKEN_IDENT); + + CONSUME_OR(TOKEN_PLUS_ASSIGN, &poisoned_decl); + TODO +} + +static inline bool check_no_visibility_before(Visibility visibility) +{ + switch (visibility) + { + case VISIBLE_PUBLIC: + SEMA_ERROR(tok, "Unexpected 'public' before '%.*s'.", tok.span.length, tok.start); + return false; + case VISIBLE_LOCAL: + SEMA_ERROR(tok, "Unexpected 'local' before '%.*s'.", tok.span.length, tok.start); + return false; + default: + return true; + } +} + /** * top_level @@ -2438,10 +2454,7 @@ static inline Decl *parse_top_level(void) case TOKEN_FUNC: return parse_func_definition(visibility, false); case TOKEN_CT_IF: - if (visibility != VISIBLE_MODULE) - { - SEMA_ERROR(tok, "Unexpected '%.*s' before '$if'.", TOK2VARSTR(tok)); - } + if (!check_no_visibility_before(visibility)) return false; return parse_ct_if_top_level(); case TOKEN_CONST: return parse_const_declaration(visibility); @@ -2458,18 +2471,20 @@ static inline Decl *parse_top_level(void) return parse_error_declaration(visibility); case TOKEN_TYPEDEF: return parse_typedef_declaration(visibility); - case TOKEN_IDENT: case TOKEN_TYPE: case TOKEN_TYPE_IDENT: // All of these start type return parse_global_declaration(visibility); + case TOKEN_IDENT: + if (!check_no_visibility_before(visibility)) return false; + return parse_incremental_array(); case TOKEN_EOF: assert(visibility != VISIBLE_MODULE); - sema_error_at(next_tok.span.loc - 1, "Expected a top level declaration after '%.*s'.", TOK2VARSTR(tok)); + sema_error_at(tok.span.loc - 1, "Expected a top level declaration'."); return &poisoned_decl; default: // We could have included all fundamental types above, but do it here instead. - if (token_is_type(next_tok.type)) + if (token_is_type(tok.type)) { return parse_global_declaration(visibility); } @@ -2687,6 +2702,68 @@ static Expr *parse_integer(Expr *left) const char *string = tok.start; const char *end = string + tok.span.length; uint64_t i = 0; + if (string[0] == '\'') + { + union + { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + uint8_t b[8]; + } bytes; + int pos = 0; + while (++string < end - 1) + { + if (*string == '\\') + { + if (*(++string) == 'x') + { + int hex = 0; + for (int j = 0; j < 2; j++) + { + hex <<= 4; + char c = *(++string); + if (c < 'A') + { + hex += c - '0'; + } + else if (c < 'a') + { + hex += c - 'A' + 10; + } + else + { + hex += c - 'a' + 10; + } + } + bytes.b[pos++] = hex; + continue; + } + } + bytes.b[pos++] = (unsigned)*string; + } + switch (pos) + { + case 1: + expr_int->const_expr.i = bytes.u8; + break; + case 2: + expr_int->const_expr.i = bytes.u16; + break; + case 4: + expr_int->const_expr.i = bytes.u32; + break; + case 8: + expr_int->const_expr.i = bytes.u64; + break; + } + expr_int->const_expr.type = CONST_INT; + expr_int->type = i > INT64_MAX ? type_compuint : type_compint; + expr_int->resolve_status = RESOLVE_DONE; + advance(); + return expr_int; + } switch (tok.span.length > 2 ? string[1] : '0') { case 'x': @@ -2813,7 +2890,6 @@ static Expr *parse_nil(Expr *left) } -static Expr *parse_initializer(void); /** * initializer_list diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index c7498fd7b..1cf4a20b4 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -10,11 +10,9 @@ bool sema_analyse_stmt_list(Context *context, Ast *statement); void sema_init(File *file) { - LOG_FUNC } - void sema_shadow_error(Decl *decl, Decl *old) { sema_error_range(decl->name.span, "The '%s' would shadow a previous declaration.", decl->name.string); @@ -101,6 +99,30 @@ static bool sema_resolve_array_type(Context *context, Type *type) } static inline bool sema_analyse_struct_member(Context *context, Decl *decl) { + if (decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION) + { + DEBUG_LOG("Beginning analysis of inner struct/union"); + VECEACH(decl->strukt.members, i) + { + Decl *member = decl->strukt.members[i]; + if (!decl_ok(member)) + { + decl_poison(decl); + continue; + } + if (!sema_analyse_struct_member(context, decl->strukt.members[i])) + { + if (decl_ok(decl)) + { + decl_poison(decl); + continue; + } + decl_poison(decl); + } + } + DEBUG_LOG("Analysis complete."); + return decl_ok(decl); + } assert(decl->decl_kind == DECL_VAR); assert(decl->var.kind == VARDECL_MEMBER); assert(!decl->var.init_expr); @@ -112,10 +134,11 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl) assert(decl->var.type->canonical); return true; } -static inline bool sema_analyse_struct(Context *context, Decl *decl) + +static inline bool sema_analyse_struct_union(Context *context, Decl *decl) { DEBUG_LOG("Beginning analysis of %s.", decl->name.string); - assert(decl->decl_kind == DECL_STRUCT); + assert(decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION); VECEACH(decl->strukt.members, i) { Decl *member = decl->strukt.members[i]; @@ -135,6 +158,7 @@ static inline bool sema_analyse_struct(Context *context, Decl *decl) } } DEBUG_LOG("Analysis complete."); + // Todo, resolve alignment, size etc. return decl_ok(decl); } @@ -268,8 +292,11 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl) *vars = VECADD(*vars, decl); if (decl->var.init_expr) { - if (!sema_analyse_expr(context, decl->var.init_expr) || - !cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) + Type *prev_type = context->left_type_in_assignment; + context->left_type_in_assignment = decl->var.type; + bool success = sema_analyse_expr(context, decl->var.init_expr) && cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN); + context->left_type_in_assignment = prev_type; + if (!success) { decl_poison(decl); return false; @@ -621,10 +648,6 @@ static bool sema_analyse_asm_stmt(Context *context, Ast *statement) TODO } -static bool sema_analyse_attribute(Context *context, Ast *statement) -{ - TODO -} static bool sema_analyse_break_stmt(Context *context, Ast *statement) { @@ -837,7 +860,7 @@ static bool sema_analyse_compound_stmt(Context *context, Ast *statement) static AstAnalysis AST_ANALYSIS[AST_WHILE_STMT + 1] = { [AST_ASM_STMT] = &sema_analyse_asm_stmt, - [AST_ATTRIBUTE] = &sema_analyse_attribute, + [AST_ATTRIBUTE] = NULL, [AST_BREAK_STMT] = &sema_analyse_break_stmt, [AST_CASE_STMT] = &sema_analyse_case_stmt, [AST_CATCH_STMT] = &sema_analyse_catch_stmt, @@ -920,6 +943,58 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl) return true; } +static inline bool sema_analyse_global(Context *context, Decl *decl) +{ + if (!sema_resolve_type(context, decl->var.type)) return false; + if (decl->var.init_expr) + { + if (!sema_analyse_expr(context, decl->var.init_expr)) return false; + if (!cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + if (decl->var.init_expr->expr_kind != EXPR_CONST) + { + SEMA_ERROR(decl->var.init_expr->loc, "The expression must be a constant value."); + return false; + } + } + switch (decl->var.kind) + { + case VARDECL_CONST: + assert(decl->var.init_expr); + return true; + case VARDECL_GLOBAL: + return true; + default: + UNREACHABLE + break; + } +} + +static inline bool sema_analyse_typedef(Context *context, Decl *decl) +{ + if (!sema_resolve_type(context, decl->typedef_decl.type)) return false; + // Do we need anything else? + return true; +} + +static inline bool sema_analyse_generic(Context *context, Decl *decl) +{ + TODO + return true; +} + +static inline bool sema_analyse_enum(Context *context, Decl *decl) +{ + if (!sema_resolve_type(context, decl->typedef_decl.type)) return false; + // TODO assign numbers to constants + return true; +} + +static inline bool sema_analyse_error(Context *context, Decl *decl) +{ + // TODO assign numbers to constants + return true; +} + static inline bool sema_analyse_decl(Context *context, Decl *decl) { if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl); @@ -933,28 +1008,51 @@ static inline bool sema_analyse_decl(Context *context, Decl *decl) } decl->resolve_status = RESOLVE_RUNNING; - switch (decl->decl_kind) { - case DECL_IMPORT: - TODO case DECL_STRUCT: - if (!sema_analyse_struct(context, decl)) return false; - decl->resolve_status = RESOLVE_DONE; + case DECL_UNION: + if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl); context_add_header_decl(context, decl); - return true; + break; case DECL_FUNC: - if (!sema_analyse_func(context, decl)) return false; - decl->resolve_status = RESOLVE_DONE; + if (!sema_analyse_func(context, decl)) return decl_poison(decl); context_add_header_decl(context, decl); - return true; + break; case DECL_MACRO: - if (!sema_analyse_macro(context, decl)) return false; - decl->resolve_status = RESOLVE_DONE; - return true; - default: - TODO + if (!sema_analyse_macro(context, decl)) return decl_poison(decl); + break; + case DECL_VAR: + if (!sema_analyse_global(context, decl)) return decl_poison(decl); + context_add_header_decl(context, decl); + break; + case DECL_TYPEDEF: + if (!sema_analyse_typedef(context, decl)) return decl_poison(decl); + break; + case DECL_ENUM: + if (!sema_analyse_enum(context, decl)) return decl_poison(decl); + break; + case DECL_ERROR: + if (!sema_analyse_error(context, decl)) return decl_poison(decl); + break; + case DECL_GENERIC: + if (!sema_analyse_generic(context, decl)) return decl_poison(decl); + break; + case DECL_POISONED: + case DECL_IMPORT: + case DECL_ENUM_CONSTANT: + case DECL_ERROR_CONSTANT: + case DECL_ARRAY_VALUE: + case DECL_MULTI_DECL: + case DECL_CT_ELSE: + case DECL_CT_ELIF: + UNREACHABLE + case DECL_CT_IF: + // Handled elsewhere + UNREACHABLE } + decl->resolve_status = RESOLVE_DONE; + return true; }