diff --git a/missing.txt b/missing.txt index f3e8a6747..98659e009 100644 --- a/missing.txt +++ b/missing.txt @@ -38,10 +38,15 @@ Things missing: - Bitstruct - Enumset - Typeid +- Ranges + +* Arrays +- Allow fixed arrays with no larger size than 32 bit unsigned. * Struct / union - Cast to union? - Structural typed anonymous structs and casts to them. +- Auto deref on access. * Expressions - Disallow x >= 0 and x < 0 on unsigned types unless in a macro. @@ -69,4 +74,5 @@ Things missing: - Values: min, max, array - Functions: fomOrdinal, ordinal, fromName, name, fromFullName, fullName, fromQualifiedName, qualifiedName, (), fromValue() - +* Error reporting +- When a variable fails to parse correctly, store it to prevent follow up errors. diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 74b2ea66e..c32388ac3 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -117,41 +117,6 @@ union SimpleUnion double f; } -struct AnonStruct -{ - int a; - struct sune - { - int b; - int c; - } - struct - { - int b1; - int c1; - } - union - { - int b2; - int c2; - } - int x; -} - - -func void testAnonStruct() -{ - - AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 }; - AnonStruct foo; - - s.sune.b = 1; - s.b1 = 2; - s.b2 = 3; - s.c2 = 4; - -} - func void testUnion() { SimpleUnion s; @@ -160,7 +125,7 @@ func void testUnion() s = { 1 }; int x = 2; s = { (x = 2) }; - //s = { f = 1.0 }; + s = { f = 1.0 }; TestUnion tu = { e = TestStruct2 { c = 1 } }; tu.e = TestStruct2 { c = 1 }; } @@ -290,6 +255,69 @@ func int barok() throws Error, OtherError return 100; } +struct SimpleStruct +{ + int a; + int b; + double c; + double d; + char z1; + char z2; +} +func void testSimpleStruct(int x) +{ + SimpleStruct snoinit; + SimpleStruct sinit = { b = 1, d = 3.0, z1 = 1 }; + sinit.a = 1; + sinit.b = 2; + printf("a = %d, b = %d (1), c = %f, d = %f (3.0), z1 = %d (1), z2 = %d\n", sinit.a, sinit.b, sinit.c, sinit.d, cast(sinit.z1, int), cast(sinit.z2, int)); + snoinit.b = 1; + snoinit.a = 100; + snoinit.d = 3.0; + snoinit.c = 2.0; + snoinit.z1 = 1; + snoinit.z2 = 2; + printf("b = %d (1), d = %f (3.0), z1 = %d (1)\n", snoinit.b, snoinit.d, snoinit.z1); +} + +struct AnonStruct +{ + int a; + struct sune + { + int b; + int c; + } + struct + { + int b1; + int c1; + } + union + { + int b2; + int c2; + } + int x; +} + +func void testAnonStruct() +{ + AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 }; + AnonStruct foo; + + printf("a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.sune.b, s.sune.c, s.b1, s.c1, s.b2, s.c2, s.x); + + s.sune.b = 100; + s.sune.c = 99; + s.b1 = 3; + s.b2 = 5; + s.c2 = 7; + + printf("a = %d, b = %d (100), c = %d (99), b1 = %d (3), c1 = %d, b2 = %d (7), c2 = %d (7), x = %d\n", s.a, s.sune.b, s.sune.c, s.b1, s.c1, s.b2, s.c2, s.x); + + +} func int boba(int y, int j) { // hello(); @@ -526,6 +554,34 @@ func int testReturnDefer() return i; } +struct WithArray +{ + int[4] x; +} + +func void testArray() +{ + //int[4] zebra = { [0] = 1 }; + WithArray boo; + boo.x[0] = 2; + printf("boo.x[0] = %d\n", boo.x[0]); + printf("boo.x[2] = %d\n", boo.x[2]); + int[4] x; + x[1] = 1; + x[0] = 3; + int y = x[1]; + int z = 1; + int* b = &z; + printf("b: %d\n", *b); + *b = 3; + printf("b: %d\n", *b); + printf("z: %d\n", z); + + for (int i = 0; i < 4; i++) + { + printf("x[%d] = %d\n", i, x[i]); + } +} func void testDefer() { printf("1 == %d\n", testReturnDefer()); @@ -557,12 +613,17 @@ JUMP: defer printf("7"); printf("6"); } + + func int main(int x) { printf("Helo!\n"); testDefault(y = 99); testPointers(2, 3); testDefer(); + testArray(); + testAnonStruct(); + testSimpleStruct(0); int efd = 9; uint fefoek = 1; printf("Helo: %d\n", efd + cast(fefoek, int)); @@ -723,4 +784,5 @@ func void test2(int* x, int y, int z) x + 1; int j1 = x[0]; j1 = *x; -} \ No newline at end of file +} + diff --git a/src/compiler/bigint.c b/src/compiler/bigint.c index 604d3118d..846060e70 100644 --- a/src/compiler/bigint.c +++ b/src/compiler/bigint.c @@ -1896,7 +1896,14 @@ const char *bigint_to_error_string(const BigInt *bigint, uint64_t base) if (bigint->digit_count == 1 && base == 10) { char *res = NULL; - asprintf(&res, "%" PRIu64, bigint->digit); + if (bigint->is_negative) + { + asprintf(&res, "-%" PRIu64, bigint->digit); + } + else + { + asprintf(&res, "%" PRIu64, bigint->digit); + } return res; } size_t len = bigint->digit_count * 64; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index f817e6b66..83a6b3611 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -133,6 +133,23 @@ typedef struct _Path uint32_t len; } Path; +typedef enum +{ + DESIGNATED_IDENT, + DESIGNATED_SUBSCRIPT +} DesignatedPathKind; + +typedef struct _DesignatedPath +{ + DesignatedPathKind kind; + struct _DesignatedPath *sub_path; + Type *type; + union + { + unsigned index; + Expr *index_expr; + }; +} DesignatedPath; typedef struct { unsigned char bitsize; @@ -508,6 +525,12 @@ typedef struct Ast **stmts; } ExprFuncBlock; +typedef struct +{ + Expr *left; + Expr *right; +} ExprRange; + typedef enum { INITIALIZER_UNKNOWN, @@ -522,6 +545,11 @@ typedef struct Expr** initializer_expr; } ExprInitializer; +typedef struct +{ + DesignatedPath *path; + Expr* value; +} ExprDesignatedInit; struct _Expr { @@ -530,9 +558,11 @@ struct _Expr SourceRange span; Type *type; union { + ExprDesignatedInit designated_init_expr; Expr *group_expr; ExprCast cast_expr; ExprConst const_expr; + ExprRange range_expr; ExprStructValue struct_value_expr; ExprTypeRef type_access; ExprTry try_expr; @@ -1151,6 +1181,7 @@ static inline Token wrap(const char *string) Type *type_get_ptr(Type *ptr_type); Type *type_get_meta(Type *meta_type); +Type *type_get_indexed_type(Type *type); Type *type_get_array(Type *arr_type, uint64_t len); Type *type_signed_int_by_bitsize(unsigned bytesize); Type *type_unsigned_int_by_bitsize(unsigned bytesize); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 67656e9c6..1ca919048 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -230,6 +230,8 @@ typedef enum EXPR_SCOPED_EXPR, EXPR_MACRO_EXPR, EXPR_EXPR_BLOCK, + EXPR_RANGE, + EXPR_DESIGNATED_INITIALIZER, } ExprKind; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 49cb4463b..189968791 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -200,6 +200,11 @@ void llvm_codegen(Context *context) { gencontext_emit_function_decl(&gen_context, context->functions[i]); } + VECEACH(context->functions, i) + { + Decl *decl = context->functions[i]; + if (decl->func.body) gencontext_emit_function_body(&gen_context, decl); + } gencontext_print_llvm_ir(&gen_context); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index b050172ec..f14542b50 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -82,6 +82,18 @@ static inline LLVMValueRef gencontext_emit_subscript_addr_from_value(GenContext llvm_type(parent_type->pointer), parent, &index, 1, "[]"); case TYPE_ARRAY: + // TODO insert trap on overflow. + { + LLVMValueRef zero = LLVMConstInt(LLVMIntType(32), 0, false); + LLVMValueRef indices[2] = { + zero, + index, + }; + return LLVMBuildInBoundsGEP2(context->builder, + llvm_type(parent_type), + parent, indices, 2, "[x]"); + + } case TYPE_VARARRAY: case TYPE_SUBARRAY: case TYPE_STRING: @@ -93,14 +105,45 @@ static inline LLVMValueRef gencontext_emit_subscript_addr_from_value(GenContext } static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr) { - LLVMValueRef parent = gencontext_emit_expr(context, expr->subscript_expr.expr); - return gencontext_emit_subscript_addr_from_value(context, parent, expr->subscript_expr.expr->type->canonical, expr->subscript_expr.index); + Expr *parent = expr->subscript_expr.expr; + Expr *index = expr->subscript_expr.index; + LLVMValueRef index_value = gencontext_emit_expr(context, index); + LLVMValueRef parent_value; + switch (parent->type->canonical->type_kind) + { + case TYPE_POINTER: + parent_value = gencontext_emit_expr(context, expr->subscript_expr.expr); + return LLVMBuildGEP2(context->builder, + llvm_type(parent->type->canonical), + parent_value, &index_value, 1, "[]"); + case TYPE_ARRAY: + { + // TODO insert trap on overflow. + LLVMValueRef zero = LLVMConstInt(LLVMIntType(32), 0, false); + LLVMValueRef indices[2] = { + zero, + index_value, + }; + parent_value = gencontext_emit_address(context, expr->subscript_expr.expr); + return LLVMBuildInBoundsGEP2(context->builder, + llvm_type(parent->type), + parent_value, indices, 2, "[x]"); + } + case TYPE_VARARRAY: + case TYPE_SUBARRAY: + case TYPE_STRING: + TODO + default: + UNREACHABLE + + } } static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member) { unsigned index; Decl *current_parent; + assert(member->resolve_status == RESOLVE_DONE); if (decl_is_struct_type(member)) { index = member->strukt.id; @@ -119,9 +162,9 @@ static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRe if (current_parent->decl_kind == DECL_UNION) { - return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), "unionref"); + return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), member->name ?: "anon"); } - return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, "structref"); + return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, member->name ?: "anon"); } @@ -151,8 +194,13 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) { switch (expr->expr_kind) { + case EXPR_RANGE: + TODO case EXPR_EXPR_BLOCK: TODO + case EXPR_DESIGNATED_INITIALIZER: + // Should only appear when generating designated initializers. + UNREACHABLE case EXPR_IDENTIFIER: return expr->identifier_expr.decl->var.backend_ref; case EXPR_UNARY: @@ -252,28 +300,7 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr * } -static inline LLVMValueRef gencontext_emit_designated_initializer(GenContext *context, Type *parent_type, LLVMValueRef parent, Expr *expr) -{ - assert(parent_type == parent_type->canonical); - switch (expr->expr_kind) - { - case EXPR_SUBSCRIPT: - if (expr->subscript_expr.expr) - { - parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->subscript_expr.expr); - parent_type = expr->subscript_expr.expr->type->canonical; - } - return gencontext_emit_subscript_addr_from_value(context, parent, parent_type, expr->subscript_expr.index); - case EXPR_ACCESS: - parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->access_expr.parent); - parent_type = expr->subscript_expr.expr->type->canonical; - return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->access_expr.ref); - case EXPR_IDENTIFIER: - return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->identifier_expr.decl); - default: - UNREACHABLE - } -} + /** * Emit a Foo { .... } literal. @@ -293,7 +320,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con LLVMConstInt(llvm_type(type_byte), 0, false), LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), expr->type->decl->strukt.abi_alignment); - return ref; + return LLVMBuildLoad2(context->builder, type, ref, ""); } Expr **elements = expr->expr_initializer.initializer_expr; @@ -307,7 +334,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con LLVMValueRef init_value = gencontext_emit_expr(context, elements[0]); LLVMValueRef u = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(elements[0]->type->canonical), 0), ""); LLVMBuildStore(context->builder, init_value, u); - return ref; + return LLVMBuildLoad2(context->builder, type, ref, ""); } VECEACH(elements, i) { @@ -316,7 +343,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con LLVMValueRef subref = LLVMBuildStructGEP2(context->builder, type, ref, i, ""); LLVMBuildStore(context->builder, init_value, subref); } - return ref; + return LLVMBuildLoad2(context->builder, type, ref, ""); } @@ -328,11 +355,48 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con VECEACH(elements, i) { Expr *element = elements[i]; - LLVMValueRef sub_value = gencontext_emit_expr(context, element->binary_expr.right); - LLVMValueRef sub_ref = gencontext_emit_designated_initializer(context, expr->type->canonical, ref, element->binary_expr.left); + DesignatedPath *path = element->designated_init_expr.path; + LLVMValueRef sub_value = gencontext_emit_expr(context, element->designated_init_expr.value); + LLVMValueRef sub_ref = ref; + Type *parent_type = expr->type->canonical; + while (path) + { + switch (path->kind) + { + case DESIGNATED_IDENT: + if (parent_type->canonical->type_kind == TYPE_UNION) + { + sub_ref = LLVMBuildBitCast(context->builder, sub_ref, LLVMPointerType(llvm_type(path->type), 0), "unionref"); + } + else + { + sub_ref = LLVMBuildStructGEP2(context->builder, llvm_type(parent_type), sub_ref, path->index, "structref"); + } + break; + case DESIGNATED_SUBSCRIPT: + { + // TODO range, more arrays + LLVMValueRef zero = LLVMConstInt(LLVMIntType(32), 0, false); + LLVMValueRef index = gencontext_emit_expr(context, path->index_expr); + LLVMValueRef indices[2] = { + zero, + index, + }; + sub_ref = LLVMBuildInBoundsGEP2(context->builder, + llvm_type(parent_type), + sub_ref, indices, 2, "[x]"); + break; + } + default: + UNREACHABLE; + + } + parent_type = path->type; + path = path->sub_path; + } LLVMBuildStore(context->builder, sub_value, sub_ref); } - return ref; + return LLVMBuildLoad2(context->builder, type, ref, ""); } static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, bool use_mod, LLVMValueRef current_value, Expr *expr, int diff) @@ -902,14 +966,6 @@ LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr) -static inline LLVMValueRef gencontext_emit_access_expr(GenContext *context, Expr *expr) -{ - // Improve, add string description to the access? - LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent); - LLVMValueRef val = LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, expr->access_expr.ref->var.id, ""); - return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, ""); -} - static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *context, Expr *expr) { LLVMValueRef value = NULL; @@ -965,8 +1021,13 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr) { switch (expr->expr_kind) { + case EXPR_RANGE: + TODO case EXPR_POISONED: UNREACHABLE + case EXPR_DESIGNATED_INITIALIZER: + // Should only appear when generating designated initializers. + UNREACHABLE case EXPR_EXPR_BLOCK: return gencontext_emit_expr_block(context, expr); case EXPR_SCOPED_EXPR: @@ -990,13 +1051,12 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr) UNREACHABLE case EXPR_IDENTIFIER: case EXPR_SUBSCRIPT: + case EXPR_ACCESS: return gencontext_load_expr(context, gencontext_emit_address(context, expr)); case EXPR_CALL: return gencontext_emit_call_expr(context, expr); case EXPR_GROUP: return gencontext_emit_expr(context, expr->group_expr); - case EXPR_ACCESS: - return gencontext_emit_access_expr(context, expr); case EXPR_INITIALIZER_LIST: return gencontext_emit_initializer_list_expr(context, expr); case EXPR_EXPRESSION_LIST: diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 289097275..6eefbfe1f 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -223,7 +223,6 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) 0); LLVMSetSubprogram(decl->func.backend_value, context->debug.function); } - if (decl->func.body) gencontext_emit_function_body(context, decl); } void gencontext_emit_extern_decl(GenContext *context, Decl *decl) diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index e460d61b6..148fe2ce5 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -98,7 +98,7 @@ static inline LLVMBasicBlockRef gencontext_create_free_block(GenContext *context { return LLVMCreateBasicBlockInContext(context->context, name); } - +void gencontext_emit_function_body(GenContext *context, Decl *decl); void gencontext_emit_implicit_return(GenContext *context); void gencontext_emit_function_decl(GenContext *context, Decl *decl); void gencontext_emit_extern_decl(GenContext *context, Decl *decl); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index e8e66bc21..8208b08c1 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -110,14 +110,13 @@ static inline LLVMTypeRef llvm_type_from_ptr(LLVMContextRef context, Type *type) static inline LLVMTypeRef llvm_type_from_array(LLVMContextRef context, Type *type) { - LLVMTypeRef base_llvm_type = llvm_get_type(context, type->array.base); - if (type->canonical != type) { return type->backend_type = llvm_get_type(context, type->canonical); } - return type->backend_type = LLVMPointerType(base_llvm_type, /** TODO **/0); + LLVMTypeRef base_llvm_type = llvm_get_type(context, type->array.base); + return type->backend_type = LLVMArrayType(base_llvm_type, type->array.len); } LLVMTypeRef llvm_func_type(LLVMContextRef context, Type *type) @@ -206,7 +205,7 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type) return type->backend_type = llvm_type_from_ptr(context, type); case TYPE_STRING: // TODO - return type->backend_type = LLVMPointerType(LLVMTYPE(type_char), 0); + return type->backend_type = LLVMPointerType(llvm_get_type(context, type_char), 0); case TYPE_ARRAY: return type->backend_type = llvm_type_from_array(context, type); case TYPE_SUBARRAY: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 07f441fe3..30502b090 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -75,7 +75,17 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type) TypeInfo *type = NULL; Expr *expr = NULL; SourceRange start = context->tok.span; - if (!parse_type_or_expr(context, &expr, &type)) return false; + // Special handling of [123] + if (try_consume(context, TOKEN_LBRACKET)) + { + expr = TRY_EXPR_OR(parse_expr(context), false); + CONSUME_OR(TOKEN_RBRACKET, false); + expr = TRY_EXPR_OR(parse_precedence_with_left_side(context, expr, PREC_ASSIGNMENT), false); + } + else + { + if (!parse_type_or_expr(context, &expr, &type)) return false; + } if (!expr) { if (!allow_type) @@ -253,8 +263,11 @@ Expr *parse_initializer_list(Context *context) Expr *initializer_list = EXPR_NEW_TOKEN(EXPR_INITIALIZER_LIST, context->tok); initializer_list->expr_initializer.init_type = INITIALIZER_UNKNOWN; CONSUME_OR(TOKEN_LBRACE, &poisoned_expr); - if (!parse_param_list(context, &initializer_list->expr_initializer.initializer_expr, false)) return &poisoned_expr; - CONSUME_OR(TOKEN_RBRACE, &poisoned_expr); + if (!try_consume(context, TOKEN_RBRACE)) + { + if (!parse_param_list(context, &initializer_list->expr_initializer.initializer_expr, false)) return &poisoned_expr; + CONSUME_OR(TOKEN_RBRACE, &poisoned_expr); + } return initializer_list; } @@ -315,6 +328,7 @@ static Expr *parse_subscript_expr(Context *context, Expr *left) Expr *subscript_ast = EXPR_NEW_EXPR(EXPR_SUBSCRIPT, left); subscript_ast->subscript_expr.expr = left; subscript_ast->subscript_expr.index = index; + RANGE_EXTEND_PREV(subscript_ast); return subscript_ast; } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index de3746006..6bbf06594 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -119,6 +119,7 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl) sema_set_struct_size(decl); } DEBUG_LOG("Analysis complete."); + decl->resolve_status = RESOLVE_DONE; return decl_ok(decl); } assert(decl->decl_kind == DECL_VAR); @@ -429,7 +430,6 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) { if (!sema_analyse_method_function(context, decl)) return decl_poison(decl); } - if (decl->func.body && !sema_analyse_function_body(context, decl)) return decl_poison(decl); if (decl->name == main_name) { if (decl->visibility == VISIBLE_LOCAL) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f43bdf609..b4dd3625e 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -351,11 +351,12 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr } } -static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *context, Expr *expr) +static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *context, Type *parent, Expr *expr) { assert(expr->expr_kind == EXPR_SUBSCRIPT); - assert(expr->subscript_expr.expr->resolve_status == RESOLVE_DONE); - Type *type = expr->subscript_expr.expr->type->canonical; + Expr *subscripted = expr->subscript_expr.expr; + Type *type = parent ? parent->canonical : subscripted->type->canonical; + Expr *index = expr->subscript_expr.index; Type *inner_type; switch (type->type_kind) { @@ -372,16 +373,45 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context * inner_type = type_char; break; default: - SEMA_ERROR(expr->subscript_expr.expr, "Cannot index '%s'.", type_to_error_string(type)); + SEMA_ERROR((parent ? expr : subscripted), "Cannot index '%s'.", type_to_error_string(type)); return false; } - if (!sema_analyse_expr(context, type_isize, expr->subscript_expr.index)) return false; + if (!sema_analyse_expr(context, type_isize, index)) return false; // Unless we already have type_usize, cast to type_isize; - if (expr->subscript_expr.index->type->canonical->type_kind != type_usize->canonical->type_kind) + if (index->type->canonical->type_kind != type_usize->canonical->type_kind) { - if (!cast_implicit(expr->subscript_expr.index, type_isize)) return false; + if (!cast_implicit(index, type_isize)) return false; + } + // Check range + if (index->expr_kind == EXPR_CONST) + { + switch (type->type_kind) + { + case TYPE_ARRAY: + { + BigInt size; + bigint_init_unsigned(&size, type->array.len); + if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT) + { + SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.", + bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1); + return false; + } + // fallthrough + } + case TYPE_VARARRAY: + case TYPE_SUBARRAY: + if (bigint_cmp_zero(&index->const_expr.i) == CMP_LT) + { + SEMA_ERROR(index, "Array index out of bounds, was %s.", bigint_to_error_string(&index->const_expr.i, 10)); + return false; + } + break; + default: + break; + } } expr->type = inner_type; return true; @@ -391,7 +421,7 @@ static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr { if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false; - return sema_expr_analyse_subscript_after_parent_resolution(context, expr); + return sema_expr_analyse_subscript_after_parent_resolution(context, NULL, expr); } static inline bool sema_expr_analyse_method_function(Context *context, Expr *expr, Decl *decl, bool is_pointer) @@ -436,9 +466,10 @@ static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *exp return true; } - -static inline bool sema_expr_analyse_access_after_parent_resolution(Context *context, Expr *expr) +static inline bool sema_expr_analyse_access(Context *context, Expr *expr) { + if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false; + assert(expr->expr_kind == EXPR_ACCESS); assert(expr->access_expr.parent->resolve_status == RESOLVE_DONE); @@ -486,12 +517,6 @@ static inline bool sema_expr_analyse_access_after_parent_resolution(Context *con return true; } -static inline bool sema_expr_analyse_access(Context *context, Expr *expr) -{ - if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false; - return sema_expr_analyse_access_after_parent_resolution(context, expr); -} - static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr) { @@ -550,78 +575,172 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp return false; } -static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr); +static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *path, Expr *expr); -static Decl *sema_analyse_init_identifier_string(Context *context, Decl *strukt, const char *string) +static DesignatedPath *sema_analyse_init_identifier_string(Context *context, DesignatedPath *parent_path, const char *string) { - assert(decl_is_struct_type(strukt)); - Decl **members = strukt->strukt.members; + assert(type_is_structlike(parent_path->type)); + Decl **members = parent_path->type->decl->strukt.members; VECEACH(members, i) { Decl *member = members[i]; - if (member->name == string) return member; + if (member->name == string) + { + DesignatedPath *sub_path = CALLOCS(DesignatedPath); + sub_path->type = member->type; + sub_path->kind = DESIGNATED_IDENT; + sub_path->index = i; + parent_path->sub_path = sub_path; + return sub_path; + } if (!member->name) { - Decl *anonymous_member = sema_analyse_init_identifier_string(context, member->type->decl, string); - if (anonymous_member) return anonymous_member; + DesignatedPath temp_path; + temp_path.type = member->type; + DesignatedPath *found = sema_analyse_init_identifier_string(context, &temp_path, string); + if (!found) continue; + DesignatedPath *real_path = malloc_arena(sizeof(DesignatedPath)); + *real_path = temp_path; + real_path->index = i; + real_path->kind = DESIGNATED_IDENT; + parent_path->sub_path = real_path; + return found; } } return NULL; } -static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr *expr) + +static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath *parent, Expr *access_expr) { - assert(expr->resolve_status == RESOLVE_NOT_DONE); - expr->resolve_status = RESOLVE_RUNNING; - Decl *res = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier); - if (!res) return NULL; - expr->identifier_expr.decl = res; - expr->resolve_status = RESOLVE_DONE; - expr->type = res->type; - return res; + DesignatedPath *last_path = sema_analyse_init_path(context, parent, access_expr->access_expr.parent); + if (!last_path) return NULL; + return sema_analyse_init_identifier_string(context, last_path, access_expr->access_expr.sub_element.string); } -static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr) +static bool expr_cast_to_index(Expr *index) { - assert(access_expr->resolve_status == RESOLVE_NOT_DONE); - access_expr->resolve_status = RESOLVE_RUNNING; - Decl *decl = sema_analyse_init_path(context, strukt, access_expr->access_expr.parent); - if (!decl || !decl_is_struct_type(decl->type->decl)) + if (index->expr_kind == EXPR_RANGE) { - access_expr->resolve_status = RESOLVE_DONE; - return NULL; + TODO } - decl = access_expr->access_expr.ref = sema_analyse_init_identifier_string(context, decl->type->decl, access_expr->access_expr.sub_element.string); - access_expr->resolve_status = RESOLVE_DONE; - access_expr->type = decl->type; - return decl; + if (index->type->canonical->type_kind == type_usize->canonical->type_kind) return true; + return cast_implicit(index, type_isize); } -static Decl *sema_analyse_init_subscript(Context *context, Decl *array, Expr *subscript) +static bool expr_check_index_in_range(Type *type, Expr *index) { - TODO - if (array->type->type_kind != TYPE_ARRAY) + if (index->expr_kind == EXPR_RANGE) { - + return expr_check_index_in_range(type, index->range_expr.left) & expr_check_index_in_range(type, index->range_expr.right); } + assert(type == type->canonical); + if (index->expr_kind == EXPR_CONST) + { + switch (type->type_kind) + { + case TYPE_ARRAY: + { + BigInt size; + bigint_init_unsigned(&size, type->array.len); + if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT) + { + SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.", + bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1); + return false; + } + // fallthrough + } + case TYPE_VARARRAY: + case TYPE_SUBARRAY: + if (bigint_cmp_zero(&index->const_expr.i) == CMP_LT) + { + SEMA_ERROR(index, "Array index out of bounds, was %s.", bigint_to_error_string(&index->const_expr.i, 10)); + return false; + } + break; + case TYPE_STRING: + TODO + default: + UNREACHABLE + } + } + return true; +} +static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedPath *parent, Expr *expr) +{ + assert(expr->expr_kind == EXPR_SUBSCRIPT); + DesignatedPath *path = sema_analyse_init_path(context, parent, expr->subscript_expr.expr); + if (!path) return NULL; + + Type *type = path->type; + if (type->canonical->type_kind == TYPE_POINTER) + { + SEMA_ERROR(expr, "It's not possible to subscript a pointer field in a designated initializer."); + return false; + } + + Expr *index = expr->subscript_expr.index; + Type *inner_type = type_get_indexed_type(type); + if (!inner_type) + { + SEMA_ERROR(expr, "Not possible to index a value of type '%s'.", type_to_error_string(type)); + return false; + } + if (!sema_analyse_expr(context, type_isize, index)) return false; + + // Unless we already have type_usize, cast to type_isize; + if (!expr_cast_to_index(index)) return false; + + // Check range + if (!expr_check_index_in_range(type->canonical, index)) return false; + + DesignatedPath *sub_path = CALLOCS(DesignatedPath); + path->sub_path = sub_path; + sub_path->type = inner_type; + sub_path->kind = DESIGNATED_SUBSCRIPT; + sub_path->index_expr = index; + return sub_path; } -static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr) +static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *parent, Expr *expr) { switch (expr->expr_kind) { case EXPR_ACCESS: - return sema_analyse_init_access(context, strukt, expr); + return sema_analyse_init_access(context, parent, expr); case EXPR_IDENTIFIER: - return sema_analyse_init_identifier(context, strukt, expr); + return sema_analyse_init_identifier_string(context, parent, expr->identifier_expr.identifier); case EXPR_SUBSCRIPT: - return sema_analyse_init_subscript(context, strukt, expr); + return sema_analyse_init_subscript(context, parent, expr); default: return NULL; } } -static bool sema_expr_analyse_struct_designated_initializer(Context *context, Decl *assigned, Expr *initializer) +/** + * Recursively find a node in a declaration. + * @return NULL if it wasn't found, otherwise the member. + */ +DesignatedInitializer *find_initializer(Decl *decl, DesignatedInitializer *initializer, const char* name) +{ + Decl** compare_members = decl->strukt.members; + VECEACH(compare_members, i) + { + Decl *member = compare_members[i]; + if (!member->name) + { + DesignatedInitializer *sub_initializer = initializer->initializers[i]; + DesignatedInitializer *found = find_initializer(member, sub_initializer, name); + if (found) return found; + } + else if (member->name == name) return initializer; + } + return NULL; +} + + +static bool sema_expr_analyse_struct_designated_initializer(Context *context, Type *assigned, Expr *initializer) { Expr **init_expressions = initializer->expr_initializer.initializer_expr; @@ -635,15 +754,20 @@ static bool sema_expr_analyse_struct_designated_initializer(Context *context, De SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here."); return false; } - Expr *path = expr->binary_expr.left; - if (!sema_analyse_init_path(context, assigned, path)) + Expr *init_expr = expr->binary_expr.left; + DesignatedPath path = { .type = assigned }; + DesignatedPath *last_path = sema_analyse_init_path(context, &path, init_expr); + if (!last_path) { - SEMA_ERROR(path, "This is not a valid member of '%s'.", type_to_error_string(assigned->type)); + SEMA_ERROR(expr, "This is not a valid member of '%s'.", type_to_error_string(assigned)); return false; } Expr *value = expr->binary_expr.right; - if (!sema_analyse_expr_of_required_type(context, path->type, value)) return false; - expr->type = path->type; + if (!sema_analyse_expr_of_required_type(context, last_path->type, value)) return false; + expr->expr_kind = EXPR_DESIGNATED_INITIALIZER; + expr->designated_init_expr.path = path.sub_path; + expr->designated_init_expr.value = value; + expr->resolve_status = RESOLVE_DONE; } initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED; return true; @@ -702,7 +826,7 @@ static inline bool sema_expr_analyse_struct_initializer(Context *context, Type * // this means that in this case we're actually not resolving macros here. if (init_expressions[0]->expr_kind == EXPR_BINARY && init_expressions[0]->binary_expr.operator == BINARYOP_ASSIGN) { - return sema_expr_analyse_struct_designated_initializer(context, assigned->decl, expr); + return sema_expr_analyse_struct_designated_initializer(context, assigned, expr); } // 3. Otherwise use the plain initializer. @@ -718,10 +842,7 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to { case TYPE_STRUCT: case TYPE_UNION: - if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer(context, - assigned, - expr); - break; + return sema_expr_analyse_struct_initializer(context, assigned, expr); case TYPE_ARRAY: TODO case TYPE_VARARRAY: @@ -2075,6 +2196,13 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex Expr *expr = expr_shallow_copy(source_expr); switch (source_expr->expr_kind) { + case EXPR_DESIGNATED_INITIALIZER: + // Created during semantic analysis + UNREACHABLE + case EXPR_RANGE: + EXPR_COPY(expr->range_expr.left); + EXPR_COPY(expr->range_expr.right); + return expr; case EXPR_EXPR_BLOCK: ast_copy_list_from_macro(context, macro, &expr->expr_block.stmts); return expr; @@ -2522,12 +2650,20 @@ EXIT: return success; } +static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *expr) +{ + TODO +} + static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr) { switch (expr->expr_kind) { case EXPR_POISONED: return false; + case EXPR_DESIGNATED_INITIALIZER: + // Created during semantic analysis + UNREACHABLE case EXPR_SCOPED_EXPR: UNREACHABLE case EXPR_EXPR_BLOCK: @@ -2536,6 +2672,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * return sema_expr_analyse_macro_expr(context, to, expr); case EXPR_TRY: return sema_expr_analyse_try(context, to, expr); + case EXPR_RANGE: + return sema_expr_analyse_range(context, to, expr); case EXPR_CONST: return true; case EXPR_BINARY: diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 91d39fa5a..b72ad59d8 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -92,6 +92,13 @@ void sema_analysis_pass_conditional_compilation(Context *context) DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); } +static inline bool analyse_func_body(Context *context, Decl *decl) +{ + if (!decl->func.body) return true; + if (!sema_analyse_function_body(context, decl)) return decl_poison(decl); + return true; +} + void sema_analysis_pass_decls(Context *context) { DEBUG_LOG("Pass: Decl analysis %s", context->file->name); @@ -119,5 +126,14 @@ void sema_analysis_pass_decls(Context *context) { sema_analyse_decl(context, context->functions[i]); } + VECEACH(context->struct_functions, i) + { + analyse_func_body(context, context->struct_functions[i]); + } + VECEACH(context->functions, i) + { + analyse_func_body(context, context->functions[i]); + } + DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); } diff --git a/src/compiler/types.c b/src/compiler/types.c index cdcc088cd..3153da554 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -334,6 +334,27 @@ Type *type_get_meta(Type *meta_type) return type_generate_meta(meta_type, false); } +Type *type_get_indexed_type(Type *type) +{ + switch (type->type_kind) + { + case TYPE_POINTER: + return type->pointer; + case TYPE_VARARRAY: + case TYPE_ARRAY: + case TYPE_SUBARRAY: + return type->array.base; + case TYPE_STRING: + return type_char; + default: + break; + } + Type *canonical = type->canonical; + if (canonical != type) return type_get_indexed_type(type); + return NULL; + +} + Type *type_create_array(Type *arr_type, uint64_t len, bool canonical) { @@ -376,7 +397,7 @@ Type *type_create_array(Type *arr_type, uint64_t len, bool canonical) } Type *array = type_new(TYPE_ARRAY, strformat("%s[%llu]", arr_type->name, len)); array->array.base = arr_type; - array->array.len = 0; + array->array.len = len; if (arr_type->canonical == arr_type) { array->canonical = array;