diff --git a/resources/testfragments/bigint.c3 b/resources/testfragments/bigint.c3 index 28fabcff2..cfa8174a7 100644 --- a/resources/testfragments/bigint.c3 +++ b/resources/testfragments/bigint.c3 @@ -1,6 +1,6 @@ module bigint; -macro @max(a, b) +macro max(a, b) { return a > b ? a : b; } @@ -8,12 +8,12 @@ macro @max(a, b) // Horribly bad implementation of BigInt with add/sub. public struct BigInt @opaque { - byte& number; + byte* number; uint length; char sign; } -public func void BigInt.init(BigInt& bigInt) +public func void BigInt.init(BigInt* bigInt) { bigInt.number = malloc(1); bigInt.number[0] = 0; @@ -21,7 +21,7 @@ public func void BigInt.init(BigInt& bigInt) bigInt.sign = 1; } -public func void BigInt.initFromString(BigInt& bigInt, char& str) +public func void BigInt.initFromString(BigInt* bigInt, char* str) { uint size = strlen(str); bigInt.sign = 1; @@ -46,14 +46,7 @@ public func void BigInt.initFromString(BigInt& bigInt, char& str) bigInt.length = size; } -public func BigInt& BigInt.newFromString(char& str) -{ - BigInt& bigInt = malloc(sizeof(BigInt)); - bigInt.initFromString(str); - return bigInt; -} - -public func void BigInt.copyTo(BigInt& source, BigInt& target) +public func void BigInt.copyTo(BigInt* source, BigInt* target) { target.number = realloc(target.number, source.length); target.sign = source.sign; @@ -61,12 +54,12 @@ public func void BigInt.copyTo(BigInt& source, BigInt& target) for (uint i = 0; i < target.length; i++) target.number[i] = source.number[i]; } -public func void BigInt.destroy(BigInt& bigInt) +public func void BigInt.destroy(BigInt* bigInt) { free(bigInt.number); } -func void BigInt.addIgnoreSign(BigInt& a, BigInt& b, BigInt& result) +func void BigInt.addIgnoreSign(BigInt* a, BigInt* b, BigInt* result) { uint length = @max(a.length, b.length) + 1; byte* res = malloc(length); @@ -105,7 +98,7 @@ func void BigInt.addIgnoreSign(BigInt& a, BigInt& b, BigInt& result) result.length = length; } -public func void BigInt.getMaxVal(BigInt &bigInt, uint& pos, int& val) +public func void BigInt.getMaxVal(BigInt* bigInt, uint* pos, int* val) { for (uint i = bigInt.length; i > 0; i++) { @@ -120,7 +113,7 @@ public func void BigInt.getMaxVal(BigInt &bigInt, uint& pos, int& val) *val = 0; } -public func char BigInt.compare(BigInt& a, BigInt& b) +public func char BigInt.compare(BigInt* a, BigInt* b) { if (a.sign != b.sign) return a.sign; byte aMax; @@ -137,7 +130,7 @@ public func char BigInt.compare(BigInt& a, BigInt& b) return 0; } -public func char BigInt.compareNoSign(BigInt& a, BigInt& b) +public func char BigInt.compareNoSign(BigInt* a, BigInt* b) { byte aMax; uint aMaxPos; @@ -153,13 +146,13 @@ public func char BigInt.compareNoSign(BigInt& a, BigInt& b) return 0; } -func void BigInt.subIgnoreSign(BigInt& a, BigInt& b, BigInt& result) +func void BigInt.subIgnoreSign(BigInt* a, BigInt* b, BigInt* result) { uint length = @max(a.length, b.length); - byte& res = malloc(length); + byte* res = malloc(length); - BigInt& x; - BigInt& y; + BigInt* x; + BigInt* y; if (a.compareNoSign(b) < 0) { result.sign = -1; @@ -194,7 +187,7 @@ func void BigInt.subIgnoreSign(BigInt& a, BigInt& b, BigInt& result) result.length = length; } -public func void BigInt.add(BigInt& a, BigInt& b, BigInt& result) +public func void BigInt.add(BigInt* a, BigInt* b, BigInt* result) { if (a.sign == b.sign) { @@ -234,7 +227,7 @@ public func char* BigInt.toCharArray(BigInt* bigInt) return out; } -public func void BigInt.print(BigInt& bigInt) +public func void BigInt.print(BigInt* bigInt) { char* chars = bigInt.toCharArray(); puts(chars); @@ -251,7 +244,7 @@ public func void BigInt.fprint(BigInt* bigInt, FILE* file) }*/ -public func int main(int size, char*& args) +public func int main(int size, char** args) { BigInt minus2; BigInt minus1; diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 641e6d345..50262c3ff 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -943,6 +943,37 @@ func int eokf(int x) return x * x + 1; } +func void Big.init(Big* big) +{ + big.x = 1; + big.y = 2; + big.z = 3; +} +func void Big.mult(Big* big, int x) +{ + big.x *= x; + big.y *= x; + big.z *= x; +} + +struct Bork +{ + Big x; + Big y; +} +func void testMethodFunctions() +{ + Big b; + b.init(); + printf("%d %d %d\n", b.x, b.y, b.z); + b.mult(3); + printf("%d %d %d\n", b.x, b.y, b.z); + Bork x; + x.x.init(); + x.x.mult(4); + printf("%d %d %d\n", x.x.x, x.x.y, x.x.z); +} + func int main(int x) { printf("Helo!\n"); @@ -958,6 +989,7 @@ func int main(int x) testType(); testExprBlock(); testFuncPointer(); + testMethodFunctions(); int efd = 9; uint fefoek = 1; printf("Helo: %d\n", efd + cast(fefoek, int)); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 42bc37ec6..caccabdda 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -949,7 +949,7 @@ typedef struct _Context Decl **error_types; Decl **types; Decl **functions; - Decl **struct_functions; + Decl **method_functions; Decl **vars; Decl **ct_ifs; Ast **defers; diff --git a/src/compiler/context.c b/src/compiler/context.c index e04f9902d..82bfba3eb 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -96,7 +96,7 @@ void context_register_global_decl(Context *context, Decl *decl) case DECL_FUNC: if (decl->func.type_parent) { - vec_add(context->struct_functions, decl); + vec_add(context->method_functions, decl); // TODO set name return; } diff --git a/src/compiler/diagnostics.c b/src/compiler/diagnostics.c index 3de6b778c..cf07f1aa0 100644 --- a/src/compiler/diagnostics.c +++ b/src/compiler/diagnostics.c @@ -42,6 +42,7 @@ static void print_error(SourceRange source_range, const char *message, PrintType } } size_t lines_in_file = vec_size(position.file->lines); + const char *start = NULL; for (unsigned i = LINES_SHOWN; i > 0; i--) { if (position.line < i) continue; @@ -51,7 +52,8 @@ static void print_error(SourceRange source_range, const char *message, PrintType SourceLoc line_end = line_number == lines_in_file ? position.file->end_id : position.file->lines[line_number]; uint32_t line_len = line_end - line_start - 1; - eprintf(number_buffer, line_number, line_len, position.file->contents + line_start - position.file->start_id); + start = position.file->contents + line_start - position.file->start_id; + eprintf(number_buffer, line_number, line_len, start); } eprintf(" "); for (unsigned i = 0; i < max_line_length; i++) @@ -60,7 +62,7 @@ static void print_error(SourceRange source_range, const char *message, PrintType } for (unsigned i = 0; i < position.col - 1; i++) { - if (position.start[i] == '\t') + if (start[i] == '\t') { eprintf("\t"); } @@ -78,13 +80,13 @@ static void print_error(SourceRange source_range, const char *message, PrintType switch (print_type) { case PRINT_TYPE_ERROR: - eprintf("(%s:%d) Error: %s\n", position.file->name, position.line, message); + eprintf("(%s:%d) Error: %s\n\n", position.file->name, position.line, message); break; case PRINT_TYPE_PREV: - eprintf("(%s:%d) %s\n", position.file->name, position.line, message); + eprintf("(%s:%d) %s\n\n", position.file->name, position.line, message); break; case PRINT_TYPE_WARN: - eprintf("(%s:%d) Warning: %s\n", position.file->name, position.line, message); + eprintf("(%s:%d) Warning: %s\n\n", position.file->name, position.line, message); break; default: UNREACHABLE diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 0e7a6542c..3168b1b41 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -358,6 +358,10 @@ void llvm_codegen(Context *context) { gencontext_emit_extern_decl(&gen_context, context->external_symbol_list[i]); } + VECEACH(context->method_functions, i) + { + gencontext_emit_function_decl(&gen_context, context->method_functions[i]); + } VECEACH(context->functions, i) { gencontext_emit_function_decl(&gen_context, context->functions[i]); @@ -379,7 +383,11 @@ void llvm_codegen(Context *context) Decl *decl = context->functions[i]; if (decl->func.body) gencontext_emit_function_body(&gen_context, decl); } - + VECEACH(context->method_functions, i) + { + Decl *decl = context->method_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 41147234e..6d48a411e 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1273,6 +1273,13 @@ LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr) func = gencontext_emit_expr(context, expr->call_expr.function); func_type = llvm_type(expr->call_expr.function->type->canonical->pointer); } + else if (expr->call_expr.is_struct_function) + { + Decl *function_decl = expr->call_expr.function->access_expr.ref; + signature = &function_decl->func.function_signature; + func = function_decl->ref; + func_type = llvm_type(function_decl->type); + } else { Decl *function_decl = expr->call_expr.function->identifier_expr.decl; diff --git a/src/compiler/parser.c b/src/compiler/parser.c index b3aff9768..6deb8349f 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -1535,7 +1535,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit func->name = context->tok.string; func->name_span = context->tok.span; advance_and_verify(context, TOKEN_IDENT); - + RANGE_EXTEND_PREV(func); if (!parse_opt_parameter_type_list(context, visibility, &(func->func.function_signature), is_interface)) return poisoned_decl; if (!parse_opt_throw_declaration(context, visibility, &(func->func.function_signature))) return poisoned_decl; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 0386efc64..108d8f18a 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -290,7 +290,7 @@ static inline int find_index_of_named_parameter(Decl** func_params, Expr *expr) return -1; } -static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionSignature *signature, Expr *expr, Decl *decl, Type *to) +static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionSignature *signature, Expr *expr, Decl *decl, Type *to, Expr *struct_var) { Decl **func_params = signature->params; expr->call_expr.throw_info = CALLOCS(ThrowInfo); @@ -316,8 +316,9 @@ static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionS expr->call_expr.throw_info, signature->throws)); } } + unsigned struct_args = struct_var == NULL ? 0 : 1; unsigned func_param_count = vec_size(func_params); - unsigned num_args = vec_size(args); + unsigned num_args = vec_size(args) + struct_args; unsigned entries_needed = func_param_count > num_args ? func_param_count : num_args; Expr **actual_args = VECNEW(Expr*, entries_needed); for (unsigned i = 0; i < entries_needed; i++) vec_add(actual_args, NULL); @@ -326,9 +327,10 @@ static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionS for (unsigned i = 0; i < num_args; i++) { - Expr *arg = args[i]; + bool is_implicit = i < struct_args; + Expr *arg = is_implicit ? struct_var : args[i - struct_args]; // Named parameters - if (arg->expr_kind == EXPR_BINARY && arg->binary_expr.operator == BINARYOP_ASSIGN) + if (!is_implicit && arg->expr_kind == EXPR_BINARY && arg->binary_expr.operator == BINARYOP_ASSIGN) { uses_named_parameters = true; int index = find_index_of_named_parameter(func_params, arg->binary_expr.left); @@ -394,7 +396,7 @@ static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr * func_ptr_type->pointer->func.signature, expr, func_ptr_type->decl, - to); + to, NULL); } static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO }; @@ -463,10 +465,10 @@ static inline Type *unify_returns(Context *context, Type *to) return to; } -static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl) +static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl, Expr *struct_var) { expr->call_expr.is_pointer_call = false; - return sema_expr_analyse_func_invocation(context, &decl->func.function_signature, expr, decl, to); + return sema_expr_analyse_func_invocation(context, &decl->func.function_signature, expr, decl, to, struct_var); } static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr) @@ -474,6 +476,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr Expr *func_expr = expr->call_expr.function; if (!sema_analyse_expr_may_be_function(context, func_expr)) return false; Decl *decl; + Expr *struct_var = NULL; switch (func_expr->expr_kind) { case EXPR_TYPE_ACCESS: @@ -482,6 +485,19 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr case EXPR_IDENTIFIER: decl = func_expr->identifier_expr.decl; break; + case EXPR_ACCESS: + decl = func_expr->access_expr.ref; + if (decl->decl_kind == DECL_FUNC) + { + expr->call_expr.is_struct_function = true; + struct_var = expr_new(EXPR_UNARY, func_expr->access_expr.parent->span); + struct_var->unary_expr.expr = func_expr->access_expr.parent; + struct_var->unary_expr.operator = UNARYOP_ADDR; + struct_var->resolve_status = RESOLVE_DONE; + assert(func_expr->access_expr.parent->resolve_status == RESOLVE_DONE); + struct_var->type = type_get_ptr(struct_var->unary_expr.expr->type); + } + break; default: TODO } @@ -490,7 +506,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr case DECL_VAR: return sema_expr_analyse_var_call(context, to, expr, decl); case DECL_FUNC: - return sema_expr_analyse_func_call(context, to, expr, decl); + return sema_expr_analyse_func_call(context, to, expr, decl, struct_var); case DECL_MACRO: SEMA_ERROR(expr, "Macro calls must be preceeded by '@'."); return false; @@ -633,11 +649,20 @@ static inline bool sema_expr_analyse_method_function(Context *context, Expr *exp Decl *function = decl->method_functions[i]; if (function->name == name) { - // TODO + expr->access_expr.ref = function; + expr->type = function->type; return true; } } - SEMA_ERROR(expr, "Cannot find method function '%s.%s'", decl->name, name); + + if (decl_is_struct_type(decl)) + { + SEMA_ERROR(expr, "There is no element nor method function '%s.%s'.", decl->name, name); + } + else + { + SEMA_ERROR(expr, "Cannot find method function '%s.%s'", decl->name, name); + } return false; } @@ -701,7 +726,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string); if (!member) { - SEMA_TOKEN_ERROR(expr->access_expr.sub_element, "There is no element '%s.%s'.", decl->name, expr->access_expr.sub_element.string); + return sema_expr_analyse_method_function(context, expr, decl, is_pointer); return false; } if (is_pointer) diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index b72ad59d8..719b82b73 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -114,9 +114,9 @@ void sema_analysis_pass_decls(Context *context) { sema_analyse_decl(context, context->error_types[i]); } - VECEACH(context->struct_functions, i) + VECEACH(context->method_functions, i) { - sema_analyse_decl(context, context->struct_functions[i]); + sema_analyse_decl(context, context->method_functions[i]); } VECEACH(context->vars, i) { @@ -126,9 +126,9 @@ void sema_analysis_pass_decls(Context *context) { sema_analyse_decl(context, context->functions[i]); } - VECEACH(context->struct_functions, i) + VECEACH(context->method_functions, i) { - analyse_func_body(context, context->struct_functions[i]); + analyse_func_body(context, context->method_functions[i]); } VECEACH(context->functions, i) {