From e04213d420b5e7fdf3dee83c4b173ca1d36fe356 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 11 Sep 2019 23:20:37 +0200 Subject: [PATCH] Some limited calls now working correctly. --- resources/testfragments/compiletest.c3 | 19 +++++- src/compiler/casts.c | 22 +++---- src/compiler/codegen.c | 86 ++++++++++++++++++++++---- src/compiler/compiler_internal.h | 1 + src/compiler/context.c | 24 +++++++ src/compiler/enums.h | 2 +- src/compiler/expr_analysis.c | 53 +++++++++++++++- src/compiler/lexer.c | 45 +++++++++----- src/compiler/parser.c | 5 +- src/compiler/semantic_analyser.c | 38 ++++++------ 10 files changed, 230 insertions(+), 65 deletions(-) diff --git a/resources/testfragments/compiletest.c3 b/resources/testfragments/compiletest.c3 index bb6130e95..65edbec5d 100644 --- a/resources/testfragments/compiletest.c3 +++ b/resources/testfragments/compiletest.c3 @@ -3,6 +3,8 @@ module foo; int oefk = 1; int bob = 'HELO'; +typedef Foo* as Bob; + struct Foo { int i; @@ -13,6 +15,7 @@ struct Bar { Foo foo; Foo* fooPtr; + Bob helo; struct bar { int a; @@ -44,10 +47,17 @@ $if (1) } +struct Simple +{ + int i; + double j; +} func int boo() { Zed zfe; - //zfe = { 1, 2 }; + Simple s = { 1 }; + s = { 2 }; + //Simple x = { j = 1 }; //Zed zfed = { 1 }; int eok = 0; { @@ -123,6 +133,10 @@ func int boo() return 1; } +func int helo(int i) +{ + return i + 1; +} func void while_test() { @@ -156,5 +170,6 @@ func void test() func void main() { - + helo(2); + printf("Helo\n"); } \ No newline at end of file diff --git a/src/compiler/casts.c b/src/compiler/casts.c index 45ac4a78e..9dd77b4e3 100644 --- a/src/compiler/casts.c +++ b/src/compiler/casts.c @@ -97,7 +97,7 @@ bool ptpt(Expr* left, Type *canonical, Type *type, CastType cast_type) if (cast_type != CAST_TYPE_EXPLICIT && !may_implicitly_cast_ptr_to_ptr(to_cast_type, canonical)) { - sema_type_mismatch(left, type, cast_type); + return sema_type_mismatch(left, type, cast_type); } if (left->expr_kind == EXPR_CONST) { @@ -109,21 +109,17 @@ bool ptpt(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool ptst(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool stpt(Expr* left, Type *canonical, Type *type, CastType cast_type) { - TODO - if (left->expr_kind == EXPR_CONST) + if (canonical->base != type_char && canonical->base != type_byte) { - assert(left->const_expr.type == CONST_INT && type_is_unsigned(left->type->canonical)); - assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64); - left->const_expr.f = left->const_expr.i; - left->type = type; - return true; + return sema_type_mismatch(left, type, cast_type); } - insert_cast(left, CAST_UIFP, canonical); + left->type = canonical; return true; } + bool boxi(Expr* left, Type *canonical, Type *type, CastType cast_type) { if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); @@ -479,7 +475,7 @@ bool usbo(Expr* left, Type *canonical, Type *type, CastType cast_type) } CastFunc BUILTIN_CONVERSION[19][19] = { -//to bool, char, short, int, long, ctint, byte, ushort, int, ulong,ctuint, float,double,ctreal, user, ptr, str, arr, varr // from: +//to bool, char, short, int, long, ctint, byte, ushort, uint, ulong,ctuint, float,double,ctreal, user, ptr, str, arr, varr // from: { &erro, &boxi, &boxi, &boxi, &boxi, &erro, &boxi, &boxi, &boxi, &boxi, &erro, &bofp, &bofp, &erro, &erro, &erro, &erro, &erro, &erro }, // bool { &xibo, &erro, &sisi, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &erro, &erro, &erro, &erro }, // char { &xibo, &sisi, &erro, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &erro, &erro, &erro, &erro }, // short @@ -495,8 +491,8 @@ CastFunc BUILTIN_CONVERSION[19][19] = { { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // double { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // fxx { &usbo, &ussi, &ussi, &ussi, &ussi, &erro, &usui, &usui, &usui, &usui, &erro, &erro, &erro, &erro, &usus, &erro, &erro, &erro, &erro }, // user - { &ptbo, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &erro, &erro, &erro, &erro, &ptpt, &ptst, &erro, &ptva }, // ptr - { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // str + { &ptbo, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &erro, &erro, &erro, &erro, &ptpt, &erro, &erro, &ptva }, // ptr + { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &stpt, &erro, &erro, &erro }, // str { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // arr { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // varr }; diff --git a/src/compiler/codegen.c b/src/compiler/codegen.c index 7b242efcf..c5b847946 100644 --- a/src/compiler/codegen.c +++ b/src/compiler/codegen.c @@ -123,10 +123,38 @@ static inline void codegen_compound_stmt(Context *context, Ast *ast, int indent) static inline int codegen_emit_call_expr(Context *context, Expr *expr, int indent) { // TODO properly + int *params = NULL; + VECEACH(expr->call_expr.arguments, i) + { + vec_add(params, codegen_emit_expr(context, expr->call_expr.arguments[i], indent)); + } INDENT(); - PRINTTYPE(expr->type); - Decl *func = expr->call_expr.function->identifier_expr.decl; - PRINTF(" _%d = %s__%s();\n", ++context->unique_index, func->module->name, func->name.string); + bool has_return = expr->type->type_kind != TYPE_VOID; + if (has_return) PRINTTYPE(expr->type); + if (expr->call_expr.function->expr_kind == EXPR_IDENTIFIER) + { + Decl *func = expr->call_expr.function->identifier_expr.decl; + if (has_return) PRINTF(" _%d = ", ++context->unique_index); + if (strcmp(func->name.string, "printf") == 0) + { + PRINTF("%s", func->name.string); + } + else + { + PRINTF("%s__%s", func->module->name, func->name.string); + } + } + else + { + TODO + } + PRINTF("("); + VECEACH(params, i) + { + if (i != 0) PRINTF(", "); + PRINTF("_%d", params[i]); + } + PRINTF(");\n"); return context->unique_index; } @@ -180,16 +208,27 @@ static inline void codegen_emit_const_expr_raw(Context *context, Expr *expr) case TYPE_F32: case TYPE_F64: case TYPE_FXX: - assert(expr->const_expr.type == CONST_INT); + assert(expr->const_expr.type == CONST_FLOAT); PRINTF("("); PRINTTYPE(canonical); PRINTF(")"); PRINTF("%Lf", expr->const_expr.f); return; case TYPE_POINTER: - PRINTF("(("); - PRINTTYPE(canonical); - PRINTF("0)"); + if (expr->const_expr.type == CONST_NIL) + { + PRINTF("(("); + PRINTTYPE(canonical); + PRINTF(")0)"); + } + else + { + assert(expr->const_expr.type == CONST_STRING); + PRINTF("(("); + PRINTTYPE(canonical); + + PRINTF(")%.*s)", expr->const_expr.string.len, expr->const_expr.string.chars); + } return; case TYPE_STRING: TODO @@ -323,10 +362,23 @@ static int codegen_emit_post_unary_expr(Context *context, Expr *expr, int indent } } -static void codegen_print_ltype(Context *context, Expr *expr, int indent) +static int codegen_emit_initializer_list(Context *context, Expr *expr, int indent) { - + int index = ++context->unique_index; + INDENT(); + PRINTTYPE(expr->type); + PRINTF(" _%d;\n", index); + Decl *decl = expr->type->canonical->decl; + // Todo, fully clear. + VECEACH(expr->initializer_expr, i) + { + int index2 = codegen_emit_expr(context, expr->initializer_expr[i], indent); + INDENT(); + PRINTF("_%d.%s = _%d;\n", index, decl->strukt.members[i]->name.string, index2); + } + return index; } + static int codegen_emit_unary_expr(Context *context, Expr *expr, int indent) { int index = ++context->unique_index; @@ -398,6 +450,8 @@ static int codegen_emit_expr(Context *context, Expr *expr, int indent) return codegen_emit_post_unary_expr(context, expr, indent); case EXPR_UNARY: return codegen_emit_unary_expr(context, expr, indent); + case EXPR_INITIALIZER_LIST: + return codegen_emit_initializer_list(context, expr, indent); default: TODO } @@ -730,12 +784,21 @@ static inline void codegen_func_decl(Context *context, Decl *decl) print_typename(context->codegen_output, decl->func.function_signature.rtype); if (strcmp("main", decl->name.string) == 0) { - PRINTF(" %s()", decl->name.string); + PRINTF(" %s(", decl->name.string); } else { - PRINTF(" %s__%s()", decl->module->name, decl->name.string); + PRINTF(" %s__%s(", decl->module->name, decl->name.string); } + Decl **params = decl->func.function_signature.params; + VECEACH(params, i) + { + if (i != 0) PRINTF(", "); + Decl *param = params[i]; + PRINTTYPE(param->var.type); + PRINTF(" _%d_%s", param->var.id, param->name.string); + } + PRINTF(")"); } static inline void codegen_func(Context *context, Decl *decl) @@ -750,6 +813,7 @@ static inline void codegen_func(Context *context, Decl *decl) { Decl *var = vars[i]; assert(var->decl_kind == DECL_VAR); + if (var->var.kind == VARDECL_PARAM) continue; Type *current = var->var.type->canonical; if (type == current) { diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index a83af23ea..73cf98189 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -723,6 +723,7 @@ bool context_set_module(Context *context, Token module_name, Token *generic_para void context_print_ast(Context *context, FILE *file); Decl *context_find_ident(Context *context, const char *symbol); void context_add_header_decl(Context *context, Decl *decl); +bool context_add_local(Context *context, Decl *decl); Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility); Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility); diff --git a/src/compiler/context.c b/src/compiler/context.c index 7663a20cc..10181732b 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -26,6 +26,30 @@ void context_add_header_decl(Context *context, Decl *decl) vec_add(context->header_declarations, decl); } +bool context_add_local(Context *context, Decl *decl) +{ + Decl *other = context_find_ident(context, decl->name.string); + if (other) + { + sema_shadow_error(decl, other); + decl_poison(decl); + decl_poison(other); + return false; + } + Decl *** vars = &context->active_function_for_analysis->func.annotations->vars; + unsigned num_vars = vec_size(*vars); + if (num_vars == MAX_LOCALS - 1 || context->last_local == &context->locals[MAX_LOCALS - 1]) + { + SEMA_ERROR(decl->name, "Reached the maximum number of locals."); + return false; + } + decl->var.id = num_vars; + *vars = VECADD(*vars, decl); + context->last_local[0] = decl; + context->last_local++; + return true; +} + static inline bool create_module_or_check_name(Context *context, Token module_name) { context->module_name = module_name; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index d61030ec9..23f2de6ba 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -443,7 +443,6 @@ typedef enum typedef enum { TYPE_POISONED, - TYPE_USER_DEFINED, TYPE_VOID, TYPE_BOOL, TYPE_I8, @@ -459,6 +458,7 @@ typedef enum TYPE_F32, TYPE_F64, TYPE_FXX, + TYPE_USER_DEFINED, TYPE_POINTER, TYPE_STRING, TYPE_ARRAY, diff --git a/src/compiler/expr_analysis.c b/src/compiler/expr_analysis.c index 9dd47f117..38f2e77f4 100644 --- a/src/compiler/expr_analysis.c +++ b/src/compiler/expr_analysis.c @@ -144,9 +144,56 @@ static inline bool sema_expr_analyse_method_ref(Context *context, Expr *expr) TODO } -static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Expr *expr) +static inline Decl *decl_find_by_name(Decl** decls, const char *name) { - TODO + VECEACH(decls, i) + { + if (decls[i]->name.string == name) return decls[i]; + } + return NULL; +} +static inline bool expr_may_be_struct_field_decl(Expr *maybe_binary) +{ + if (maybe_binary->expr_kind != EXPR_BINARY) return false; + if (maybe_binary->binary_expr.operator != TOKEN_EQ) return false; + Expr *expr = maybe_binary->binary_expr.left; + while (1) + { + if (expr->expr_kind == EXPR_IDENTIFIER) return true; + if (expr->expr_kind != EXPR_ACCESS) return false; + expr = expr->access_expr.parent; + } +} + +static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Type *assigned, Expr *expr) +{ + Decl **members = assigned->decl->strukt.members; + unsigned size = vec_size(members); + VECEACH(expr->initializer_expr, i) + { + Expr *field = expr->initializer_expr[i]; + Decl *decl; + if (expr_may_be_struct_field_decl(field)) + { + if (field->expr_kind == EXPR_IDENTIFIER) + { + decl = decl_find_by_name(members, field->identifier_expr.identifier.string); + } + TODO + } + else + { + if (i >= size) + { + SEMA_ERROR(field->loc, "Too many elements in initializer"); + return false; + } + decl = members[i]; + } + if (!cast(field, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + } + expr->type = assigned; + return true; } static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *expr) { @@ -156,7 +203,7 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *ex switch (assigned->type_kind) { case TYPE_USER_DEFINED: - if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer_list(context, expr); + if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer_list(context, assigned, expr); break; case TYPE_ARRAY: TODO diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index cf4c3512a..1ec1b5baa 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -4,7 +4,6 @@ #include "compiler_internal.h" - typedef struct { bool lexer_init_complete; @@ -413,26 +412,40 @@ static inline Token scan_digit(void) static inline Token scan_char() { - next(); // Consume "'" - // Handle escaped char, also handle hex code. - if (next() == '\\') + int width = 0; + char c; + while ((c = next()) != '\'') { - // Escape seq? We don't support octal. - if (next() == 'x') + if (c == '\0' || c == '\n') return error_token("Character literal did not terminate."); + width++; + // Was this an escape? + if (c == '\\') { - for (int i = 0; i < 2; i++) + // Yes, so check if it's hex: + if (next() == 'x') { - if (!is_hex(next())) + // Walk through the two characters. + for (int i = 0; i < 2; i++) { - return error_token( - "An escape sequence starting with " - "'\\x' needs to be followed by " - "a two digit hexadecimal number."); + if (!is_hex(next())) + { + return error_token( + "An escape sequence starting with " + "'\\x' needs to be followed by " + "a two digit hexadecimal number."); + } } } } } - if (next() != '\'') return error_token("The character only consist of a single character, did you want to use \"\" instead?"); + if (width == 0) + { + return error_token("The character literal was empty."); + } + if (width > 2 && width != 4 && width != 8) + { + error_token("Character literals may only be 1, 2 or 8 characters wide."); + } return make_token(TOKEN_INTEGER); } @@ -668,7 +681,12 @@ Token lexer_scan_token(void) backtrack(); return is_digit(c) ? scan_digit() : scan_ident(); } + if (c < 0) + { + return error_token("The 0%x character may not be placed outside of a string or comment, did you perhaps forget a \" somewhere?", (uint8_t)c); + } return error_token("'%c' may not be placed outside of a string or comment, did you perhaps forget a \" somewhere?", c); + } } @@ -686,7 +704,6 @@ void lexer_check_init(void) void lexer_add_file_for_lexing(File *file) { - LOG_FUNC lexer_check_init(); lexer.current_file = file; lexer.file_begin = lexer.current_file->contents; diff --git a/src/compiler/parser.c b/src/compiler/parser.c index c19f5d0da..5b85a21c8 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -2667,15 +2667,16 @@ static Expr *parse_string_literal(Expr *left) Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, tok); expr_string->resolve_status = RESOLVE_DONE; expr_string->type = type_string; - advance_and_verify(TOKEN_STRING); char *str = malloc_arena(tok.span.length + 1); size_t len = tok.span.length; - memcpy(str, tok.start + tok.span.loc, tok.span.length); + memcpy(str, tok.start, tok.span.length); // Just keep chaining if there are multiple parts. + advance_and_verify(TOKEN_STRING); + while (tok.type == TOKEN_STRING) { char *new_string = malloc_arena(len + tok.span.length + 1); diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 1cf4a20b4..9e273dc42 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -273,23 +273,6 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl) { assert(decl->decl_kind == DECL_VAR); if (!sema_resolve_type(context, decl->var.type)) return false; - Decl *other = context_find_ident(context, decl->name.string); - if (other) - { - sema_shadow_error(decl, other); - decl_poison(decl); - decl_poison(other); - return false; - } - Decl *** vars = &context->active_function_for_analysis->func.annotations->vars; - unsigned num_vars = vec_size(*vars); - if (num_vars == MAX_LOCALS - 1 || context->last_local == &context->locals[MAX_LOCALS - 1]) - { - SEMA_ERROR(decl->name, "Reached the maximum number of locals."); - return false; - } - decl->var.id = num_vars; - *vars = VECADD(*vars, decl); if (decl->var.init_expr) { Type *prev_type = context->left_type_in_assignment; @@ -302,8 +285,7 @@ static inline bool sema_analyse_var_decl(Context *context, Decl *decl) return false; } } - context->last_local[0] = decl; - context->last_local++; + if (!context_add_local(context, decl)) return false; return true; } @@ -906,6 +888,11 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func) context->in_volatile_section = 0; func->func.annotations = CALLOCS(*func->func.annotations); context_push_scope(context); + Decl **params = func->func.function_signature.params; + VECEACH(params, i) + { + if (!context_add_local(context, params[i])) return false; + } if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false; if (context->current_scope->exit != EXIT_RETURN && func->func.function_signature.rtype->canonical != type_void) { @@ -1104,6 +1091,19 @@ static inline void sema_process_imports(Context *context) } void sema_analysis(Context *context) { + const char *printf = "printf"; + TokenType t_type = TOKEN_IDENT; + const char *interned = symtab_add(printf, (uint32_t) 6, fnv1a(printf, (uint32_t)6), &t_type); + Decl *decl = decl_new(DECL_FUNC, wrap(interned), VISIBLE_PUBLIC); + Type *type = type_new(TYPE_POINTER); + type->base = type_char; + sema_resolve_type(context, type); + Decl *param = decl_new_var(wrap("str"), type, VARDECL_PARAM, VISIBLE_LOCAL); + + vec_add(decl->func.function_signature.params, param); + decl->func.function_signature.rtype = type_void; + decl->resolve_status = RESOLVE_DONE; + context_register_global_decl(context, decl); sema_process_imports(context); VECEACH(context->ct_ifs, i) {