From 2eb91083a61c3f4373400e0c7de2aa527c255a71 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 29 Aug 2019 17:08:34 +0200 Subject: [PATCH] Refactor type handling, some extremely simple codegen, but mostly work on casts (not finished) --- CMakeLists.txt | 3 +- resources/testfragments/compiletest.c3 | 22 +- resources/testfragments/parsertest.c3 | 4 +- src/build/build_options.c | 4 + src/build/build_options.h | 5 + src/compiler/ast.c | 293 +++----- src/compiler/ast.h | 812 -------------------- src/compiler/bigint.c | 2 +- src/compiler/bigint.h | 2 +- src/compiler/builtins.c | 160 ++++ src/compiler/casts.c | 508 +++++++++++++ src/compiler/codegen.c | 459 ++++++++++++ src/compiler/compiler.c | 17 +- src/compiler/compiler.h | 1 - src/compiler/compiler_common.h | 85 --- src/compiler/compiler_internal.h | 820 ++++++++++++++++++++ src/compiler/const_folding.c | 158 ++++ src/compiler/context.c | 8 +- src/compiler/context.h | 32 - src/compiler/diagnostics.c | 12 +- src/compiler/diagnostics.h | 43 -- src/compiler/enums.h | 525 +++++++++++++ src/compiler/lexer.c | 10 +- src/compiler/lexer.h | 39 - src/compiler/module.c | 8 - src/compiler/parser.c | 329 +++++--- src/compiler/parser.h | 25 - src/compiler/semantic_analyser.c | 999 +++++++++++++++++++++++-- src/compiler/semantic_analyser.h | 17 - src/compiler/source_file.c | 5 +- src/compiler/source_file.h | 11 - src/compiler/symtab.c | 9 +- src/compiler/symtab.h | 30 - src/compiler/tokens.c | 42 +- src/compiler/tokens.h | 188 ----- src/compiler/types.c | 224 ++++++ src/compiler/value.c | 902 ---------------------- src/compiler/value.h | 87 --- src/compiler_tests/tests.c | 7 +- src/main.c | 6 +- src/utils/common.h | 2 + src/utils/file_utils.c | 1 - src/utils/file_utils.h | 4 - src/utils/lib.h | 13 +- src/utils/malloc.h | 8 - 45 files changed, 4194 insertions(+), 2747 deletions(-) delete mode 100644 src/compiler/ast.h create mode 100644 src/compiler/builtins.c create mode 100644 src/compiler/casts.c create mode 100644 src/compiler/codegen.c delete mode 100644 src/compiler/compiler_common.h create mode 100644 src/compiler/compiler_internal.h create mode 100644 src/compiler/const_folding.c delete mode 100644 src/compiler/context.h delete mode 100644 src/compiler/diagnostics.h create mode 100644 src/compiler/enums.h delete mode 100644 src/compiler/lexer.h delete mode 100644 src/compiler/module.c delete mode 100644 src/compiler/parser.h delete mode 100644 src/compiler/semantic_analyser.h delete mode 100644 src/compiler/source_file.h delete mode 100644 src/compiler/symtab.h delete mode 100644 src/compiler/tokens.h create mode 100644 src/compiler/types.c delete mode 100644 src/compiler/value.c delete mode 100644 src/compiler/value.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fdf909d82..58beca7e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ add_executable(c3c src/compiler/source_file.c src/compiler/diagnostics.c src/compiler/ast.c - src/compiler/module.c - src/compiler/value.c src/compiler/value.h src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c) + src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c src/compiler/builtins.c src/compiler/codegen.c src/compiler/const_folding.c src/compiler/enums.h src/compiler/casts.c src/compiler/compiler.h src/compiler/types.c) target_compile_options(c3c PRIVATE -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) diff --git a/resources/testfragments/compiletest.c3 b/resources/testfragments/compiletest.c3 index 8f67c0fd7..ed486e5a1 100644 --- a/resources/testfragments/compiletest.c3 +++ b/resources/testfragments/compiletest.c3 @@ -1,11 +1,25 @@ module foo; +struct Foo +{ + int i; + Bar *x; +} + +struct Bar +{ + Foo foo; + Foo* fooPtr; +} + func void test() { + int i = 1; + int j, k; + int l, m = 0; + int o = 0, p = 3; + short f = -2; + c_int x = 2; return; } -func int test2() -{ - return; -} \ No newline at end of file diff --git a/resources/testfragments/parsertest.c3 b/resources/testfragments/parsertest.c3 index 738ca6d24..1fee37b8c 100644 --- a/resources/testfragments/parsertest.c3 +++ b/resources/testfragments/parsertest.c3 @@ -8,7 +8,6 @@ macro void @foo(int i, $e) $e = 1; printf("Helo"); } - macro @goo(i, $e) { @@ -34,6 +33,7 @@ enum FEok : int { IFEJ } + enum Test { FOO = 1 + 2, @@ -84,7 +84,7 @@ generic boor2(i) case int: return "Helo"; default: - return 1000; + return 10001; } $if ($e > 0) diff --git a/src/build/build_options.c b/src/build/build_options.c index 84c36c936..b86161730 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -264,6 +264,10 @@ void parse_arguments(int argc, const char *argv[]) exit(EXIT_SUCCESS); } + build_options.cshort_size = sizeof(short); + build_options.cint_size = sizeof(int); + build_options.clong_size = sizeof(long); + build_options.clonglong_size = sizeof(long long); build_options.pointer_size = sizeof(void *); build_options.path = "."; build_options.command = COMMAND_MISSING; diff --git a/src/build/build_options.h b/src/build/build_options.h index bd4c72785..195e5ea55 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -82,6 +82,11 @@ typedef struct CompileOption compile_option; DiagnosticsSeverity severity[DIAG_END_SENTINEL]; int pointer_size; + int cshort_size; + int cint_size; + int clong_size; + int clonglong_size; + int clongdouble_size; } BuildOptions; diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 7c6f1a691..0e8455463 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -2,12 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include -#include -#include -#include "ast.h" +#include "compiler_internal.h" -Decl *decl_new_in_module(Module *module, DeclKind decl_kind, Token name, Visibility visibility) +Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility) { assert(name.string); Decl *decl = malloc_arena(sizeof(Decl)); @@ -15,75 +12,34 @@ Decl *decl_new_in_module(Module *module, DeclKind decl_kind, Token name, Visibil decl->decl_kind = decl_kind; decl->name = name; decl->visibility = visibility; - decl->module = module; return decl; } -Type poisoned_type = { .type_kind = TYPE_POISONED }; +Type poisoned_type = { .type_kind = TYPE_POISONED, .resolve_status = RESOLVE_DONE }; -char *type_to_string(Type *type) -{ - switch (type->type_kind) - { - case TYPE_VOID: - return "void"; - case TYPE_UNRESOLVED: - TODO - case TYPE_STRING: - return "string"; - case TYPE_UNRESOLVED_EXPR: - TODO - case TYPE_NIL: - return "nil"; - case TYPE_BUILTIN: - return "TODO"; - default: - TODO - } -} -Type *type_poisoned() -{ - static Type poison = { .type_kind = TYPE_POISONED }; - return &poison; -} -Type *type_new(TypeKind type_kind) -{ - Type *type = malloc_arena(sizeof(Type)); - memset(type, 0, sizeof(Type)); - type->type_kind = type_kind; - return type; -} -Decl *decl_new_self_type(struct _Module *module, Token name, DeclKind decl_type, TypeKind type_kind, Visibility visibility) +Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility) { - Decl *decl = decl_new_in_module(module, decl_type, name, visibility); - Type *type = type_new(type_kind); - type->canonical_type = type; + Decl *decl = decl_new(decl_type, name, visibility); + Type *type = type_new(TYPE_USER_DEFINED); + type->resolve_status = RESOLVE_DONE; + type->canonical = type; type->decl = decl; - decl->type = type; + decl->self_type = type; return decl; } Decl poisoned_decl = { .decl_kind = DECL_POISONED, .resolve_status = RESOLVE_DONE }; -Decl *decl_new_var(struct _Module *module, Token name, Type *type, VarDeclKind kind, Visibility visibility) +Decl *decl_new_var(Token name, Type *type, VarDeclKind kind, Visibility visibility) { - Decl *decl = decl_new_in_module(module, DECL_VAR, name, visibility); + Decl *decl = decl_new(DECL_VAR, name, visibility); decl->var.kind = kind; decl->var.type = type; return decl; } -Decl *decl_new_enum_const(Decl *parent, Token name, DeclKind kind) -{ - Decl *decl = decl_new_in_module(parent->module, DECL_VAR, name, parent->visibility); - decl->decl_kind = kind; - assert(parent->type); - decl->type = parent->type; - return decl; -} - Decl *struct_find_name(Decl *decl, const char* name) { Decl** compare_members = decl->strukt.members; @@ -110,81 +66,23 @@ Expr *expr_new(ExprKind kind, Token start) return expr; } -Expr poisoned_expr = { .expr_kind = EXPR_POISONED }; +Expr poisoned_expr = { .expr_kind = EXPR_POISONED, .resolve_status = RESOLVE_DONE }; -Type type_bool; -Type type_void, type_nil, type_string; -Type type_half, type_float, type_double, type_quad; -Type type_char, type_short, type_int, type_long, type_isize; -Type type_byte, type_ushort, type_uint, type_ulong, type_usize; -Type type_compint, type_compfloat; - -void type_setup(int pointer_size) -{ - type_void = (Type) { .type_kind = TYPE_VOID, .canonical_type = &type_void }; - type_nil = (Type) { .type_kind = TYPE_NIL, .canonical_type = &type_nil }; - type_string = (Type) { .type_kind = TYPE_STRING, .canonical_type = &type_string }; - -#define DEF_TYPE(name, bits, _bytes, type) name = (Type) { .type_kind = TYPE_BUILTIN, .bitsize = bits, .bytes = _bytes, .num_type = type, .canonical_type = &name } - - DEF_TYPE(type_compint, 0, 0, NUMBER_TYPE_SIGNED_INT); - DEF_TYPE(type_compfloat, 0, 0, NUMBER_TYPE_FLOAT); - - DEF_TYPE(type_bool, 1, 8, NUMBER_TYPE_BOOL); - - DEF_TYPE(type_half, 2, 16, NUMBER_TYPE_FLOAT); - DEF_TYPE(type_float, 4, 32, NUMBER_TYPE_FLOAT); - DEF_TYPE(type_double, 8, 64, NUMBER_TYPE_FLOAT); - DEF_TYPE(type_quad, 16, 128, NUMBER_TYPE_FLOAT); - - DEF_TYPE(type_char, 1, 8, NUMBER_TYPE_SIGNED_INT); - DEF_TYPE(type_short, 2, 16, NUMBER_TYPE_SIGNED_INT); - DEF_TYPE(type_int, 4, 32, NUMBER_TYPE_SIGNED_INT); - DEF_TYPE(type_long, 8, 64, NUMBER_TYPE_SIGNED_INT); - DEF_TYPE(type_isize, pointer_size / 8, pointer_size, NUMBER_TYPE_SIGNED_INT); - - DEF_TYPE(type_byte, 1, 8, NUMBER_TYPE_UNSIGNED_INT); - DEF_TYPE(type_ushort, 2, 16, NUMBER_TYPE_UNSIGNED_INT); - DEF_TYPE(type_uint, 4, 32, NUMBER_TYPE_UNSIGNED_INT); - DEF_TYPE(type_ulong, 8, 64, NUMBER_TYPE_UNSIGNED_INT); - DEF_TYPE(type_usize, pointer_size / 8, pointer_size, NUMBER_TYPE_UNSIGNED_INT); - -#undef DEF_TYPE - -} Type* type_int_max_type(bool is_signed) { return is_signed ? &type_long : &type_ulong; } -Type *type_get_signed(Type *type) -{ - assert(type->type_kind == TYPE_BUILTIN); - if (type->num_type == NUMBER_TYPE_SIGNED_INT) return type; - assert(type->num_type == NUMBER_TYPE_UNSIGNED_INT); - switch (type->bytes) - { - case 8: - return &type_long; - case 4: - return &type_int; - case 2: - return &type_short; - case 1: - return &type_char; - default: - UNREACHABLE - } -} - +/* Type* type_get_unsigned(Type *type) { assert(type->type_kind == TYPE_BUILTIN); - if (type->num_type == NUMBER_TYPE_UNSIGNED_INT) return type; - assert(type->num_type == NUMBER_TYPE_SIGNED_INT); - switch (type->bytes) + Decl *decl = type->decl; + if (decl->builtin.num_type == NUMBER_TYPE_UNSIGNED_INT) return type; + assert(decl->builtin.num_type == NUMBER_TYPE_SIGNED_INT); + switch (decl->builtin.bytes) { case 8: return &type_ulong; @@ -199,7 +97,7 @@ Type* type_get_unsigned(Type *type) } } - +*/ BinOp bin_op[256] = { [TOKEN_EQ] = BINOP_ASSIGN, @@ -307,6 +205,8 @@ void fprint_endparen(FILE *file, int indent) fprintf(file, ")\n"); } +void fprint_decl_recursive(FILE *file, Decl *decl, int indent); + void fprint_type_recursive(FILE *file, Type *type, int indent) { fprint_indent(file, indent); @@ -320,73 +220,78 @@ void fprint_type_recursive(FILE *file, Type *type, int indent) case TYPE_POISONED: fprintf(file, "(POISON)\n"); return; - case TYPE_UNRESOLVED: - if (type->unresolved.module.string) + case TYPE_USER_DEFINED: + if (type->resolve_status == RESOLVE_DONE) { - fprintf(file, "(unresolved %s::%s)\n", type->unresolved.module.string, type->unresolved.name.string); + if (type->decl != type->canonical->decl) + { + fprintf(file, "(user-defined %s::%s\n", type->decl->module->name, type->decl->name.string); + fprint_type_recursive(file, type->canonical, indent + 1); + break; + } + fprintf(file, "(user-defined %s::%s)\n", type->decl->module->name, type->decl->name.string); + return; } else { - fprintf(file, "(unresolved %s)\n", type->unresolved.name.string); + fprintf(file, "(unresolved %s::%s)\n", type->unresolved.module.string, type->name_loc.string); + return; } - return; - case TYPE_UNRESOLVED_EXPR: - fprintf(file, "(unresolved\n"); - fprint_expr_recursive(file, type->unresolved_type_expr, indent + 1); - fprint_endparen(file, indent); - return; - case TYPE_VOID: - fprintf(file, "(void)\n"); - return; - case TYPE_OPAQUE: - break; - case TYPE_BUILTIN: - fprintf(file, "(builtin)\n"); - return; - case TYPE_NIL: - fprintf(file, "(nil)\n"); - return; case TYPE_POINTER: fprintf(file, "(pointer\n"); fprint_type_recursive(file, type->base, indent + 1); - fprint_endparen(file, indent); + break; + case TYPE_VARARRAY: + fprintf(file, "(vararray\n"); + fprint_type_recursive(file, type->base, indent + 1); + break; + case TYPE_EXPRESSION: + fprintf(file, "(typexpr\n"); + fprint_expr_recursive(file, type->unresolved_type_expr, indent + 1); + break; + case TYPE_ARRAY: + if (type->resolve_status == RESOLVE_DONE) + { + fprintf(file, "(array [%zu]\n", type->len); + fprint_type_recursive(file, type->base, indent + 1); + } + else + { + fprintf(file, "(unresolved-array\n"); + fprint_type_recursive(file, type->base, indent + 1); + fprint_expr_recursive(file, type->unresolved_len, indent + 1); + } + break; + case TYPE_INC_ARRAY: + fprintf(file, "(TYPETODO)\n"); + return; + case TYPE_VOID: + case TYPE_BOOL: + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_F32: + case TYPE_F64: + fprintf(file, "(%s)\n", type->name_loc.string); + return; + case TYPE_IXX: + fprintf(file, "(comp time int)\n"); + return; + case TYPE_UXX: + fprintf(file, "(comp time uint)\n"); + return; + case TYPE_FXX: + fprintf(file, "(comp time float)\n"); return; case TYPE_STRING: - fprintf(file, "(string)\n"); - return; - case TYPE_ARRAY: - fprintf(file, "(array [%zu]\n", type->len); - fprint_type_recursive(file, type->base, indent + 1); - fprint_endparen(file, indent); - return; - case TYPE_INC_ARRAY: - break; - case TYPE_UNRESOLVED_ARRAY: - fprintf(file, "(array\n"); - fprint_type_recursive(file, type->base, indent + 1); - fprint_expr_recursive(file, type->unresolved_len, indent + 1); - fprint_endparen(file, indent); - return; - case TYPE_TYPEDEF: - break; - case TYPE_MACRO: - break; - case TYPE_FUNC_TYPE: - break; - case TYPE_ENUM: - break; - case TYPE_ERROR: - break; - case TYPE_FUNC: - break; - case TYPE_STRUCT: - break; - case TYPE_UNION: - break; - case TYPE_GENERIC: - break; + TODO } - fprintf(file, "(TYPETODO)\n"); + fprint_endparen(file, indent); } void fprint_expr_recursive(FILE *file, Expr *expr, int indent) { @@ -398,8 +303,31 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) return; case EXPR_CONST: fprintf(file, "(const "); - value_fprint(file, expr->const_expr); - fprintf(file, ")\n"); + switch (expr->const_expr.type) + { + case CONST_NIL: + fprintf(file, "nil)\n"); + break; + case CONST_BOOL: + fprintf(file, expr->const_expr.b ? "true" : "false"); + break; + case CONST_INT: + if (expr->type->type_kind >= TYPE_U8 && expr->type->type_kind <= TYPE_UXX) + { + fprintf(file, "%llu)\n", expr->const_expr.i); + } + else + { + fprintf(file, "%lld)\n", (int64_t)expr->const_expr.i); + } + break; + case CONST_FLOAT: + fprintf(file, "%Lf)\n", expr->const_expr.f); + break; + case CONST_STRING: + fprintf(file, "%s)\n", expr->const_expr.string.chars); + break; + } return; case EXPR_BINARY: fprintf(file, "(binary %s\n", token_type_to_string(binop_to_token(expr->binary_expr.operator))); @@ -630,12 +558,6 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent) case DECL_POISONED: fprintf(file, "(poisoned-decl)\n"); return; - case DECL_BUILTIN: - fprintf(file, "(builtin %s)\n", decl->name.string); - break; - case DECL_FUNC_TYPE: - TODO - break; case DECL_ARRAY_VALUE: TODO break; @@ -853,4 +775,5 @@ void fprint_decl(FILE *file, Decl *dec) { fprint_decl_recursive(file, dec, 0); } -Module module_poisoned = { .name = "INVALID" }; \ No newline at end of file +Module poisoned_module = { .name = "INVALID" }; + diff --git a/src/compiler/ast.h b/src/compiler/ast.h deleted file mode 100644 index 1954b8f89..000000000 --- a/src/compiler/ast.h +++ /dev/null @@ -1,812 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -#include "compiler_common.h" -#include "symtab.h" -#include "value.h" - -typedef enum _NumberType -{ - NUMBER_TYPE_BOOL, - NUMBER_TYPE_FLOAT, - NUMBER_TYPE_SIGNED_INT, - NUMBER_TYPE_UNSIGNED_INT, -} NumberType; - -// IF ORDER IS CHANGED, rewrite type_implicit_convert_ordered -typedef enum _TypeKind -{ - TYPE_POISONED, - TYPE_UNRESOLVED, - TYPE_UNRESOLVED_EXPR, - TYPE_VOID, - TYPE_OPAQUE, - TYPE_BUILTIN, - TYPE_NIL, - TYPE_POINTER, - TYPE_STRING, - TYPE_ARRAY, - TYPE_INC_ARRAY, - TYPE_UNRESOLVED_ARRAY, - TYPE_TYPEDEF, - TYPE_MACRO, - TYPE_FUNC_TYPE, - TYPE_ENUM, - TYPE_ERROR, - TYPE_FUNC, - TYPE_STRUCT, - TYPE_UNION, - TYPE_GENERIC, -} TypeKind; - -struct _Type -{ - TypeKind type_kind; - union - { - struct - { - unsigned char bytes; - unsigned char bitsize; - NumberType num_type : 8; - }; - Decl *decl; - struct - { - Token module; - Token name; - } unresolved; - Expr *unresolved_type_expr; - struct - { - union - { - Expr *unresolved_len; - size_t len; - }; - Type *base; - bool nullable : 1; - }; - }; - Type *canonical_type; -}; - -void type_setup(int pointer_size); -Type *type_new(TypeKind type_kind); -Type *type_poisoned(); -char *type_to_string(Type *type); - -static bool type_is_poison(Type *type) -{ - return type->type_kind == TYPE_POISONED; -} - -static bool type_ok(Type *type) -{ - return !type || type->type_kind != TYPE_POISONED; -} - -extern Type poisoned_type; - -extern Type type_bool, type_void, type_nil, type_string; - -extern Type type_half, type_float, type_double, type_quad; -extern Type type_char, type_short, type_int, type_long, type_isize; -extern Type type_byte, type_ushort, type_uint, type_ulong, type_usize; - -extern Type type_compint, type_compfloat; - -typedef enum _AttrKind -{ - ATTR_INVALID, - ATTR_UNRESOLVED, -} AttrKind; - -typedef struct _Attr -{ - Token module; - Token name; - union - { - Expr *expr; - }; -} Attr; - -typedef struct _ErrorDecl -{ - Decl **error_constants; -} ErrorDecl; - -typedef struct _ImportDecl -{ - ImportType type : 3; - Token alias; - Expr** generic_parameters; - struct _Module *module; -} ImportDecl; - -typedef struct _StructDecl -{ - Decl **members; - Decl **method_functions; -} StructDecl; - -typedef enum _VarDeclKind { - VARDECL_CONST = 0, - VARDECL_GLOBAL = 1, - VARDECL_LOCAL = 2, - VARDECL_PARAM = 3, - VARDECL_MEMBER = 4, - VARDECL_MULTI = 5, -} VarDeclKind; - -typedef struct _VarDecl -{ - VarDeclKind kind : 3; - Type *type; - Expr *init_expr; -} VarDecl; - - -typedef struct _CtIfDecl -{ - Expr *expr; - Decl **then; - Decl *elif; -} CtIfDecl; - - -typedef enum _DeclKind -{ - DECL_POISONED = 0, - DECL_BUILTIN, - DECL_FUNC, - DECL_VAR, - DECL_ENUM_CONSTANT, - DECL_TYPEDEF, - DECL_STRUCT, - DECL_UNION, - DECL_ENUM, - DECL_ERROR, - DECL_ERROR_CONSTANT, - DECL_FUNC_TYPE, - DECL_ARRAY_VALUE, - DECL_IMPORT, - DECL_MACRO, - DECL_MULTI_DECL, - DECL_GENERIC, - DECL_CT_IF, - DECL_CT_ELSE, - DECL_CT_ELIF, -} DeclKind; - -static inline bool decl_may_be_type(DeclKind kind) -{ - switch (kind) - { - case DECL_TYPEDEF: - case DECL_STRUCT: - case DECL_UNION: - case DECL_ENUM: - case DECL_ERROR: - case DECL_FUNC_TYPE: - case DECL_BUILTIN: - return true; - default: - return false; - } -} -typedef struct _EnumConstantDecl -{ - Expr *expr; -} EnumConstantDecl; - -typedef struct _ErrorConstantDecl -{ - uint32_t value; -} ErrorConstantDecl; - -typedef struct _EnumDecl -{ - Decl** values; - Type *type; -} EnumDecl; - - -typedef struct _FunctionSignature -{ - bool variadic : 1; - Type *rtype; - Decl** params; - Token *throws; -} FunctionSignature; - -typedef struct _FuncDecl -{ - const char *full_name; - Type *struct_parent; - FunctionSignature function_signature; - Ast *body; -} FuncDecl; - -typedef struct _TypedefDecl -{ - bool is_func : 1; - union - { - FunctionSignature function_signature; - Type *type; - }; -} TypedefDecl; - -typedef struct _MacroDecl -{ - Decl **parameters; - Type *rtype; // May be null! - Ast *body; -} MacroDecl; - -typedef struct _GenericDecl -{ - Ast **cases; - Token *parameters; - Type *rtype; // May be null! -} GenericDecl; - - -struct _Decl -{ - DeclKind decl_kind : 6; - bool is_exported : 1; - Visibility visibility : 2; - ResolveStatus resolve_status : 2; - bool is_used : 1; - bool is_used_public : 1; - bool has_cname : 1; - uint32_t alignment : 5; - union - { - uint32_t offset; - uint32_t counter; - }; - uint32_t size; - Token name; - struct _Module *module; - Attr** attributes; - Type *type; - Type *pointer_types[2]; // Up to three stars - union - { - ErrorDecl error; - ErrorConstantDecl error_constant; - ImportDecl import; - StructDecl strukt; - VarDecl var; - EnumDecl enums; - EnumConstantDecl enum_constant; - FuncDecl func; - TypedefDecl typedef_decl; - Decl** multi_decl; - MacroDecl macro_decl; - GenericDecl generic_decl; - CtIfDecl ct_if_decl; - CtIfDecl ct_elif_decl; - Decl** ct_else_decl; - /* - QualifiedType alias; - SourceRange unparsed_alias; - EnumConstantDecl enum_constant; - MacroDecl macro_decl; - FuncTypeDecl func_type; - ArrayDecl array_decl; - MacroParmDecl macro_param;*/ - }; -}; - -Decl *decl_new_in_module(struct _Module *module, DeclKind decl_kind, Token name, Visibility visibility); -Decl *decl_new_self_type(struct _Module *module, Token name, DeclKind decl_type, TypeKind type_kind, Visibility visibility); -Decl *decl_new_var(struct _Module *module, Token name, Type *type, VarDeclKind kind, Visibility visibility); -Decl *decl_new_enum_const(Decl *parent, Token name, DeclKind kind); -Decl *struct_find_name(Decl *decl, const char* name); - -static inline Decl *decl_poison(Decl *decl) -{ - decl->decl_kind = DECL_POISONED; - return decl; -} - -static inline DeclKind decl_from_token(TokenType type) -{ - if (type == TOKEN_STRUCT) return DECL_STRUCT; - if (type == TOKEN_UNION) return DECL_UNION; - UNREACHABLE -} -static inline bool decl_ok(Decl *decl) -{ - return decl->decl_kind != DECL_POISONED; -} - -extern Decl poisoned_decl; - -typedef enum _BinOp -{ - BINOP_ERROR, - BINOP_ASSIGN, - BINOP_MULT, - BINOP_MULT_ASSIGN, - BINOP_ADD, - BINOP_ADD_ASSIGN, - BINOP_SUB, - BINOP_SUB_ASSIGN, - BINOP_DIV, - BINOP_DIV_ASSIGN, - BINOP_MOD, - BINOP_MOD_ASSIGN, - BINOP_AND, - BINOP_AND_ASSIGN, - BINOP_OR, - BINOP_OR_ASSIGN, - BINOP_BIT_AND, - BINOP_BIT_AND_ASSIGN, - BINOP_BIT_OR, - BINOP_BIT_OR_ASSIGN, - BINOP_BIT_XOR, - BINOP_BIT_XOR_ASSIGN, - BINOP_NE, - BINOP_EQ, - BINOP_GE, - BINOP_GT, - BINOP_LE, - BINOP_LT, - BINOP_SHR, - BINOP_SHR_ASSIGN, - BINOP_SHL, - BINOP_SHL_ASSIGN, - BINOP_ELVIS -} BinOp; - -typedef enum _AssignOp -{ - ASSIGNOP_ERROR, - ASSIGNOP_ASSIGN, - ASSIGNOP_MULT_ASSIGN, - ASSIGNOP_ADD_ASSIGN, - ASSIGNOP_SUB_ASSIGN, - ASSIGNOP_DIV_ASSIGN, - ASSIGNOP_MOD_ASSIGN, - ASSIGNOP_AND_ASSIGN, - ASSIGNOP_OR_ASSIGN, - ASSIGNOP_BIT_AND_ASSIGN, - ASSIGNOP_BIT_OR_ASSIGN, - ASSIGNOP_BIT_XOR_ASSIGN, - ASSIGNOP_SHR_ASSIGN, - ASSIGNOP_SHL_ASSIGN, -} AssignOp; - -typedef enum _UnaryOp -{ - UNARYOP_ERROR, - UNARYOP_DEREF, - UNARYOP_ADDR, - UNARYOP_NEG, - UNARYOP_BITNEG, - UNARYOP_NOT, - UNARYOP_INC, - UNARYOP_DEC, -} UnaryOp; - -typedef enum _ExprKind -{ - EXPR_POISONED, - EXPR_TRY, - EXPR_CONST, - EXPR_BINARY, - EXPR_CONDITIONAL, - EXPR_UNARY, - EXPR_POST_UNARY, - EXPR_TYPE, - EXPR_IDENTIFIER, - EXPR_METHOD_REF, - EXPR_CALL, - EXPR_SIZEOF, - EXPR_SUBSCRIPT, - EXPR_ACCESS, - EXPR_STRUCT_VALUE, - EXPR_STRUCT_INIT_VALUES, - EXPR_INITIALIZER_LIST, - EXPR_EXPRESSION_LIST, - EXPR_DEFERRED_TOKENS, -} ExprKind; - -typedef struct _ExprTry -{ - Expr *expr; - Expr *else_expr; -} ExprTry; - -typedef struct _ExprMethodRef -{ - Type *type; - Token method; -} ExprMethodRef; - -typedef struct _ExprStructValue -{ - Type *type; - Expr *init_expr; -} ExprStructValue; - -typedef struct _ExprTernary -{ - Expr *cond; - Expr *then_expr; // May be null for elvis! - Expr *else_expr; -} ExprTernary; - -typedef struct _ExprBinary -{ - Expr *left; - Expr *right; - BinOp operator; -} ExprBinary; - -typedef struct _ExprAssign -{ - Expr *left; - Expr *right; - AssignOp operator; -} ExprAssign; - -typedef struct _ExprUnary -{ - Expr* expr; - UnaryOp operator; -} ExprUnary; - -typedef struct _ExprCall -{ - bool is_struct_function; - Expr *function; - Expr **parameters; -} ExprCall; - -typedef struct _ExprSubscript -{ - Expr *expr; - Expr *index; -} ExprSubscript; - -typedef struct _ExprAccess -{ - Expr *parent; - Token sub_element; -} ExprAccess; - -typedef struct _ExprIdentifier -{ - Token module; - Token identifier; - bool is_ref; - Decl *decl; -} ExprIdentifier; - -typedef struct _ExprType -{ - Type *type; -} ExprType; - -struct _Expr -{ - ExprKind expr_kind : 8; - Token loc; - Type *type; - - union { - Token* deferred_tokens; - Token deferred_token; - Value const_expr; - ExprStructValue struct_value_expr; - ExprMethodRef method_ref_expr; - ExprTry try_expr; - ExprBinary binary_expr; - ExprAssign assign_expr; - ExprTernary conditional_expr; - ExprUnary unary_expr; - ExprUnary post_expr; - ExprCall call_expr; - ExprSubscript subscript_expr; - ExprAccess access_expr; - ExprIdentifier identifier_expr; - ExprType type_expr; - Expr** initializer_expr; - Expr** expression_list; - /* - Value const_expr; - ExprPost post_expr; - ExprStructInitValues struct_init_values_expr; - ExprDesignatedInitializer designated_initializer_expr; - ExprSizeof sizeof_expr; - ExprCast cast_expr;*/ - }; -}; - -Expr *expr_new(ExprKind kind, Token start); -#define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->loc) -#define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok) - -AssignOp assignop_from_token(TokenType type); -BinOp binop_from_token(TokenType type); -UnaryOp unaryop_from_token(TokenType type); - -extern Expr poisoned_expr; - -static inline bool expr_ok(Expr *expr) -{ - return expr == NULL || expr->expr_kind != EXPR_POISONED; -} - -typedef struct _AstAttribute -{ - -} AstAttribute; - -typedef enum _AstKind -{ - AST_POISONED, - AST_ASM_STMT, - AST_ATTRIBUTE, - AST_BREAK_STMT, - AST_CASE_STMT, - AST_CATCH_STMT, - AST_COMPOUND_STMT, - AST_COND_STMT, - AST_CONTINUE_STMT, - AST_CT_IF_STMT, - AST_CT_ELIF_STMT, - AST_CT_ELSE_STMT, - AST_DECLARE_STMT, - AST_DECL_EXPR_LIST, - AST_DEFAULT_STMT, - AST_DEFER_STMT, - AST_DO_STMT, - AST_EXPR_STMT, - AST_FOR_STMT, - AST_GOTO_STMT, - AST_IF_STMT, - AST_LABEL, - AST_NOP_STMT, - AST_RETURN_STMT, - AST_SWITCH_STMT, - AST_THROW_STMT, - AST_TRY_STMT, - AST_NEXT_STMT, - AST_VOLATILE_STMT, - AST_WHILE_STMT, - AST_GENERIC_CASE_STMT, - AST_GENERIC_DEFAULT_STMT, -} AstKind; - -// Ordering here is in priority if two branches should have the same exit. -typedef enum _ExitType -{ - EXIT_NONE, - EXIT_BREAK, - EXIT_GOTO, - EXIT_CONTINUE, - EXIT_RETURN, -} ExitType; - -typedef struct _AstCompoundStmt -{ - Ast **stmts; -// DeferList defer_list; TODO -} AstCompoundStmt; - -typedef struct _AstLabel -{ - uint16_t last_goto; - bool is_used : 1; - Ast *defer; - Ast *in_defer; -} AstLabelStmt; - -typedef struct _AstReturnStmt -{ - Expr *expr; // May be NULL - Ast *defer; -} AstReturnStmt; - -typedef struct _AstWhileStmt -{ - Ast *cond; - Ast *body; -} AstWhileStmt; - -typedef struct _AstDoStmt -{ - Expr *expr; - Ast *body; -} AstDoStmt; - -typedef struct _AstIfStmt -{ - Ast *cond; - Ast *then_body; - Ast *else_body; -} AstIfStmt; - - -typedef struct _AstCaseStmt -{ - Expr *expr; -} AstCaseStmt; - -typedef struct _AstSwitchStmt -{ - Ast *cond; - Ast *body; -} AstSwitchStmt; - -typedef struct _AstForStmt -{ - Ast *init; - Expr *cond; - Expr *incr; - Ast *body; -} AstForStmt; - -typedef enum DeclExprType -{ - DECLEXPR_DECL, - DECLEXPR_EXPR, -} DeclExprType; - -typedef struct _AstCondStmt -{ - Decl *decl; - Ast *decl_expr; -} AstCondStmt; - - -typedef struct _AstDeclExprList -{ - DeclExprType list_type : 2; - union - { - Decl *decl; - Expr *expr; - }; -} AstDeclExprList; - -typedef enum _GotoType -{ - GOTO_NOT_ANALYSED, - GOTO_JUMP_FORWARD, - GOTO_JUMP_BACK -} GotoType; - -typedef struct _AstGotoStmt -{ - GotoType type : 2; - Ast *defer; - union - { - Ast *in_defer; - Ast *defer_end; - }; -} AstGotoStmt; - -typedef struct _AstDeferStmt -{ - bool emit_boolean : 1; - Ast *body; // Compound statement - Ast *prev_defer; -} AstDeferStmt; - -typedef struct _AstCatchStmt -{ - Decl *error_param; - Ast *body; -} AstCatchStmt; - -typedef struct _AstCtIfStmt -{ - Expr *expr; - Ast *then; - Ast *elif; -} AstCtIfStmt; - - -typedef struct _AstGenericCaseStmt -{ - Type **types; - Ast *body; -} AstGenericCaseStmt; - -typedef struct _Ast -{ - AstKind ast_kind : 8; - ExitType exit : 3; - Token token; - - union - { - AstAttribute attribute; - AstCompoundStmt compound_stmt; - Decl *declare_stmt; - Expr *expr_stmt; - Expr *throw_stmt; - Ast *volatile_stmt; - Ast *try_stmt; - AstLabelStmt label_stmt; - AstReturnStmt return_stmt; - AstWhileStmt while_stmt; - AstDoStmt do_stmt; - AstIfStmt if_stmt; - AstDeferStmt defer_stmt; - AstSwitchStmt switch_stmt; - AstCaseStmt case_stmt; - AstCatchStmt catch_stmt; - AstGotoStmt goto_stmt; - AstForStmt for_stmt; - AstCondStmt cond_stmt; - AstCtIfStmt ct_if_stmt; - AstCtIfStmt ct_elif_stmt; - Ast* ct_else_stmt; - AstDeclExprList decl_expr_list; - AstGenericCaseStmt generic_case_stmt; - Ast* generic_default_stmt; - }; -} Ast; - - -#define NEW_AST(_kind, _token) new_ast(_kind, _token) - -void *malloc_arena(size_t mem); - -static inline Ast *new_ast(AstKind kind, Token token) -{ - Ast *ast = malloc_arena(sizeof(Ast)); - memset(ast, 0, sizeof(Ast)); - ast->token = token; - ast->ast_kind = kind; - ast->exit = EXIT_NONE; - return ast; -} - -extern Ast poisoned_ast; -static inline bool ast_ok(Ast *ast) -{ - return ast == NULL || ast->ast_kind != AST_POISONED; -} -static inline void ast_poison(Ast *ast) -{ - ast->ast_kind = AST_POISONED; -} - -typedef struct _Module -{ - const char *name; - - bool is_external; - bool is_c_library; - bool is_exported; - - Ast **files; // Asts - - Decl** functions; - STable struct_functions; - STable symbols; - STable public_symbols; -} Module; - -extern Module module_poisoned; - -void fprint_ast(FILE *file, Ast *ast); -void fprint_decl(FILE *file, Decl *dec); -void fprint_type_recursive(FILE *file, Type *type, int indent); -void fprint_expr_recursive(FILE *file, Expr *expr, int indent); diff --git a/src/compiler/bigint.c b/src/compiler/bigint.c index 0d50804a4..b523590e7 100644 --- a/src/compiler/bigint.c +++ b/src/compiler/bigint.c @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. #include "bigint.h" -#include "../utils/malloc.h" +#include "../utils/lib.h" #include static inline uint32_t u32_min(uint32_t a, uint32_t b) diff --git a/src/compiler/bigint.h b/src/compiler/bigint.h index 67c4950e8..6bfb3d710 100644 --- a/src/compiler/bigint.h +++ b/src/compiler/bigint.h @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "compiler_common.h" +#include "compiler_internal.h" typedef struct _BigInt { diff --git a/src/compiler/builtins.c b/src/compiler/builtins.c new file mode 100644 index 000000000..12ef44837 --- /dev/null +++ b/src/compiler/builtins.c @@ -0,0 +1,160 @@ +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "compiler_internal.h" + + + +/* +BuiltinType builtin_common_type[16][16] = { + // err, wptr, nil, bool, char, short, int, long, byte,ushort, int, ulong, float,double, ctint, ctreal + { TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // Error + { TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // void + { TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR, TERR }, // wptr + { TERR, TERR, TERR, T_U1, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_U1, T_FXX }, // bool + { TERR, TERR, TERR, T_I8, T_I8, T_I16, T_I32, T_I64, T_I8, T_I16, T_I32, T_I64, T_F32, T_F64, T_I8, T_FXX }, // char + { TERR, TERR, TERR, T_I16, T_I16, T_I16, T_I32, T_I64, T_I16, T_I16, T_I32, T_I64, T_F32, T_F64, T_I16, T_FXX }, // short + { TERR, TERR, TERR, T_I32, T_I32, T_I32, T_I32, T_I64, T_I32, T_I32, T_I32, T_I64, T_F32, T_F64, T_I32, T_FXX }, // int + { TERR, TERR, TERR, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_I64, T_F32, T_F64, T_I64, T_FXX }, // long + { TERR, TERR, TERR, T_U8, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_U8, T_FXX }, // byte + { TERR, TERR, TERR, T_U16, T_I16, T_I16, T_I32, T_I64, T_U16, T_U16, T_U32, T_U64, T_F32, T_F64, T_U16, T_FXX }, // ushort + { TERR, TERR, TERR, T_U32, T_I32, T_I32, T_I32, T_I64, T_U32, T_U32, T_U32, T_U64, T_F32, T_F64, T_U32, T_FXX }, // uint + { TERR, TERR, TERR, T_U64, T_I64, T_I64, T_I64, T_I64, T_U64, T_U64, T_U64, T_U64, T_F32, T_F64, T_U64, T_FXX }, // ulong + { TERR, TERR, TERR, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F32, T_F64, T_F32, T_F32 }, // float + { TERR, TERR, TERR, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64, T_F64 }, // double + { TERR, TERR, TERR, T_U1, T_I8, T_I16, T_I32, T_I64, T_U8, T_U16, T_U32, T_U64, T_F32, T_F64, T_IXX, T_FXX }, // ctint + { TERR, TERR, TERR, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_FXX, T_F32, T_F64, T_FXX, T_FXX }, // ctreal +}; +void +BuiltinConv BUILTIN_ASSIGN_CONVERSION[16][16] = { + //e v w b c s i l b u u u f d c c + //r o p o h h n o y s i l l o t t + //r i t o a o t n t h n o o u i r + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // error + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // void = + { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // wptr = + { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // bool = + { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // char = + { 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }, // short = + { 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // int = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 }, // long = + { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }, // byte = + { 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // ushort = + { 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0 }, // uint = + { 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0 }, // ulong = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, // float = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // double = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctint + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctfloat +}; + +// x += x -= x /= x *= +bool BUILTIN_ASSIGN_UPDATE_CONVERSION[16][16] = { + //e v w b c s i l b u u u f d c c + //r o p o h h n o y s i l l o t t + //r i t o a o t n t h n o o u i r + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // error + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // void = + { 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // wptr = + { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, // bool = + { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, // char = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // short = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // int = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // long = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // byte = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // ushort = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // uint = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 }, // ulong = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // float = + { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // double = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctint + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ctfloat +}; +*/ + + +/* +void builtin_convert(ExprConst *value, BuiltinConv conversion, Type *canonical_target) +{ + assert(canonical_target == canonical_target->canonical); + switch (conversion) + { + case C_XXXX: + FATAL_ERROR("Should never be called"); + break; + case C_FPFP: + if (canonical_target->builtin.bitsize == 16) + { + value->f = (float)value->f; + } + if (canonical_target->builtin.bitsize == 32) + { + value->f = (double)value->f; + } + break; + case C_FPSI: + if (value->f < 0) + { + value->integer.i = (uint64_t)(-value->f); + value->type = CONST_NEGATIVE_INT; + } + else + { + value->integer.i = (uint64_t)(-value->f); + value->type = CONST_POSITIVE_INT; + } + break; + case C_FPUI: + assert(value->f >= 0); + value->integer.i = (uint64_t)(value->f); + value->type = CONST_POSITIVE_INT; + break; + case C_SIFP: + case C_UIFP: + value->f = value->integer.i; + if (value->type == CONST_NEGATIVE_INT) value->f = -value->f; + value->type = CONST_FLOAT; + break; + case C_SISI: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); + break; + case C_SIUI: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); + break; + case C_UISI: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); + break; + case C_UIUI: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); + break; + case C_PTXI: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); + break; + case C_XIPT: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, true, true); + break; + case C_BOFP: +// value_convert(value, VALUE_TYPE_FLOAT, canonical_target->decl->builtin.bitsize, false, true); + break; + case C_BOSI: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); + break; + case C_BOUI: +// value_convert(value, VALUE_TYPE_INT, canonical_target->decl->builtin.bitsize, false, true); + break; + case C_FPBO: +// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true); + break; + case C_XIBO: +// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true); + break; + case C_PTBO: +// value_convert(value, VALUE_TYPE_BOOL, canonical_target->decl->builtin.bitsize, true, true); + break; + default: + UNREACHABLE + } +} +*/ + diff --git a/src/compiler/casts.c b/src/compiler/casts.c new file mode 100644 index 000000000..f18664c29 --- /dev/null +++ b/src/compiler/casts.c @@ -0,0 +1,508 @@ +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "compiler_internal.h" + +#define EXIT_T_MISMATCH() return sema_type_mismatch(left, canonical, cast_type) + + +static inline void insert_cast(Expr *expr, CastKind kind, Type *type) +{ + Expr *inner = malloc_arena(sizeof(Expr)); + *inner = *expr; + expr->expr_kind = EXPR_CAST; + expr->expr_cast.kind = kind; + expr->type = type; +} + +static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type) +{ + const char *action = ""; + switch (cast_type) + { + case CAST_TYPE_EXPLICIT: + action = "cast"; + break; + case CAST_TYPE_IMPLICIT: + action = "implicitly cast"; + break; + case CAST_TYPE_IMPLICIT_ASSIGN: + case CAST_TYPE_IMPLICIT_ASSIGN_ADD: + action = "assign"; + break; + + } + SEMA_ERROR(expr->loc, "Cannot %s '%s' to '%s'", action, type->name_loc.string, expr->type->name_loc.string); + return false; +} + + +bool erro(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + EXIT_T_MISMATCH(); +} + +bool ptxi(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_NIL); + left->const_expr.type = sign_from_type(canonical); + left->const_expr.i = 0; + left->type = type; + return true; + } + insert_cast(left, CAST_PTRINT, canonical); + return true; +} + +bool ptbo(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_NIL); + left->const_expr.type = CONST_BOOL; + left->const_expr.b = false; + left->type = type; + return true; + } + insert_cast(left, CAST_PTRBOOL, canonical); + return true; +} + +static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *target_type) +{ + assert(current_type->canonical == current_type); + assert(target_type->canonical == target_type); + + // Neither is void* or have matching bases: + // TODO recursively check for ?* or? + if (target_type->base != &type_void && current_type->base != &type_void && target_type->base != current_type->base) return false; + + // Current is not null, or target is nullable? Ok! + return target_type->nullable || !current_type->nullable; +} + +bool ptpt(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + Type *to_cast_type = left->type->canonical; + + if (cast_type != CAST_TYPE_EXPLICIT && !may_implicitly_cast_ptr_to_ptr(to_cast_type, canonical)) + { + sema_type_mismatch(left, type, cast_type); + } + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_NIL); + left->type = type; + return true; + } + insert_cast(left, CAST_PTRPTR, canonical); + return true; +} + +bool ptst(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO + if (left->expr_kind == EXPR_CONST) + { + 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; + } + insert_cast(left, CAST_UIFP, canonical); + return true; +} + +bool boxi(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_BOOL); + left->const_expr.type = sign_from_type(canonical); + left->const_expr.i = left->const_expr.b ? 1 : 0; + left->type = type; + return true; + } + insert_cast(left, CAST_BOOLINT, canonical); + return true; +} + +bool bofp(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_NIL); + left->const_expr.type = CONST_FLOAT; + left->const_expr.f = left->const_expr.b ? 1.0 : 0.0; + left->type = type; + return true; + } + insert_cast(left, CAST_BOOLFP, canonical); + return true; +} + +bool xibo(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_INT); + left->const_expr.type = CONST_BOOL; + left->const_expr.b = left->const_expr.i != 0; + left->type = type; + return true; + } + insert_cast(left, CAST_INTBOOL, canonical); + return true; +} + +bool fpbo(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_FLOAT); + left->const_expr.type = CONST_BOOL; + left->const_expr.b = left->const_expr.f != 0; + left->type = type; + return true; + } + insert_cast(left, CAST_INTBOOL, canonical); + return true; +} + + +bool fpfp(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + Type *left_canonical = left->type->canonical; + bool is_narrowing = left_canonical->builtin.bytesize < canonical->builtin.bytesize && left_canonical->type_kind != TYPE_FXX; + + // Is this correct? TODO + if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); + + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_FLOAT); + if (type->type_kind == TYPE_F32) + { + left->const_expr.f = (float)left->const_expr.f; + } + left->type = type; + return true; + } + insert_cast(left, CAST_FPFP, canonical); + return true; +} + +bool fpui(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_FLOAT); + assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64); + left->const_expr.i = (uint64_t)left->const_expr.f; + left->type = type; + return true; + } + insert_cast(left, CAST_FPUI, canonical); + return true; +} + +bool fpsi(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_FLOAT); + assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64); + left->const_expr.i = (uint64_t)((int64_t)left->const_expr.f); + left->type = type; + return true; + } + insert_cast(left, CAST_FPUI, canonical); + return true; +} + +static uint64_t type_mask[4] = { 0xFF, 0xFFFF, 0xFFFFFFFFU, 0xFFFFFFFFFFFFFFFFLLU}; +static int64_t int_type_max[4] = { INT8_MAX, INT16_MAX, INT32_MAX, INT64_MAX }; +static uint64_t uint_type_max[4] = { UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX }; +static int64_t int_type_min[4] = { INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN }; + +bool sisi(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + Type *left_canonical = left->type->canonical; + bool is_narrowing = left->type->builtin.bytesize < canonical->builtin.bytesize && left_canonical->type_kind != TYPE_IXX; + + if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + int64_t i = (int64_t)left->const_expr.i; + int index = canonical->type_kind - TYPE_I8; + if (left_canonical->type_kind == TYPE_IXX) + { + if ((i > int_type_max[index]) || (i < int_type_min[index])) + { + SEMA_ERROR(left->loc, "'%lld' does not fit into '%s'", i, canonical->name_loc.string); + return false; + } + } + assert(left->const_expr.type == CONST_INT); + assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64); + uint64_t mask = type_mask[index]; + if (i < 0) + { + left->const_expr.i = ~((~((uint64_t)i)) & mask); + } + else + { + left->const_expr.i &= mask; + } + left->type = type; + return true; + } + assert(left_canonical->type_kind != TYPE_IXX); + insert_cast(left, CAST_SISI, canonical); + return true; +} + +bool siui(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + // TODO + Type *left_canonical = left->type->canonical; + bool is_narrowing = left->type->builtin.bytesize < canonical->builtin.bytesize && left_canonical->type_kind != TYPE_IXX; + if (is_narrowing && (cast_type != CAST_TYPE_IMPLICIT_ASSIGN_ADD && cast_type != CAST_TYPE_EXPLICIT)) EXIT_T_MISMATCH(); + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_INT); + assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64); + left->const_expr.i &= type_mask[canonical->type_kind - TYPE_U8]; + left->type = type; + return true; + } + insert_cast(left, CAST_SIUI, canonical); + return true; +} + +bool xiptr(Expr* left, Type *canonical, Type *type) +{ + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_INT); + assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64); + assert(left->const_expr.i == 0); + left->const_expr.type = CONST_NIL; + left->type = type; + return true; + } + insert_cast(left, CAST_XIPTR, canonical); + return true; +} + +bool sifp(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + // TODO + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_INT); + assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64); + if (left->const_expr.i > (uint64_t)INT64_MAX) + { + left->const_expr.f = -((long double)(~left->const_expr.i)); + } + else + { + left->const_expr.f = left->const_expr.i; + } + left->type = type; + return true; + } + insert_cast(left, CAST_SIFP, canonical); + return true; +} + + +bool uisi(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (left->expr_kind == EXPR_CONST) + { + assert(canonical->type_kind >= TYPE_I8 && canonical->type_kind <= TYPE_I64); + int index = canonical->type_kind - TYPE_I8; + uint64_t mask = type_mask[index]; + if (cast_type != CAST_TYPE_EXPLICIT && left->type->canonical->type_kind == TYPE_UXX) + { + if (left->const_expr.i > (uint64_t)int_type_max[index]) + { + SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", left->const_expr.i, type->name_loc.string); + return false; + } + } + if (left->const_expr.i > (uint64_t)INT64_MAX) + { + left->const_expr.i = ~((~left->const_expr.i) & mask); + } + else + { + left->const_expr.i &= mask; + } + left->type = type; + return true; + } + insert_cast(left, CAST_UISI, canonical); + return true; +} + +bool uiui(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + if (left->expr_kind == EXPR_CONST) + { + assert(left->const_expr.type == CONST_INT && type_is_unsigned(left->type)); + assert(canonical->type_kind >= TYPE_U8 && canonical->type_kind <= TYPE_U64); + int index = canonical->type_kind - TYPE_U8; + if (cast_type != CAST_TYPE_EXPLICIT && left->type->canonical->type_kind == TYPE_UXX) + { + if (left->const_expr.i > uint_type_max[index]) + { + SEMA_ERROR(left->loc, "Cannot implicitly convert value '%llu' into %s - it will not fit.", type->name_loc.string); + return false; + } + } + left->const_expr.i &= type_mask[index]; + left->type = type; + return true; + } + insert_cast(left, CAST_UIUI, canonical); + return true; +} + + +bool uifp(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO + if (left->expr_kind == EXPR_CONST) + { + 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; + } + insert_cast(left, CAST_UIFP, canonical); + return true; +} + +bool ussi(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + Decl *decl = type->decl; + + if (decl->decl_kind != DECL_ENUM) return sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT); + if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); + + if (left->expr_kind == EXPR_IDENTIFIER && left->identifier_expr.decl->decl_kind == DECL_ENUM_CONSTANT) + { + Expr *value = left->identifier_expr.decl->enum_constant.expr; + assert(value->expr_kind == EXPR_CONST); + assert(value->const_expr.type == CONST_INT); + left->const_expr.i = value->const_expr.i; + // TODO narrowing + } + insert_cast(left, CAST_ENUMSI, canonical); + return true; +} + +bool sius(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool uius(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool xipt(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool usus(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool usui(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool ptva(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool usbo(Expr* left, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +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: + { &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 + { &xibo, &sisi, &sisi, &erro, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // int + { &xibo, &sisi, &sisi, &sisi, &erro, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // long + { &xibo, &sisi, &sisi, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &xipt, &erro, &erro, &erro }, // cint + { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &erro, &uiui, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // byte + { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &erro, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // ushort + { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &erro, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // uint + { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &uiui, &erro, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // ulong + { &xibo, &uisi, &uisi, &uisi, &uisi, &erro, &uiui, &uiui, &uiui, &uiui, &erro, &uifp, &uifp, &erro, &uius, &xipt, &erro, &erro, &erro }, // cuint + { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // float + { &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 }, // cfloat + { &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 + { &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 +}; + +static inline bool cannot_convert(TypeKind type_kind) +{ + return type_kind <= TYPE_VOID || type_kind >= TYPE_INC_ARRAY; +} + +bool cast(Expr *expr, Type *to_type, CastType cast_type) +{ + Type *from_type = expr->type->canonical; + Type *canonical = to_type->canonical; + TypeKind from_kind = from_type->type_kind; + TypeKind to_kind = canonical->type_kind; + + if (cannot_convert(from_kind) || cannot_convert(to_kind)) + { + switch (cast_type) + { + case CAST_TYPE_EXPLICIT: + case CAST_TYPE_IMPLICIT: + SEMA_ERROR(expr->loc, "Cannot convert '%s' to '%s'", expr->type->name_loc.start, to_type->name_loc.start); + break; + case CAST_TYPE_IMPLICIT_ASSIGN: + case CAST_TYPE_IMPLICIT_ASSIGN_ADD: + SEMA_ERROR(expr->loc, "Cannot assign '%s' to '%s'", expr->type->name_loc.start, to_type->name_loc.start); + break; + } + return false; + } + CastFunc func = BUILTIN_CONVERSION[from_type->type_kind - TYPE_BOOL][to_type->type_kind - TYPE_BOOL]; + return func(expr, to_type, canonical, cast_type); +} diff --git a/src/compiler/codegen.c b/src/compiler/codegen.c new file mode 100644 index 000000000..7aa1f8afa --- /dev/null +++ b/src/compiler/codegen.c @@ -0,0 +1,459 @@ +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "compiler_internal.h" + + +#define PRINTF(...) fprintf(context->codegen_output, __VA_ARGS__) +#define PRINTTYPE(_t) print_typename(context->codegen_output, _t) +static void codegen_ast(Context *context, Ast *ast, int indent); + +static void print_typename(FILE *file, Type *type) +{ + assert(type->resolve_status == RESOLVE_DONE); + type = type->canonical; + switch (type->type_kind) + { + case TYPE_POISONED: + case TYPE_INC_ARRAY: + UNREACHABLE + case TYPE_USER_DEFINED: + switch (type->decl->decl_kind) + { + case DECL_STRUCT: + fprintf(file, "struct"); + break; + case DECL_UNION: + fprintf(file, "union"); + break; + case DECL_ENUM: + fprintf(file, "enum"); + break; + case DECL_ERROR: + fprintf(file, "int32_t"); + return; + default: + UNREACHABLE + } + fprintf(file, " _%s_%s", type->decl->module->name, type->decl->name.string); + break; + case TYPE_VOID: + fprintf(file, "void"); + break; + case TYPE_BOOL: + fprintf(file, "bool"); + break; + case TYPE_I8: + fprintf(file, "int8_t"); + break; + case TYPE_I16: + fprintf(file, "int16_t"); + break; + case TYPE_I32: + fprintf(file, "int32_t"); + break; + case TYPE_I64: + fprintf(file, "int64_t"); + break; + case TYPE_IXX: + UNREACHABLE + case TYPE_U8: + fprintf(file, "uint8_t"); + break; + case TYPE_U16: + fprintf(file, "uint16_t"); + break; + case TYPE_U32: + fprintf(file, "int32_t"); + break; + case TYPE_U64: + fprintf(file, "uint64_t"); + break; + case TYPE_UXX: + UNREACHABLE + case TYPE_F32: + fprintf(file, "float"); + break; + case TYPE_F64: + fprintf(file, "double"); + break; + case TYPE_FXX: + UNREACHABLE + case TYPE_STRING: + UNREACHABLE; + case TYPE_VARARRAY: + case TYPE_POINTER: + print_typename(file, type->base); + fprintf(file, "*"); + break; + case TYPE_ARRAY: + print_typename(file, type->base); + fprintf(file, "[%zu]", type->len); + break; + case TYPE_EXPRESSION: + UNREACHABLE + } +} + +static void indent_line(Context *context, int indent) +{ + for (int i = 0; i < indent; i++) + { + PRINTF(" "); + } +} + +static void codegen_expr(Context *context, Expr *expr) +{ + switch (expr->expr_kind) + { + case EXPR_POISONED: + UNREACHABLE; + case EXPR_TRY: + break; + case EXPR_CONST: + break; + case EXPR_BINARY: + break; + case EXPR_CONDITIONAL: + break; + case EXPR_UNARY: + break; + case EXPR_POST_UNARY: + break; + case EXPR_TYPE: + break; + case EXPR_IDENTIFIER: + break; + case EXPR_METHOD_REF: + break; + case EXPR_CALL: + break; + case EXPR_SIZEOF: + break; + case EXPR_SUBSCRIPT: + break; + case EXPR_ACCESS: + break; + case EXPR_STRUCT_VALUE: + break; + case EXPR_STRUCT_INIT_VALUES: + break; + case EXPR_INITIALIZER_LIST: + break; + case EXPR_EXPRESSION_LIST: + break; + case EXPR_DEFERRED_TOKENS: + break; + case EXPR_CAST: + break; + } + TODO +} +static inline void codegen_compound_stmt(Context *context, Ast *ast, int indent) +{ + indent_line(context, indent); + PRINTF("{\n"); + VECEACH(ast->compound_stmt.stmts, i) + { + codegen_ast(context, ast->compound_stmt.stmts[i], indent + 1); + } + indent_line(context, indent); + PRINTF("}\n"); +} + +static inline void codegen_emit_cast(Context *context, Type *canonical) +{ + assert(canonical == canonical->canonical); + PRINTF("("); + TODO +} +static inline void codegen_emit_const_expr(Context *context, Expr *expr) +{ + assert(expr->expr_kind == EXPR_CONST); + Type *canonical = expr->type->canonical; + switch (canonical->type_kind) + { + case TYPE_POISONED: + case TYPE_USER_DEFINED: + case TYPE_VOID: + UNREACHABLE + break; + case TYPE_BOOL: + assert(expr->const_expr.type == CONST_BOOL); + PRINTF(expr->const_expr.b ? "true" : "false"); + break; + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + assert(expr->const_expr.type == CONST_INT); + PRINTF("(("); + print_typename(context->codegen_output, canonical); + PRINTF(")"); + PRINTF("%lld)", (long long)expr->const_expr.i); + break; + case TYPE_IXX: + UNREACHABLE + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + assert(expr->const_expr.type == CONST_INT); + PRINTF("(("); + print_typename(context->codegen_output, canonical); + PRINTF(")"); + PRINTF("%llu)", expr->const_expr.i); + break; + case TYPE_UXX: + UNREACHABLE + case TYPE_F32: + case TYPE_F64: + assert(expr->const_expr.type == CONST_FLOAT); + PRINTF("(("); + print_typename(context->codegen_output, canonical); + PRINTF(")"); + PRINTF("%Lf)", expr->const_expr.f); + break; + case TYPE_FXX: + UNREACHABLE + case TYPE_POINTER: + assert(expr->const_expr.type == CONST_NIL); + PRINTF("(("); + print_typename(context->codegen_output, canonical); + PRINTF("0)"); + break; + case TYPE_STRING: + TODO + case TYPE_ARRAY: + case TYPE_VARARRAY: + case TYPE_INC_ARRAY: + case TYPE_EXPRESSION: + UNREACHABLE + } +} + +static inline void codegen_emit_expr(Context *context, Expr *expr) +{ + switch (expr->expr_kind) + { + case EXPR_CONST: + codegen_emit_const_expr(context, expr); + break; + default: + TODO + } +} + +static inline void codegen_var_decl(Context *context, Decl *decl, int indent) +{ + assert(decl->decl_kind == DECL_VAR); + indent_line(context, indent); + print_typename(context->codegen_output, decl->var.type); + PRINTF(" "); + PRINTF("%s", decl->name.string); + PRINTF(";\n"); + if (!decl->var.init_expr) return; + indent_line(context, indent); + PRINTF("%s = ", decl->name.string); + codegen_emit_expr(context, decl->var.init_expr); + PRINTF(";\n"); +} + +static inline void codegen_declare_stmt(Context *context, Ast *ast, int indent) +{ + Decl *decl = ast->declare_stmt; + if (decl->decl_kind == DECL_MULTI_DECL) + { + VECEACH(decl->multi_decl, i) + { + codegen_var_decl(context, decl->multi_decl[i], indent); + } + } + else + { + codegen_var_decl(context, decl, indent); + } +} + +static void codegen_ast(Context *context, Ast *ast, int indent) +{ + switch (ast->ast_kind) + { + case AST_POISONED: + UNREACHABLE + case AST_ASM_STMT: + break; + case AST_ATTRIBUTE: + break; + case AST_BREAK_STMT: + break; + case AST_CASE_STMT: + break; + case AST_CATCH_STMT: + UNREACHABLE + case AST_COMPOUND_STMT: + codegen_compound_stmt(context, ast, indent); + return; + case AST_COND_STMT: + break; + case AST_CONTINUE_STMT: + break; + case AST_CT_IF_STMT: + break; + case AST_CT_ELIF_STMT: + break; + case AST_CT_ELSE_STMT: + break; + case AST_DECLARE_STMT: + codegen_declare_stmt(context, ast, indent); + return; + case AST_DECL_EXPR_LIST: + break; + case AST_DEFAULT_STMT: + break; + case AST_DEFER_STMT: + break; + case AST_DO_STMT: + break; + case AST_EXPR_STMT: + break; + case AST_FOR_STMT: + break; + case AST_GOTO_STMT: + break; + case AST_IF_STMT: + break; + case AST_LABEL: + break; + case AST_NOP_STMT: + break; + case AST_RETURN_STMT: + indent_line(context, indent); + if (ast->return_stmt.expr) + { + PRINTF("return "); + codegen_expr(context, ast->return_stmt.expr); + PRINTF(";\n"); + } + else + { + PRINTF("return;\n"); + } + return; + case AST_SWITCH_STMT: + break; + case AST_THROW_STMT: + break; + case AST_TRY_STMT: + break; + case AST_NEXT_STMT: + break; + case AST_VOLATILE_STMT: + break; + case AST_WHILE_STMT: + break; + case AST_GENERIC_CASE_STMT: + break; + case AST_GENERIC_DEFAULT_STMT: + break; + } + TODO +} +static inline void codegen_func(Context *context, Decl *decl) +{ + print_typename(context->codegen_output, decl->func.function_signature.rtype); + PRINTF(" %s__%s()\n", decl->module->name, decl->name.string); + codegen_ast(context, decl->func.body, 0); +} + +static void codegen_struct_member(Context *context, Decl *decl, int indent) +{ + indent_line(context, indent); + switch (decl->decl_kind) + { + case DECL_VAR: + PRINTTYPE(decl->var.type); + PRINTF(" %s;\n", decl->name.string); + return; + case DECL_STRUCT: + case DECL_UNION: + break; + default: + UNREACHABLE + } + const char* type = decl->decl_kind == DECL_UNION ? "union" : "struct"; + PRINTF("%s {\n", type); + VECEACH(decl->strukt.members, i) + { + codegen_struct_member(context, decl->strukt.members[i], indent + 1); + } + indent_line(context, indent); + PRINTF("};\n"); +} + +static inline void codegen_struct_union(Context *context, Decl *decl) +{ + const char* type = decl->decl_kind == DECL_UNION ? "union" : "struct"; + PRINTF("typedef %s _%s_%s\n", type, decl->module->name, decl->name.string); + PRINTF("{\n"); + VECEACH(decl->strukt.members, i) + { + codegen_struct_member(context, decl->strukt.members[i], 1); + } + PRINTF("} %s_%s;\n\n", decl->module->name, decl->name.string); +} + +static inline void codegen_decl(Context *context, Decl *decl) +{ + switch (decl->decl_kind) + { + case DECL_POISONED: + FATAL_ERROR("Tried to codegen broken code"); + return; + case DECL_FUNC: + codegen_func(context, decl); + return; + case DECL_VAR: + break; + case DECL_ENUM_CONSTANT: + break; + case DECL_TYPEDEF: + break; + case DECL_STRUCT: + case DECL_UNION: + codegen_struct_union(context, decl); + return; + case DECL_ENUM: + break; + case DECL_ERROR: + break; + case DECL_ERROR_CONSTANT: + break; + case DECL_ARRAY_VALUE: + break; + case DECL_IMPORT: + break; + case DECL_MACRO: + break; + case DECL_MULTI_DECL: + break; + case DECL_GENERIC: + break; + case DECL_CT_IF: + break; + case DECL_CT_ELSE: + break; + case DECL_CT_ELIF: + break; + } + TODO +} +void codegen(Context *context) +{ + VECEACH(context->declarations, i) + { + codegen_decl(context, context->declarations[i]); + } +} \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index d397d5769..50efe2dd6 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -2,17 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include -#include -#include "compiler.h" -#include "symtab.h" +#include "compiler_internal.h" #include "../build/build_options.h" -#include "../utils/lib.h" -#include "lexer.h" -#include "source_file.h" -#include "parser.h" -#include "diagnostics.h" -#include "semantic_analyser.h" void compiler_init(void) { @@ -40,7 +31,7 @@ static void compiler_lex() void compiler_parse() { - type_setup(build_options.pointer_size); + builtin_setup(); VECEACH(build_options.files, i) { bool loaded = false; @@ -55,7 +46,7 @@ void compiler_parse() void compiler_compile() { - type_setup(build_options.pointer_size); + builtin_setup(); VECEACH(build_options.files, i) { bool loaded = false; @@ -64,6 +55,8 @@ void compiler_compile() diag_reset(); parse_file(file); sema_analysis(current_context); + current_context->codegen_output = stdout; + codegen(current_context); } exit(EXIT_SUCCESS); } diff --git a/src/compiler/compiler.h b/src/compiler/compiler.h index 2c1fdfd2b..cc465f184 100644 --- a/src/compiler/compiler.h +++ b/src/compiler/compiler.h @@ -4,6 +4,5 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. - void compiler_init(); void compile_file(); diff --git a/src/compiler/compiler_common.h b/src/compiler/compiler_common.h deleted file mode 100644 index 10f48705b..000000000 --- a/src/compiler/compiler_common.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "tokens.h" -#include "utils/common.h" -#include "symtab.h" - -typedef uint32_t SourceLoc; -#define INVALID_LOC UINT32_MAX -#define INVALID_RANGE ((SourceRange){ .loc = UINT32_MAX }) -#define EMPTY_TOKEN ((Token) { .string = NULL }) -typedef struct _Decl Decl; -typedef struct _Type Type; -typedef struct _Expr Expr; -typedef struct _Ast Ast; - -typedef enum { - IMPORT_TYPE_FULL, - IMPORT_TYPE_ALIAS, - IMPORT_TYPE_ALIAS_LOCAL, - IMPORT_TYPE_LOCAL -} ImportType; - -typedef enum -{ - VISIBLE_MODULE, - VISIBLE_LOCAL, - VISIBLE_PUBLIC, -} Visibility; - -typedef enum -{ - RESOLVE_NOT_DONE, - RESOLVE_RUNNING, - RESOLVE_DONE -} ResolveStatus; - -typedef struct -{ - SourceLoc loc; - uint32_t length; -} SourceRange; - - -typedef struct -{ - SourceRange span; - TokenType type : 8; - union - { - const char *string; - const char* start; - }; -} Token; - -#define TOK2VARSTR(_token) _token.span.length, _token.start - -static inline Token wrap(const char *string) -{ - return (Token) { .span = INVALID_RANGE, .type = TOKEN_IDENT, .string = string }; -} - -typedef struct -{ - const char *contents; - const char *name; - const char *full_path; - SourceLoc start_id; - SourceLoc end_id; -} File; - -typedef enum -{ - LEXER_STATE_NORMAL, - LEXER_STATE_DEFERED_PARSING, - LEXER_STATE_DOCS_PARSE, - LEXER_STATE_DOCS_PARSE_DIRECTIVE, -} LexerState; - - -#define TOKEN_MAX_LENGTH 0xFFFF - diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h new file mode 100644 index 000000000..bb0ee62a7 --- /dev/null +++ b/src/compiler/compiler_internal.h @@ -0,0 +1,820 @@ +#pragma once +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "../utils/common.h" +#include "../utils/errors.h" +#include "../utils/lib.h" +#include "../build/build_options.h" +#include "compiler.h" +#include "enums.h" + +typedef uint32_t SourceLoc; +#define INVALID_LOC UINT32_MAX +#define INVALID_RANGE ((SourceRange){ .loc = UINT32_MAX }) +#define EMPTY_TOKEN ((Token) { .string = NULL }) +#define MAX_LOCALS 0xFFFF +#define MAX_SCOPE_DEPTH 0xFF + + +typedef struct _Ast Ast; +typedef struct _Decl Decl; +typedef struct _Type Type; +typedef struct _Expr Expr; +typedef struct _Module Module; + +typedef bool(*CastFunc)(Expr*, Type*, Type*, CastType cast_type); + +typedef struct +{ + SourceLoc loc; + uint32_t length; +} SourceRange; + + +typedef struct +{ + SourceRange span; + TokenType type : 8; + union + { + const char *string; + const char* start; + }; +} Token; + +typedef struct _Diagnostics +{ + bool panic_mode; + unsigned errors; + unsigned warnings; +} Diagnostics; + +typedef struct +{ + const char *key; + void *value; +} SEntry; + +typedef struct +{ + uint32_t count; + uint32_t capacity; + SEntry *entries; +} STable; + + +typedef struct +{ + const char *contents; + const char *name; + const char *full_path; + SourceLoc start_id; + SourceLoc end_id; +} File; + + +struct _Type +{ + TypeKind type_kind : 6; + ResolveStatus resolve_status : 2; + Type *canonical; + Token name_loc; + Type **ptr_like_canonical; + union + { + Decl *decl; + struct + { + unsigned bitsize : 16; + unsigned char bytesize; + } builtin; + struct + { + Token module; + } unresolved; + Expr *unresolved_type_expr; + struct + { + Type *base; + union + { + Expr *unresolved_len; + size_t len; + bool nullable; + }; + }; + }; +}; + +typedef struct +{ + Token module; + Token name; + union + { + Expr *expr; + }; +} Attr; + +typedef struct +{ + Decl **error_constants; +} ErrorDecl; + +typedef struct +{ + ImportType type : 3; + Token alias; + Expr** generic_parameters; + struct _Module *module; +} ImportDecl; + +typedef struct +{ + Decl **members; + Decl **method_functions; +} StructDecl; + + +typedef struct _VarDecl +{ + VarDeclKind kind : 3; + Type *type; + Expr *init_expr; +} VarDecl; + + +typedef struct +{ + Expr *expr; + Decl **then; + Decl *elif; +} CtIfDecl; + + +typedef struct +{ + Decl *parent; + Expr *expr; +} EnumConstantDecl; + +typedef struct +{ + Decl *parent; + uint32_t value; +} ErrorConstantDecl; + +typedef struct +{ + Decl** values; + Type *type; +} EnumDecl; + + +typedef struct +{ + bool variadic : 1; + Type *rtype; + Decl** params; + Token *throws; +} FunctionSignature; + +typedef struct +{ + const char *full_name; + Type *struct_parent; + FunctionSignature function_signature; + struct _Ast *body; +} FuncDecl; + +typedef struct +{ + bool is_func : 1; + union + { + FunctionSignature function_signature; + Type *type; + }; +} TypedefDecl; + +typedef struct +{ + Decl **parameters; + Type *rtype; // May be null! + struct _Ast *body; +} MacroDecl; + +typedef struct +{ + struct _Ast **cases; + Token *parameters; + Type *rtype; // May be null! +} GenericDecl; + + +typedef struct _Decl +{ + Token name; + DeclKind decl_kind : 6; + Visibility visibility : 2; + ResolveStatus resolve_status : 2; +/* bool is_exported : 1; + bool is_used : 1; + bool is_used_public : 1; + bool has_cname : 1; + uint32_t alignment : 5; + union + { + uint32_t offset; + uint32_t counter; + }; + uint32_t size;*/ + Type *self_type; + struct _Module *module; + Attr** attributes; + union + { + ErrorDecl error; + ErrorConstantDecl error_constant; + ImportDecl import; + StructDecl strukt; + VarDecl var; + EnumDecl enums; + EnumConstantDecl enum_constant; + FuncDecl func; + TypedefDecl typedef_decl; + Decl** multi_decl; + MacroDecl macro_decl; + GenericDecl generic_decl; + CtIfDecl ct_if_decl; + CtIfDecl ct_elif_decl; + Decl** ct_else_decl; + }; +} Decl; + +typedef struct +{ + Expr *expr; + Expr *else_expr; +} ExprTry; + +typedef struct +{ + Type *type; + Token method; +} ExprMethodRef; + +typedef struct +{ + Type *type; + Expr *init_expr; +} ExprStructValue; + +typedef struct +{ + Expr *cond; + Expr *then_expr; // May be null for elvis! + Expr *else_expr; +} ExprTernary; + +typedef struct +{ + Expr *left; + Expr *right; + BinOp operator; +} ExprBinary; + +typedef struct +{ + Expr *left; + Expr *right; + AssignOp operator; +} ExprAssign; + +typedef struct +{ + Expr* expr; + UnaryOp operator; +} ExprUnary; + + +typedef struct +{ + union + { + long double f; + uint64_t i; + bool b; + struct + { + char* chars; + int len; + } string; + }; + ConstType type : 3; +} ExprConst; + +typedef struct +{ + bool is_struct_function; + Expr *function; + Expr **parameters; +} ExprCall; + +typedef struct +{ + Expr *expr; + Expr *index; +} ExprSubscript; + +typedef struct +{ + Expr *parent; + Token sub_element; +} ExprAccess; + +typedef struct +{ + Token module; + Token identifier; + bool is_ref; + Decl *decl; +} ExprIdentifier; + +typedef struct +{ + Type *type; +} ExprType; + + +typedef struct +{ + CastKind kind; + Expr *expr; + union + { + size_t truncated_size; + }; +} ExprCast; + +struct _Expr +{ + ExprKind expr_kind : 8; + ResolveStatus resolve_status : 3; + Token loc; + Type *type; + + union { + Token* deferred_tokens; + Token deferred_token; + ExprCast expr_cast; + ExprConst const_expr; + ExprStructValue struct_value_expr; + ExprMethodRef method_ref_expr; + ExprTry try_expr; + ExprBinary binary_expr; + ExprAssign assign_expr; + ExprTernary conditional_expr; + ExprUnary unary_expr; + ExprUnary post_expr; + ExprCall call_expr; + ExprSubscript subscript_expr; + ExprAccess access_expr; + ExprIdentifier identifier_expr; + ExprType type_expr; + Expr** initializer_expr; + Expr** expression_list; + }; +}; + +typedef struct +{ + +} AstAttribute; + + +typedef struct +{ + struct _Ast **stmts; +// DeferList defer_list; TODO +} AstCompoundStmt; + +typedef struct +{ + uint16_t last_goto; + bool is_used : 1; + struct _Ast *defer; + struct _Ast *in_defer; +} AstLabelStmt; + +typedef struct +{ + Expr *expr; // May be NULL + struct _Ast *defer; +} AstReturnStmt; + +typedef struct +{ + Ast *cond; + Ast *body; +} AstWhileStmt; + +typedef struct +{ + Expr *expr; + Ast *body; +} AstDoStmt; + +typedef struct +{ + Ast *cond; + Ast *then_body; + Ast *else_body; +} AstIfStmt; + + +typedef struct +{ + Expr *expr; +} AstCaseStmt; + +typedef struct +{ + Ast *cond; + Ast *body; +} AstSwitchStmt; + +typedef struct +{ + Ast *init; + Expr *cond; + Expr *incr; + Ast *body; +} AstForStmt; + + +typedef struct +{ + Decl *decl; + Ast *decl_expr; +} AstCondStmt; + + +typedef struct +{ + DeclExprType list_type : 2; + union + { + Decl *decl; + Expr *expr; + }; +} AstDeclExprList; + + +typedef struct +{ + GotoType type : 2; + struct _Ast *defer; + union + { + struct _Ast *in_defer; + struct _Ast *defer_end; + }; +} AstGotoStmt; + +typedef struct _AstDeferStmt +{ + bool emit_boolean : 1; + struct _Ast *body; // Compound statement + struct _Ast *prev_defer; +} AstDeferStmt; + +typedef struct _AstCatchStmt +{ + Decl *error_param; + struct _Ast *body; +} AstCatchStmt; + +typedef struct _AstCtIfStmt +{ + Expr *expr; + struct _Ast *then; + struct _Ast *elif; +} AstCtIfStmt; + + +typedef struct _AstGenericCaseStmt +{ + Type **types; + struct _Ast *body; +} AstGenericCaseStmt; + +typedef struct _Ast +{ + AstKind ast_kind : 8; + ExitType exit : 3; + Token token; + + union + { + AstAttribute attribute; + AstCompoundStmt compound_stmt; + Decl *declare_stmt; + Expr *expr_stmt; + Expr *throw_stmt; + struct _Ast *volatile_stmt; + struct _Ast *try_stmt; + AstLabelStmt label_stmt; + AstReturnStmt return_stmt; + AstWhileStmt while_stmt; + AstDoStmt do_stmt; + AstIfStmt if_stmt; + AstDeferStmt defer_stmt; + AstSwitchStmt switch_stmt; + AstCaseStmt case_stmt; + AstCatchStmt catch_stmt; + AstGotoStmt goto_stmt; + AstForStmt for_stmt; + AstCondStmt cond_stmt; + AstCtIfStmt ct_if_stmt; + AstCtIfStmt ct_elif_stmt; + struct _Ast* ct_else_stmt; + AstDeclExprList decl_expr_list; + AstGenericCaseStmt generic_case_stmt; + struct _Ast* generic_default_stmt; + }; +} Ast; + + + +typedef struct _Module +{ + const char *name; + + bool is_external; + bool is_c_library; + bool is_exported; + + Ast **files; // Asts + + Decl** functions; + STable struct_functions; + STable symbols; + STable public_symbols; +} Module; + +typedef struct _DynamicScope +{ + int flags; + int flags_created; + unsigned errors; + Decl **local_decl_start; + Ast *defer_stack_start; + Ast *active_defer; +} DynamicScope; + +typedef struct _Context +{ + Token module_name; + Token* module_parameters; + File * file; + Decl** imports; + Module *module; + STable local_symbols; + Decl **declarations; + Decl **ct_ifs; + Decl *active_function_for_analysis; + FILE *codegen_output; + Decl *locals[MAX_LOCALS]; + Decl **last_local; + DynamicScope scopes[MAX_SCOPE_DEPTH]; + DynamicScope *current_scope; +} Context; + +extern Context *current_context; + +extern Ast poisoned_ast; +extern Decl poisoned_decl; +extern Expr poisoned_expr; +extern Type poisoned_type; +extern Module poisoned_module; + +extern Token next_tok; +extern Token tok; + +extern Type type_bool, type_void, type_string; +extern Type type_half, type_float, type_double, type_quad; +extern Type type_char, type_short, type_int, type_long, type_isize; +extern Type type_byte, type_ushort, type_uint, type_ulong, type_usize; +extern Type type_compint, type_compuint, type_compfloat; +extern Type type_c_short, type_c_int, type_c_long, type_c_longlong; +extern Type type_c_ushort, type_c_uint, type_c_ulong, type_c_ulonglong; + +#define AST_NEW(_kind, _token) new_ast(_kind, _token) + +static inline bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; } +static inline void ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; } +static inline Ast *new_ast(AstKind kind, Token token) +{ + Ast *ast = malloc_arena(sizeof(Ast)); + memset(ast, 0, sizeof(Ast)); + ast->token = token; + ast->ast_kind = kind; + ast->exit = EXIT_NONE; + return ast; +} + + +void builtin_setup(); + +static inline bool builtin_may_negate(Type *canonical) +{ + assert(canonical->canonical == canonical); + switch (canonical->type_kind) + { + case TYPE_FXX: + case TYPE_F32: + case TYPE_F64: + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_IXX: + return true; + default: + return false; + } +} + +static inline bool builtin_may_bit_negate(Type *canonical) +{ + assert(canonical->canonical == canonical); + switch (canonical->type_kind) + { + case TYPE_BOOL: + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_IXX: + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_UXX: + return true; + default: + return false; + } +} + +static inline ConstType sign_from_type(Type *type) +{ + assert(type->canonical == type); + TODO // return (type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX) ? CONST_INT : CONST_UINT; +} + +bool cast(Expr *expr, Type *to_type, CastType cast_type); + + +void codegen(Context *context); + + + + + +Context *context_create(File *file); +void context_push(Context *context); +void context_register_global_decl(Context *context, Decl *decl); +bool context_add_import(Context *context, Token module_name, Token alias, ImportType import_type, Expr** generic_parameters); +bool context_set_module_from_filename(Context *context); +bool context_set_module(Context *context, Token module_name, Token *generic_parameters); +void context_print_ast(Context *context, FILE *file); + +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; return decl; } +static inline DeclKind decl_from_token(TokenType type) +{ + if (type == TOKEN_STRUCT) return DECL_STRUCT; + if (type == TOKEN_UNION) return DECL_UNION; + UNREACHABLE +} + +void diag_reset(void); +void diag_error_range(SourceRange span, const char *message, ...); +void diag_verror_range(SourceRange span, const char *message, va_list args); + + +#define EXPR_NEW_EXPR(_kind, _expr) expr_new(_kind, _expr->loc) +#define EXPR_NEW_TOKEN(_kind, _tok) expr_new(_kind, _tok) +Expr *expr_new(ExprKind kind, Token start); +static inline bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; } +static inline void expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; } + +void fprint_ast(FILE *file, Ast *ast); +void fprint_decl(FILE *file, Decl *dec); +void fprint_type_recursive(FILE *file, Type *type, int indent); +void fprint_expr_recursive(FILE *file, Expr *expr, int indent); + + +Token lexer_scan_token(void); +Token lexer_scan_ident_test(const char *scan); +void lexer_test_setup(const char *text, size_t len); +void lexer_add_file_for_lexing(File *file); +File* lexer_current_file(void); +void lexer_check_init(void); +void lexer_store_state(void); +void lexer_restore_state(void); + +static inline void advance(void) +{ + tok = next_tok; + while (1) + { + next_tok = lexer_scan_token(); + // printf(">>> %.*s => %s\n", tok.length, tok.start, token_type_to_string(tok.type)); + if (next_tok.type != TOKEN_INVALID_TOKEN) break; + } +} + +static inline void advance_and_verify(TokenType token_type) +{ + assert(tok.type == token_type); + advance(); +} + +void parse_file(File *file); + +#define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__) +void sema_init(File *file); +void sema_analysis(Context *context); +bool sema_const_fold_binary(Context *context, Expr *expr); +void sema_error_at(SourceLoc loc, const char *message, ...); +void sema_error_range(SourceRange range, const char *message, ...); +void sema_verror_at(SourceLoc loc, const char *message, va_list args); +void sema_verror_range(SourceRange range, const char *message, va_list args); +void sema_error(const char *message, ...); +void sema_prev_at_range(SourceRange span, const char *message, ...); +void sema_prev_at(SourceLoc loc, const char *message, ...); + + +File *source_file_load(const char *filename, bool *already_loaded); +File *source_file_from_position(SourceLoc loc); + + +void stable_init(STable *table, uint32_t initial_size); +void *stable_set(STable *table, const char *key, void *value); +void *stable_get(STable *table, const char *key); +void *stable_delete(STable *table, const char *key); +void stable_clear(STable *table); + +void symtab_init(uint32_t max_size); +const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type); + +#define TOKEN_MAX_LENGTH 0xFFFF +#define TOK2VARSTR(_token) _token.span.length, _token.start +bool token_is_type(TokenType type); +const char *token_type_to_string(TokenType type); +static inline Token wrap(const char *string) +{ + return (Token) { .span = INVALID_RANGE, .type = TOKEN_IDENT, .string = string }; +} + +Type *type_new(TypeKind type_kind); +Type *type_get_canonical_ptr(Type *ptr_type); +Type *type_get_canonical_array(Type *arr_type); +Type *type_signed_int_by_size(int bitsize); +Type *type_unsigned_int_by_size(int bitsize); + +size_t type_size(Type *canonical); +static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; } +static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX; } +static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_UXX; } +static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; } +static inline void type_poison(Type *type) { type->type_kind = TYPE_POISONED; type->resolve_status = RESOLVE_DONE; } + +#define TYPE_MODULE_UNRESOLVED(_module, _name) ({ Type *__type = type_new(TYPE_USER_DEFINED); \ + __type->name_loc = _name; __type->unresolved.module = _module; __type; }) +#define TYPE_UNRESOLVED(_name) ({ Type *__type = type_new(TYPE_USER_DEFINED); __type->name_loc = _name; __type; }) + +AssignOp assignop_from_token(TokenType type); +BinOp binop_from_token(TokenType type); +TokenType binop_to_token(BinOp type); +UnaryOp unaryop_from_token(TokenType type); +Decl *struct_find_name(Decl *decl, const char* name); + + +static inline const char* struct_union_name_from_token(TokenType type) +{ + return type == TOKEN_STRUCT ? "struct" : "union"; +} + + + + + diff --git a/src/compiler/const_folding.c b/src/compiler/const_folding.c new file mode 100644 index 000000000..30aedfe48 --- /dev/null +++ b/src/compiler/const_folding.c @@ -0,0 +1,158 @@ +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "compiler_internal.h" + +#define COMP_OP(comp) \ +switch (left->type)\ +{ case CONST_NIL: result->b = 0 comp 0; break;\ +case CONST_BOOL: result->b = left->b comp right->b; break;\ +case CONST_STRING: UNREACHABLE;\ +case CONST_FLOAT: result->b = left->f comp right->f; break;\ +case CONST_INT: result->b = left->i comp right->i; break;\ +default: UNREACHABLE }\ +result->type = CONST_BOOL; expr->expr_kind = EXPR_CONST; expr->type = &type_bool; return true; + +#define BOOL_COMP(comp) \ +switch (left->type)\ +{ case CONST_NIL: result->b = 0 comp 0; break;\ +case CONST_BOOL: result->b = left->b comp right->b; break;\ +case CONST_STRING: UNREACHABLE;\ +case CONST_FLOAT: result->b = (left->f != 0) comp (right->f != 0); break;\ +case CONST_INT: result->b = (left->i != 0) comp (right->i != 0); break;\ +default: break; }\ +result->type = CONST_BOOL; expr->expr_kind = EXPR_CONST; expr->type = &type_bool; return true + +#define BITOP(op)\ +switch (left->type)\ +{ case CONST_NIL: break; \ +case CONST_BOOL: result->b = left->b op right->b; break; \ +case CONST_STRING: case CONST_FLOAT: UNREACHABLE; \ +case CONST_INT: result->b = left->i op right->i; break; \ +default: UNREACHABLE; \ +} break + +#define ARITH(op)\ +switch (left->type)\ +{ case CONST_NIL: case CONST_BOOL: case CONST_STRING: UNREACHABLE; \ +case CONST_FLOAT: result->f = left->f op right->f; break;\ +case CONST_INT: result->i = left->i op right->i; break; \ +default: UNREACHABLE; \ +} break + +bool sema_const_fold_binary(Context *context, Expr *expr) +{ + Expr *left_expr = expr->binary_expr.left; + Expr *right_expr = expr->binary_expr.right; + + if (left_expr->expr_kind != EXPR_CONST || right_expr->expr_kind != EXPR_CONST) return true; + Type *type = left_expr->type->canonical; + assert(type == right_expr->type->canonical); + ExprConst *left = &left_expr->const_expr; + ExprConst *right = &right_expr->const_expr; + ExprConst *result = &expr->const_expr; + switch (expr->binary_expr.operator) + { + case BINOP_ERROR: + case BINOP_ASSIGN: + case BINOP_MULT_ASSIGN: + case BINOP_ADD_ASSIGN: + case BINOP_SUB_ASSIGN: + case BINOP_DIV_ASSIGN: + case BINOP_MOD_ASSIGN: + case BINOP_AND_ASSIGN: + case BINOP_OR_ASSIGN: + case BINOP_BIT_AND_ASSIGN: + case BINOP_BIT_OR_ASSIGN: + case BINOP_BIT_XOR_ASSIGN: + case BINOP_SHR_ASSIGN: + case BINOP_SHL_ASSIGN: + SEMA_ERROR(expr->loc, "Invalid operation '%s' %s '%s.", left_expr->type->name_loc.string, token_type_to_string(binop_to_token(expr->binary_expr.operator)), right_expr->type->name_loc.string); + return false; + case BINOP_MULT: + ARITH(*); + case BINOP_ADD: + ARITH(+); + case BINOP_SUB: + ARITH(-); + case BINOP_DIV: + switch (left->type) + { + case CONST_NIL: + case CONST_BOOL: + case CONST_STRING: + UNREACHABLE; + case CONST_INT: + if (right->i == 0) + { + SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); + return false; + } + result->i = left->i / right->i; + break; + case CONST_FLOAT: + if (right->f == 0) + { + SEMA_ERROR(expr->binary_expr.right->loc, "Division by zero not allowed."); + return false; + } + expr->const_expr.f = left->f / right->f; + expr->const_expr.type = CONST_FLOAT; + break; + } + break; + case BINOP_MOD: + switch (left->type) + { + case CONST_NIL: + case CONST_BOOL: + case CONST_STRING: + case CONST_FLOAT: + UNREACHABLE; + case CONST_INT: + if (right->i == 0) + { + SEMA_ERROR(expr->binary_expr.right->loc, "Cannot do mod by zero."); + return false; + } + result->i = left->i % right->i; + break; + } + break; + case BINOP_AND: + BOOL_COMP(&&); + case BINOP_OR: + BOOL_COMP(||); + case BINOP_BIT_AND: + BITOP(&); + case BINOP_BIT_OR: + BITOP(|); + case BINOP_BIT_XOR: + BITOP(^); + case BINOP_NE: + COMP_OP(!=) + case BINOP_EQ: + COMP_OP(==) + case BINOP_GE: + COMP_OP(>=) + case BINOP_GT: + COMP_OP(>) + case BINOP_LE: + COMP_OP(<=) + case BINOP_LT: + COMP_OP(<) + case BINOP_SHR: + TODO + break; + case BINOP_SHL: + TODO + break; + case BINOP_ELVIS: + TODO + break; + } + expr->type = type; + expr->expr_kind = EXPR_CONST; + return true; +} diff --git a/src/compiler/context.c b/src/compiler/context.c index 18b60d681..654878836 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -2,10 +2,7 @@ // Created by Christoffer Lerno on 2019-08-24. // -#include -#include -#include "context.h" -#include "diagnostics.h" +#include "compiler_internal.h" Context *current_context; @@ -85,6 +82,7 @@ bool context_set_module(Context *context, Token module_name, Token *generic_para void context_register_global_decl(Context *context, Decl *decl) { + decl->module = context->module; if (decl->decl_kind == DECL_CT_IF) { context->ct_ifs = VECADD(context->ct_ifs, decl); @@ -105,7 +103,7 @@ bool context_add_import(Context *context, Token module_name, Token alias, Import sema_error_range(module_name.span, "A module is not expected to have any upper case characters, please change it."); return false; } - Decl *decl = decl_new_in_module(context->module, DECL_IMPORT, module_name, VISIBLE_LOCAL); + Decl *decl = decl_new(DECL_IMPORT, module_name, VISIBLE_LOCAL); decl->import.type = import_type; decl->import.generic_parameters = generic_parameters; if (import_type == IMPORT_TYPE_ALIAS_LOCAL || import_type == IMPORT_TYPE_ALIAS) diff --git a/src/compiler/context.h b/src/compiler/context.h deleted file mode 100644 index 0523d668b..000000000 --- a/src/compiler/context.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "compiler_common.h" -#include "ast.h" - -typedef struct _Context -{ - Token module_name; - Token* module_parameters; - File * file; - Decl** imports; - Module *module; - STable local_symbols; - Decl **declarations; - Decl **ct_ifs; - Decl *active_function_for_analysis; -} Context; - -extern Context *current_context; - -Context *context_create(File *file); -void context_push(Context *context); - -void context_register_global_decl(Context *context, Decl *decl); -bool context_add_import(Context *context, Token module_name, Token alias, ImportType import_type, Expr** generic_parameters); -bool context_set_module_from_filename(Context *context); -bool context_set_module(Context *context, Token module_name, Token *generic_parameters); -void context_print_ast(Context *context, FILE *file); - diff --git a/src/compiler/diagnostics.c b/src/compiler/diagnostics.c index d320a0219..480315774 100644 --- a/src/compiler/diagnostics.c +++ b/src/compiler/diagnostics.c @@ -2,18 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "diagnostics.h" -#include "source_file.h" -#include "lexer.h" +#include "compiler_internal.h" #include -#include - -typedef struct _Diagnostics -{ - bool panic_mode; - unsigned errors; - unsigned warnings; -} Diagnostics; Diagnostics diagnostics; diff --git a/src/compiler/diagnostics.h b/src/compiler/diagnostics.h deleted file mode 100644 index 15eedcca4..000000000 --- a/src/compiler/diagnostics.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "compiler_common.h" - -void diag_reset(void); -void diag_error_range(SourceRange span, const char *message, ...); -void diag_verror_range(SourceRange span, const char *message, va_list args); -void sema_error_at(SourceLoc loc, const char *message, ...); -void sema_error_range(SourceRange range, const char *message, ...); -void sema_verror_at(SourceLoc loc, const char *message, va_list args); -void sema_verror_range(SourceRange range, const char *message, va_list args); -void sema_error(const char *message, ...); -void sema_prev_at_range(SourceRange span, const char *message, ...); -void sema_prev_at(SourceLoc loc, const char *message, ...); - -#define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__) - -/* - - -typedef struct _Array Array; - -void diagnostics_init(void); -void diagnostics_reset(void); -void diagnostics_update_severity(DiagnosticsSeverity severity, DiagnosticsType type); -bool diagnostics_silence_warnings(Array *warnings); -void diagnostics_use_color(bool use_color); -void verror_at(SourceRange span, const char *message, va_list args); -void sema_error_range(SourceRange token, const char *message, ...); -void sema_error_at(SourceLoc loc, const char *message, ...); -void prev_at_range(SourceRange span, const char *message, ...); -void prev_at(SourceLoc loc, const char *message, ...); -void sema_warn_at(DiagnosticsType type, SourceLoc loc, const char *message, ...); -void sema_warn_range(DiagnosticsType type, SourceRange span, const char *message, ...); -bool in_panic_mode(void); -unsigned errors(); -void reset_panic_mode(void); -bool error_found(void); -*/ \ No newline at end of file diff --git a/src/compiler/enums.h b/src/compiler/enums.h new file mode 100644 index 000000000..31b39b544 --- /dev/null +++ b/src/compiler/enums.h @@ -0,0 +1,525 @@ +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Only include this from compiler_common.h + +typedef enum +{ + ASSIGNOP_ERROR, + ASSIGNOP_ASSIGN, + ASSIGNOP_MULT_ASSIGN, + ASSIGNOP_ADD_ASSIGN, + ASSIGNOP_SUB_ASSIGN, + ASSIGNOP_DIV_ASSIGN, + ASSIGNOP_MOD_ASSIGN, + ASSIGNOP_AND_ASSIGN, + ASSIGNOP_OR_ASSIGN, + ASSIGNOP_BIT_AND_ASSIGN, + ASSIGNOP_BIT_OR_ASSIGN, + ASSIGNOP_BIT_XOR_ASSIGN, + ASSIGNOP_SHR_ASSIGN, + ASSIGNOP_SHL_ASSIGN, +} AssignOp; + +typedef enum +{ + AST_POISONED, + AST_ASM_STMT, + AST_ATTRIBUTE, + AST_BREAK_STMT, + AST_CASE_STMT, + AST_CATCH_STMT, + AST_COMPOUND_STMT, + AST_COND_STMT, + AST_CONTINUE_STMT, + AST_CT_IF_STMT, + AST_CT_ELIF_STMT, + AST_CT_ELSE_STMT, + AST_DECLARE_STMT, + AST_DECL_EXPR_LIST, + AST_DEFAULT_STMT, + AST_DEFER_STMT, + AST_DO_STMT, + AST_EXPR_STMT, + AST_FOR_STMT, + AST_GOTO_STMT, + AST_IF_STMT, + AST_LABEL, + AST_NOP_STMT, + AST_RETURN_STMT, + AST_SWITCH_STMT, + AST_THROW_STMT, + AST_TRY_STMT, + AST_NEXT_STMT, + AST_VOLATILE_STMT, + AST_WHILE_STMT, + AST_GENERIC_CASE_STMT, + AST_GENERIC_DEFAULT_STMT, +} AstKind; + +typedef enum +{ + ATTR_INVALID, + ATTR_UNRESOLVED, +} AttrKind; + +typedef enum +{ + BINOP_ERROR, + BINOP_ASSIGN, + BINOP_MULT, + BINOP_MULT_ASSIGN, + BINOP_ADD, + BINOP_ADD_ASSIGN, + BINOP_SUB, + BINOP_SUB_ASSIGN, + BINOP_DIV, + BINOP_DIV_ASSIGN, + BINOP_MOD, + BINOP_MOD_ASSIGN, + BINOP_AND, + BINOP_AND_ASSIGN, + BINOP_OR, + BINOP_OR_ASSIGN, + BINOP_BIT_AND, + BINOP_BIT_AND_ASSIGN, + BINOP_BIT_OR, + BINOP_BIT_OR_ASSIGN, + BINOP_BIT_XOR, + BINOP_BIT_XOR_ASSIGN, + BINOP_NE, + BINOP_EQ, + BINOP_GE, + BINOP_GT, + BINOP_LE, + BINOP_LT, + BINOP_SHR, + BINOP_SHR_ASSIGN, + BINOP_SHL, + BINOP_SHL_ASSIGN, + BINOP_ELVIS +} BinOp; + +typedef enum +{ + CAST_ERROR, + CAST_TRUNC, + CAST_PTRPTR, + CAST_PTRINT, + CAST_VARRPTR, + CAST_ARRPTR, + CAST_STRPTR, + CAST_PTRBOOL, + CAST_BOOLINT, + CAST_BOOLFP, + CAST_INTBOOL, + CAST_FPFP, + CAST_FPSI, + CAST_FPUI, + CAST_SISI, + CAST_SIUI, + CAST_SIFP, + CAST_XIPTR, + CAST_UISI, + CAST_UIUI, + CAST_UIFP, + CAST_ENUMSI, + /* + CAST_NONE, + CAST_INLINE, + CAST_FAILED, + CAST_SUBTYPE, + CAST_VARRPTR, + CAST_STRPTR, + CAST_ARRPTR, + CAST_INTPTR, + CAST_PTRINT, + CAST_PTRBOOL, + CAST_FPFP, + CAST_FPUI, + CAST_FPSI, + CAST_FPBOOL, + CAST_UIFP, + CAST_UIUI, + CAST_UISI, + CAST_SIFP, + CAST_SISI, + CAST_SIUI, + CAST_INTBOOL, + CAST_BOOLFP, + CAST_BOOLINT, + CAST_RVALUE,*/ +} CastKind; + +typedef enum _CastType +{ + CAST_TYPE_EXPLICIT, + CAST_TYPE_IMPLICIT, + CAST_TYPE_IMPLICIT_ASSIGN, + CAST_TYPE_IMPLICIT_ASSIGN_ADD, +} CastType; + +typedef enum +{ + CONST_NIL, + CONST_BOOL, + CONST_INT, + CONST_FLOAT, + CONST_STRING, +} ConstType; + +typedef enum +{ + DECLEXPR_DECL, + DECLEXPR_EXPR, +} DeclExprType; + +typedef enum +{ + DECL_POISONED = 0, + DECL_FUNC, + DECL_VAR, + DECL_ENUM_CONSTANT, + DECL_TYPEDEF, + DECL_STRUCT, + DECL_UNION, + DECL_ENUM, + DECL_ERROR, + DECL_ERROR_CONSTANT, + DECL_ARRAY_VALUE, + DECL_IMPORT, + DECL_MACRO, + DECL_MULTI_DECL, + DECL_GENERIC, + DECL_CT_IF, + DECL_CT_ELSE, + DECL_CT_ELIF, +} DeclKind; + +// Ordering here is in priority if two branches should have the same exit. +typedef enum +{ + EXIT_NONE, + EXIT_BREAK, + EXIT_GOTO, + EXIT_CONTINUE, + EXIT_RETURN, +} ExitType; + +typedef enum +{ + EXPR_POISONED, + EXPR_TRY, + EXPR_CONST, + EXPR_BINARY, + EXPR_CONDITIONAL, + EXPR_UNARY, + EXPR_POST_UNARY, + EXPR_TYPE, + EXPR_IDENTIFIER, + EXPR_METHOD_REF, + EXPR_CALL, + EXPR_SIZEOF, + EXPR_SUBSCRIPT, + EXPR_ACCESS, + EXPR_STRUCT_VALUE, + EXPR_STRUCT_INIT_VALUES, + EXPR_INITIALIZER_LIST, + EXPR_EXPRESSION_LIST, + EXPR_DEFERRED_TOKENS, + EXPR_CAST, +} ExprKind; + +typedef enum +{ + GOTO_NOT_ANALYSED, + GOTO_JUMP_FORWARD, + GOTO_JUMP_BACK +} GotoType; + +typedef enum +{ + IMPORT_TYPE_FULL, + IMPORT_TYPE_ALIAS, + IMPORT_TYPE_ALIAS_LOCAL, + IMPORT_TYPE_LOCAL +} ImportType; + + +typedef enum +{ + LEXER_STATE_NORMAL, + LEXER_STATE_DEFERED_PARSING, + LEXER_STATE_DOCS_PARSE, + LEXER_STATE_DOCS_PARSE_DIRECTIVE, +} LexerState; + +typedef enum +{ + NUMBER_TYPE_BOOL, + NUMBER_TYPE_FLOAT, + NUMBER_TYPE_SIGNED_INT, + NUMBER_TYPE_UNSIGNED_INT, +} NumberType; + +typedef enum _Precedence +{ + PREC_NONE, + PREC_ASSIGNMENT, // =, *=, /=, %=, ... + PREC_CONDITIONAL, // ?: + PREC_LOGICAL, // && || + PREC_RELATIONAL, // < > <= >= == != + PREC_ADDITIVE, // + - + PREC_BIT, // ^ | & + PREC_SHIFT, // << >> >>> + PREC_MULTIPLICATIVE, // * / % + PREC_UNARY, // ! - + ~ * & prefix ++/-- + PREC_CALL, // . () [] postfix ++/-- +} Precedence; + +typedef enum +{ + RESOLVE_NOT_DONE = 0, + RESOLVE_RUNNING, + RESOLVE_DONE +} ResolveStatus; + +typedef enum +{ + TOKEN_INVALID_TOKEN = 0, + + // Single-character tokens. + TOKEN_AMP, // & + TOKEN_AT, // @ + TOKEN_BIT_NOT, // ~ + TOKEN_BIT_OR, // = + TOKEN_BIT_XOR, // ^ + TOKEN_COLON, // : + TOKEN_COMMA, // , + TOKEN_EOS, // ; + TOKEN_EQ, // = + TOKEN_GREATER, // > + TOKEN_DIV, // / + TOKEN_DOLLAR, // $ + TOKEN_DOT, // . + TOKEN_HASH, // # + TOKEN_LESS, // < + TOKEN_LBRACE, // { + TOKEN_LBRACKET, // [ + TOKEN_LPAREN, // ( + TOKEN_MINUS, // - + TOKEN_MOD, // % + TOKEN_NOT, // ! + TOKEN_OR, // | + TOKEN_PLUS, // + + TOKEN_QUESTION, // ? + TOKEN_RBRACE, // } + TOKEN_RBRACKET, // ] + TOKEN_RPAREN, // ) + TOKEN_STAR, // * + + // two character tokens. + TOKEN_AND, // && + TOKEN_ARROW, // -> // Not used but reserved + TOKEN_BIT_AND_ASSIGN, // &= + TOKEN_BIT_OR_ASSIGN, // |= + TOKEN_BIT_XOR_ASSIGN, // ^= + TOKEN_DIV_ASSIGN, // /= + TOKEN_DOTDOT, // .. + TOKEN_ELVIS, // ?: + TOKEN_EQEQ, // == + TOKEN_GREATER_EQ, // >= + TOKEN_LESS_EQ, // <= + TOKEN_MINUS_ASSIGN, // -= + TOKEN_MINUSMINUS, // -- + TOKEN_MOD_ASSIGN, // %= + TOKEN_MULT_ASSIGN, // *= + TOKEN_NOT_EQUAL, // != + TOKEN_PLUS_ASSIGN, // += + TOKEN_PLUSPLUS, // ++ + TOKEN_SCOPE, // :: + TOKEN_SHR, // >> + TOKEN_SHL, // >> + + // Three or more + TOKEN_AND_ASSIGN, // &&= + TOKEN_ELIPSIS, // ... + TOKEN_OR_ASSIGN, // ||= + TOKEN_SHR_ASSIGN, // >>= + TOKEN_SHL_ASSIGN, // >>= + + // Basic types names + TOKEN_VOID, + TOKEN_BYTE, + TOKEN_BOOL, + TOKEN_CHAR, + TOKEN_DOUBLE, + TOKEN_FLOAT, + TOKEN_HALF, + TOKEN_INT, + TOKEN_ISIZE, + TOKEN_LONG, + TOKEN_SHORT, + TOKEN_UINT, + TOKEN_ULONG, + TOKEN_USHORT, + TOKEN_USIZE, + TOKEN_QUAD, + + // C types + TOKEN_C_SHORT, + TOKEN_C_INT, + TOKEN_C_LONG, + TOKEN_C_LONGLONG, + TOKEN_C_USHORT, + TOKEN_C_UINT, + TOKEN_C_ULONG, + TOKEN_C_ULONGLONG, + + + // Literals. + + TOKEN_IDENT, // Any normal ident. + TOKEN_CONST_IDENT, // Any purely upper case ident, + TOKEN_TYPE_IDENT, // Any ident on the format FooBar or __FooBar + + // We want to parse @foo / #foo / $foo separately. + // Otherwise we allow things like "@ foo" which would be pretty bad. + TOKEN_AT_IDENT, // @foobar + TOKEN_HASH_IDENT, // #foobar + TOKEN_CT_IDENT, // $foobar + + TOKEN_STRING, // "Teststring" + TOKEN_INTEGER, // 123 0x23 0b10010 0o327 + TOKEN_REAL, // 0x23.2p-2a 43.23e23 + + // Keywords + TOKEN_ALIAS, // Reserved + TOKEN_AS, + TOKEN_ASM, + TOKEN_ATTRIBUTE, + TOKEN_BREAK, + TOKEN_CASE, + TOKEN_CAST, + TOKEN_CATCH, + TOKEN_CONST, + TOKEN_CONTINUE, + TOKEN_DEFAULT, + TOKEN_DEFER, + TOKEN_DO, + TOKEN_ELSE, + TOKEN_ENUM, + TOKEN_ERROR_TYPE, + TOKEN_FALSE, + TOKEN_FOR, + TOKEN_FUNC, + TOKEN_GENERIC, + TOKEN_GOTO, + TOKEN_IF, + TOKEN_IMPORT, + TOKEN_LOCAL, + TOKEN_MACRO, + TOKEN_MODULE, + TOKEN_NEXT, + TOKEN_NIL, + TOKEN_PUBLIC, + TOKEN_RETURN, + TOKEN_STRUCT, + TOKEN_SWITCH, + TOKEN_THROW, + TOKEN_THROWS, + TOKEN_TRUE, + TOKEN_TRY, + TOKEN_TYPE, // Reserved + TOKEN_TYPEDEF, + TOKEN_UNION, + TOKEN_UNTIL, + TOKEN_VAR, // Reserved + TOKEN_VOLATILE, + TOKEN_WHILE, + + TOKEN_AT_PARAM, // @param + TOKEN_AT_THROWS, // @throws + TOKEN_AT_RETURN, // @return + TOKEN_AT_ENSURE, // @ensure + TOKEN_AT_REQUIRE, // @require + TOKEN_AT_PURE, // @pure + TOKEN_AT_CONST, // @const + TOKEN_AT_REQPARSE, // @reqparse + TOKEN_AT_DEPRECATED, // @deprecated + + TOKEN_CT_CASE, // $case + TOKEN_CT_DEFAULT, // $default + TOKEN_CT_EACH, // $each + TOKEN_CT_ELIF, // $elif + TOKEN_CT_ELSE, // $else + TOKEN_CT_IF, // $if + TOKEN_CT_SWITCH, // $switch + + TOKEN_DOCS_START, // /** + TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*` + TOKEN_DOCS_EOL, // "\n" only seen in docs. + TOKEN_DOCS_LINE, // Any line within /** **/ + + TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN. + +} TokenType; + + +typedef enum +{ + TYPE_POISONED, + TYPE_USER_DEFINED, + TYPE_VOID, + TYPE_BOOL, + TYPE_I8, + TYPE_I16, + TYPE_I32, + TYPE_I64, + TYPE_IXX, + TYPE_U8, + TYPE_U16, + TYPE_U32, + TYPE_U64, + TYPE_UXX, + TYPE_F32, + TYPE_F64, + TYPE_FXX, + TYPE_POINTER, + TYPE_STRING, + TYPE_ARRAY, + TYPE_VARARRAY, + TYPE_INC_ARRAY, + TYPE_EXPRESSION, +} TypeKind; + +typedef enum +{ + UNARYOP_ERROR, + UNARYOP_DEREF, + UNARYOP_ADDR, + UNARYOP_NEG, + UNARYOP_BITNEG, + UNARYOP_NOT, + UNARYOP_INC, + UNARYOP_DEC, +} UnaryOp; + +typedef enum +{ + VARDECL_CONST = 0, + VARDECL_GLOBAL = 1, + VARDECL_LOCAL = 2, + VARDECL_PARAM = 3, + VARDECL_MEMBER = 4, + VARDECL_MULTI = 5, +} VarDeclKind; + +typedef enum +{ + VISIBLE_MODULE, + VISIBLE_LOCAL, + VISIBLE_PUBLIC, +} Visibility; + diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 5696ad67c..cf4c3512a 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -2,14 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "lexer.h" -#include -#include "../utils/errors.h" -#include "../utils/lib.h" -#include "symtab.h" -#include "source_file.h" -#include "diagnostics.h" -#include +#include "compiler_internal.h" + typedef struct { diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h deleted file mode 100644 index 7236a350e..000000000 --- a/src/compiler/lexer.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -#include "compiler_common.h" - -extern Token next_tok; -extern Token tok; - -Token lexer_scan_token(void); -Token lexer_scan_ident_test(const char *scan); -void lexer_test_setup(const char *text, size_t len); -void lexer_add_file_for_lexing(File *file); -File* lexer_current_file(void); -void lexer_check_init(void); -void lexer_store_state(void); -void lexer_restore_state(void); - -static inline void advance(void) -{ - tok = next_tok; - while (1) - { - next_tok = lexer_scan_token(); - // printf(">>> %.*s => %s\n", tok.length, tok.start, token_type_to_string(tok.type)); - if (next_tok.type != TOKEN_INVALID_TOKEN) break; - } -} - -static inline void advance_and_verify(TokenType token_type) -{ - assert(tok.type == token_type); - advance(); -} - - diff --git a/src/compiler/module.c b/src/compiler/module.c deleted file mode 100644 index 27297ca5d..000000000 --- a/src/compiler/module.c +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "../utils/lib.h" -#include "compiler_common.h" -#include "ast.h" - diff --git a/src/compiler/parser.c b/src/compiler/parser.c index bf2cde3ce..3136f96d2 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -2,15 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include -#include -#include "../utils/lib.h" -#include "parser.h" -#include "semantic_analyser.h" -#include "lexer.h" -#include "ast.h" -#include "diagnostics.h" -#include "context.h" +#include "compiler_internal.h" const int MAX_DOCS_ROWS = 1024; @@ -200,7 +192,7 @@ static Ast* parse_compound_stmt() { LOG_FUNC CONSUME_OR(TOKEN_LBRACE, &poisoned_ast); - Ast *ast = NEW_AST(AST_COMPOUND_STMT, tok); + Ast *ast = AST_NEW(AST_COMPOUND_STMT, tok); while (!try_consume(TOKEN_RBRACE)) { Ast *stmt = TRY_AST(parse_stmt()); @@ -238,10 +230,10 @@ static inline Type *parse_base_type(void) if (tok.type == TOKEN_IDENT && next_tok.type == TOKEN_SCOPE) { - Type *type = type_new(TYPE_UNRESOLVED); + Type *type = type_new(TYPE_USER_DEFINED); type->unresolved.module = tok; advance(); advance(); - type->unresolved.name = tok; + type->name_loc = tok; if (!consume_type_name("types")) return &poisoned_type; return type; } @@ -250,14 +242,13 @@ static inline Type *parse_base_type(void) switch (tok.type) { case TOKEN_TYPE_IDENT: - type = type_new(TYPE_UNRESOLVED); - type->unresolved.name = tok; + type = TYPE_UNRESOLVED(tok); break; case TOKEN_TYPE: advance_and_verify(TOKEN_TYPE); CONSUME_OR(TOKEN_LPAREN, &poisoned_type); { - type = type_new(TYPE_UNRESOLVED_EXPR); + type = type_new(TYPE_EXPRESSION); type->unresolved_type_expr = TRY_EXPR_OR(parse_expr(), &poisoned_type); } EXPECT_OR(TOKEN_RPAREN, &poisoned_type); @@ -304,6 +295,31 @@ static inline Type *parse_base_type(void) case TOKEN_USIZE: type = &type_usize; break; + case TOKEN_C_SHORT: + type = &type_c_short; + break; + case TOKEN_C_INT: + type = &type_c_int; + break; + case TOKEN_C_LONG: + type = &type_c_long; + break; + case TOKEN_C_LONGLONG: + type = &type_c_longlong; + break; + case TOKEN_C_USHORT: + type = &type_c_ushort; + break; + case TOKEN_C_UINT: + type = &type_c_uint; + break; + case TOKEN_C_ULONG: + type = &type_c_ulong; + break; + case TOKEN_C_ULONGLONG: + type = &type_c_ulonglong; + break; + default: SEMA_ERROR(tok, "A type name was expected here."); type = &poisoned_type; @@ -335,16 +351,17 @@ static inline Type *parse_array_type_index(Type *type) CONSUME_OR(TOKEN_RBRACKET, &poisoned_type); Type *incr_array = type_new(TYPE_INC_ARRAY); incr_array->base = type; + incr_array->resolve_status = incr_array->base->resolve_status; return incr_array; } if (try_consume(TOKEN_RBRACKET)) { - Type *array = type_new(TYPE_ARRAY); + Type *array = type_new(TYPE_VARARRAY); array->base = type; array->len = 0; return array; } - Type *array = type_new(TYPE_UNRESOLVED_ARRAY); + Type *array = type_new(TYPE_ARRAY); array->base = type; array->unresolved_len = TRY_EXPR_OR(parse_expr(), &poisoned_type); CONSUME_OR(TOKEN_RBRACKET, &poisoned_type); @@ -377,9 +394,10 @@ static Type *parse_type_expression(void) advance(); { Type *ptr_type = type_new(TYPE_POINTER); - type->base = type; - type->nullable = true; - type = ptr_type; + assert(type); + ptr_type->base = type; + ptr_type->nullable = true; + type = ptr_type; } break; case TOKEN_AMP: @@ -387,7 +405,8 @@ static Type *parse_type_expression(void) { Type *ptr_type = type_new(TYPE_POINTER); type->base = type; - type->nullable = false; + assert(type); + type->nullable = false; type = ptr_type; } break; @@ -411,7 +430,7 @@ static inline Decl *parse_decl_after_type(bool local, Type *type) advance(); Visibility visibility = local ? VISIBLE_LOCAL : VISIBLE_MODULE; - Decl *decl = decl_new_var(current_context->module, name, type, VARDECL_LOCAL, visibility); + Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, visibility); Decl *main_decl = decl; while (1) @@ -454,7 +473,7 @@ static inline Decl *parse_decl_after_type(bool local, Type *type) if (tok.type == TOKEN_IDENT) { - Decl *new_decl = decl_new_var(current_context->module, tok, type, VARDECL_LOCAL, visibility); + Decl *new_decl = decl_new_var(tok, type, VARDECL_LOCAL, visibility); advance(); if (main_decl->decl_kind == DECL_MULTI_DECL) { @@ -462,7 +481,7 @@ static inline Decl *parse_decl_after_type(bool local, Type *type) decl = new_decl; continue; } - Decl *multi = decl_new_in_module(current_context->module, DECL_MULTI_DECL, main_decl->name, visibility); + Decl *multi = decl_new(DECL_MULTI_DECL, main_decl->name, visibility); multi->multi_decl = VECADD(multi->multi_decl, main_decl); multi->multi_decl = VECADD(multi->multi_decl, new_decl); main_decl = multi; @@ -499,7 +518,7 @@ static Decl *parse_decl(void) */ static Ast *parse_declaration_stmt(void) { - Ast *decl_stmt = NEW_AST(AST_DECLARE_STMT, tok); + Ast *decl_stmt = AST_NEW(AST_DECLARE_STMT, tok); decl_stmt->declare_stmt = TRY_DECL_OR(parse_decl(), &poisoned_ast); CONSUME_OR(TOKEN_EOS, &poisoned_ast); return decl_stmt; @@ -521,7 +540,7 @@ typedef enum */ static Ast *parse_expr_stmt(void) { - Ast *stmt = NEW_AST(AST_EXPR_STMT, tok); + Ast *stmt = AST_NEW(AST_EXPR_STMT, tok); stmt->expr_stmt = TRY_EXPR_OR(parse_expr(), &poisoned_ast); TRY_CONSUME_EOS(); return stmt; @@ -561,7 +580,7 @@ static inline Ast* parse_decl_expr_list(void) Expr *expr = NULL; Type *type = NULL; - Ast *decl_expr_list = NEW_AST(AST_DECL_EXPR_LIST, tok); + Ast *decl_expr_list = AST_NEW(AST_DECL_EXPR_LIST, tok); if (!parse_type_or_expr(&expr, &type)) return &poisoned_ast; @@ -637,7 +656,7 @@ static inline Ast *parse_control_expression() static inline Ast* parse_if_stmt(void) { LOG_FUNC - Ast *if_ast = NEW_AST(AST_IF_STMT, tok); + Ast *if_ast = AST_NEW(AST_IF_STMT, tok); advance_and_verify(TOKEN_IF); CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); Ast *cond = TRY_AST(parse_control_expression()); @@ -665,7 +684,7 @@ static inline Ast* parse_if_stmt(void) static inline Ast* parse_while_stmt(void) { - Ast *while_ast = NEW_AST(AST_WHILE_STMT, tok); + Ast *while_ast = AST_NEW(AST_WHILE_STMT, tok); advance_and_verify(TOKEN_WHILE); CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); @@ -684,7 +703,7 @@ static inline Ast* parse_while_stmt(void) */ static inline Ast* parse_defer_stmt(void) { - Ast *defer_stmt = NEW_AST(AST_DEFER_STMT, tok); + Ast *defer_stmt = AST_NEW(AST_DEFER_STMT, tok); advance_and_verify(TOKEN_DEFER); defer_stmt->defer_stmt.body = TRY_AST(parse_stmt()); return defer_stmt; @@ -700,7 +719,7 @@ static inline Ast* parse_defer_stmt(void) */ static inline Ast* parse_catch_stmt(void) { - Ast *catch_stmt = NEW_AST(AST_CATCH_STMT, tok); + Ast *catch_stmt = AST_NEW(AST_CATCH_STMT, tok); advance_and_verify(TOKEN_CATCH); CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); @@ -711,7 +730,7 @@ static inline Ast* parse_catch_stmt(void) type = TRY_TYPE_OR(parse_type_expression(), &poisoned_ast); } EXPECT_IDENT_FOR_OR("error parameter", &poisoned_ast); - Decl *decl = decl_new_var(current_context->module, tok, type, VARDECL_PARAM, VISIBLE_LOCAL); + Decl *decl = decl_new_var(tok, type, VARDECL_PARAM, VISIBLE_LOCAL); catch_stmt->catch_stmt.error_param = decl; CONSUME_OR(TOKEN_RPAREN, &poisoned_ast); @@ -730,7 +749,7 @@ static inline Ast* parse_asm_stmt(void) */ static inline Ast* parse_do_stmt(void) { - Ast *do_ast = NEW_AST(AST_DO_STMT, tok); + Ast *do_ast = AST_NEW(AST_DO_STMT, tok); advance_and_verify(TOKEN_DO); @@ -755,7 +774,7 @@ static inline Ast* parse_do_stmt(void) */ static inline Ast* parse_switch_stmt(void) { - Ast *switch_ast = NEW_AST(AST_SWITCH_STMT, tok); + Ast *switch_ast = AST_NEW(AST_SWITCH_STMT, tok); advance_and_verify(TOKEN_SWITCH); CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); switch_ast->switch_stmt.cond = TRY_AST(parse_control_expression()); @@ -779,7 +798,7 @@ static inline Ast* parse_switch_stmt(void) */ static inline Ast* parse_for_stmt(void) { - Ast *ast = NEW_AST(AST_FOR_STMT, tok); + Ast *ast = AST_NEW(AST_FOR_STMT, tok); advance_and_verify(TOKEN_FOR); CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); @@ -812,7 +831,7 @@ static inline Expr* parse_constant_expr(void) */ static inline Ast* parse_case_stmt(void) { - Ast *ast = NEW_AST(AST_CASE_STMT, tok); + Ast *ast = AST_NEW(AST_CASE_STMT, tok); advance(); Expr *expr = TRY_EXPR_OR(parse_constant_expr(), &poisoned_ast); ast->case_stmt.expr = expr; @@ -823,7 +842,7 @@ static inline Ast* parse_case_stmt(void) static inline Ast* parse_goto_stmt(void) { advance_and_verify(TOKEN_GOTO); - Ast *ast = NEW_AST(AST_GOTO_STMT, tok); + Ast *ast = AST_NEW(AST_GOTO_STMT, tok); if (!consume_const_name("label")) return &poisoned_ast; CONSUME_OR(TOKEN_EOS, &poisoned_ast); return ast; @@ -831,7 +850,7 @@ static inline Ast* parse_goto_stmt(void) static inline Ast* parse_continue_stmt(void) { - Ast *ast = NEW_AST(AST_CONTINUE_STMT, tok); + Ast *ast = AST_NEW(AST_CONTINUE_STMT, tok); advance_and_verify(TOKEN_CONTINUE); CONSUME_OR(TOKEN_EOS, &poisoned_ast); return ast; @@ -839,7 +858,7 @@ static inline Ast* parse_continue_stmt(void) static inline Ast* parse_next_stmt(void) { - Ast *ast = NEW_AST(AST_NEXT_STMT, tok); + Ast *ast = AST_NEW(AST_NEXT_STMT, tok); advance_and_verify(TOKEN_NEXT); CONSUME_OR(TOKEN_EOS, &poisoned_ast); return ast; @@ -847,7 +866,7 @@ static inline Ast* parse_next_stmt(void) static inline Ast* parse_break_stmt(void) { - Ast *ast = NEW_AST(AST_BREAK_STMT, tok); + Ast *ast = AST_NEW(AST_BREAK_STMT, tok); advance_and_verify(TOKEN_BREAK); CONSUME_OR(TOKEN_EOS, &poisoned_ast); return ast; @@ -862,7 +881,7 @@ static inline Ast* parse_ct_switch_stmt(void) static inline Ast* parse_ct_else_stmt(void) { LOG_FUNC - Ast *ast = NEW_AST(AST_CT_ELSE_STMT, tok); + Ast *ast = AST_NEW(AST_CT_ELSE_STMT, tok); advance_and_verify(TOKEN_CT_ELSE); ast->ct_elif_stmt.then = TRY_AST(parse_compound_stmt()); return ast; @@ -876,7 +895,7 @@ static inline Ast* parse_ct_else_stmt(void) static inline Ast *parse_ct_elif_stmt(void) { LOG_FUNC - Ast *ast = NEW_AST(AST_CT_ELIF_STMT, tok); + Ast *ast = AST_NEW(AST_CT_ELIF_STMT, tok); advance_and_verify(TOKEN_CT_ELIF); ast->ct_elif_stmt.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_ast); @@ -906,7 +925,7 @@ static inline Ast *parse_ct_elif_stmt(void) static inline Ast* parse_ct_if_stmt(void) { LOG_FUNC - Ast *ast = NEW_AST(AST_CT_IF_STMT, tok); + Ast *ast = AST_NEW(AST_CT_IF_STMT, tok); advance_and_verify(TOKEN_CT_IF); ast->ct_if_stmt.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_ast); ast->ct_if_stmt.then = TRY_AST(parse_compound_stmt()); @@ -943,7 +962,7 @@ static Ast *parse_return_stmt(void) LOG_FUNC advance_and_verify(TOKEN_RETURN); - Ast *ast = NEW_AST(AST_RETURN_STMT, tok); + Ast *ast = AST_NEW(AST_RETURN_STMT, tok); ast->exit = EXIT_RETURN; ast->return_stmt.defer = 0; if (try_consume(TOKEN_EOS)) @@ -958,7 +977,7 @@ static Ast *parse_return_stmt(void) static Ast *parse_throw_stmt(void) { - Ast *ast = NEW_AST(AST_THROW_STMT, tok); + Ast *ast = AST_NEW(AST_THROW_STMT, tok); advance_and_verify(TOKEN_THROW); ast->throw_stmt = TRY_EXPR_OR(parse_expr(), &poisoned_ast); CONSUME_OR(TOKEN_EOS, &poisoned_ast); @@ -967,14 +986,14 @@ static Ast *parse_throw_stmt(void) static Ast *parse_volatile_stmt(void) { - Ast *ast = NEW_AST(AST_VOLATILE_STMT, tok); + Ast *ast = AST_NEW(AST_VOLATILE_STMT, tok); ast->volatile_stmt = TRY_AST_OR(parse_compound_stmt(), &poisoned_ast); return ast; } static Ast *parse_default_stmt(void) { - Ast *ast = NEW_AST(AST_DEFAULT_STMT, tok); + Ast *ast = AST_NEW(AST_DEFAULT_STMT, tok); advance_and_verify(TOKEN_DEFAULT); TRY_CONSUME_OR(TOKEN_COLON, "Expected ':' after 'default'.", &poisoned_ast); return ast; @@ -1000,7 +1019,7 @@ bool is_valid_try_statement(TokenType type) static inline Ast *parse_label_stmt(void) { LOG_FUNC - Ast *ast = NEW_AST(AST_LABEL, tok); + Ast *ast = AST_NEW(AST_LABEL, tok); advance_and_verify(TOKEN_CONST_IDENT); advance_and_verify(TOKEN_COLON); return ast; @@ -1030,6 +1049,14 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr) case TOKEN_USHORT: case TOKEN_USIZE: case TOKEN_QUAD: + case TOKEN_C_SHORT: + case TOKEN_C_INT: + case TOKEN_C_LONG: + case TOKEN_C_LONGLONG: + case TOKEN_C_USHORT: + case TOKEN_C_UINT: + case TOKEN_C_ULONG: + case TOKEN_C_ULONGLONG: case TOKEN_TYPE_IDENT: if (next_tok.type == TOKEN_DOT || next_tok.type == TOKEN_LPAREN) break; *typePtr = parse_type_expression(); @@ -1061,7 +1088,7 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr) CONSUME_OR(TOKEN_RPAREN, false); if (inner_expr) { - *typePtr = type_new(TYPE_UNRESOLVED_EXPR); + *typePtr = type_new(TYPE_EXPRESSION); (**typePtr).unresolved_type_expr = inner_expr; return true; } @@ -1096,7 +1123,7 @@ static inline Ast *parse_decl_or_expr_stmt(void) else { Decl *decl = TRY_DECL_OR(parse_decl_after_type(false, type), &poisoned_ast); - Ast *ast = NEW_AST(AST_DECLARE_STMT, decl->name); + Ast *ast = AST_NEW(AST_DECLARE_STMT, decl->name); ast->declare_stmt = decl; CONSUME_OR(TOKEN_EOS, &poisoned_ast); return ast; @@ -1129,6 +1156,14 @@ static Ast *parse_stmt(void) case TOKEN_ULONG: case TOKEN_USHORT: case TOKEN_USIZE: + case TOKEN_C_SHORT: + case TOKEN_C_INT: + case TOKEN_C_LONG: + case TOKEN_C_LONGLONG: + case TOKEN_C_USHORT: + case TOKEN_C_UINT: + case TOKEN_C_ULONG: + case TOKEN_C_ULONGLONG: case TOKEN_TYPE_IDENT: if (next_tok.type == TOKEN_DOT || next_tok.type == TOKEN_LBRACE) { @@ -1176,7 +1211,7 @@ static Ast *parse_stmt(void) Token try_token = tok; advance(); Ast *stmt = TRY_AST(parse_stmt()); - Ast *try_ast = NEW_AST(AST_TRY_STMT, try_token); + Ast *try_ast = AST_NEW(AST_TRY_STMT, try_token); try_ast->try_stmt = stmt; return try_ast; } @@ -1313,7 +1348,7 @@ static Ast *parse_stmt(void) return &poisoned_ast; case TOKEN_EOS: advance(); - return NEW_AST(AST_NOP_STMT, tok); + return AST_NEW(AST_NOP_STMT, tok); case TOKEN_EOF: sema_error_at(tok.span.loc - 1, "Reached the end of the file when expecting a statement."); return &poisoned_ast; @@ -1646,7 +1681,7 @@ static inline Decl *parse_const_declaration(Visibility visibility) advance_and_verify(TOKEN_CONST); - Decl *decl = decl_new_var(current_context->module, tok, NULL, VARDECL_CONST, visibility); + Decl *decl = decl_new_var(tok, NULL, VARDECL_CONST, visibility); // Parse the compile time constant. if (tok.type == TOKEN_CT_IDENT) { @@ -1685,7 +1720,7 @@ static inline Decl *parse_global_declaration(Visibility visibility) Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); - Decl *decl = decl_new_var(current_context->module, tok, type, VARDECL_GLOBAL, visibility); + Decl *decl = decl_new_var(tok, type, VARDECL_GLOBAL, visibility); if (!consume_ident("global variable")) return &poisoned_decl; @@ -1787,19 +1822,18 @@ bool parse_struct_body(Decl *parent, Decl *visible_parent) if (token_type == TOKEN_STRUCT || token_type == TOKEN_UNION) { DeclKind decl_kind = decl_from_token(token_type); - TypeKind type_kind = DECL_STRUCT == decl_kind ? TYPE_STRUCT : TYPE_UNION; Decl *member; if (next_tok.type != TOKEN_IDENT) { Token name_replacement = tok; name_replacement.string = NULL; - member = decl_new_self_type(parent->module, name_replacement, decl_kind, type_kind, parent->visibility); + member = decl_new_user_defined_type(name_replacement, decl_kind, parent->visibility); advance(); } else { advance(); - member = decl_new_self_type(parent->module, tok, decl_kind, type_kind, parent->visibility); + member = decl_new_user_defined_type(tok, decl_kind, parent->visibility); Decl *other = struct_find_name(visible_parent, tok.string); if (other) { @@ -1825,7 +1859,7 @@ bool parse_struct_body(Decl *parent, Decl *visible_parent) while (1) { EXPECT_OR(TOKEN_IDENT, false); - Decl *member = decl_new_var(parent->module, tok, type, VARDECL_MEMBER, parent->visibility); + Decl *member = decl_new_var(tok, type, VARDECL_MEMBER, parent->visibility); Decl *other = struct_find_name(visible_parent, member->name.string); if (other) { @@ -1865,10 +1899,8 @@ static inline Decl *parse_struct_declaration(Visibility visibility) Token name = tok; if (!consume_type_name(type_name)) return &poisoned_decl; - Decl *decl = decl_new_self_type(current_context->module, name, - decl_from_token(type), - type == TOKEN_STRUCT ? TYPE_STRUCT : TYPE_UNION, - visibility); + Decl *decl = decl_new_user_defined_type(name, decl_from_token(type), visibility); + decl->strukt.method_functions = NULL; if (!parse_attributes(decl)) @@ -1889,7 +1921,7 @@ static inline Decl *parse_struct_declaration(Visibility visibility) */ static inline Ast *parse_generics_statements(void) { - Ast *ast = NEW_AST(AST_COMPOUND_STMT, tok); + Ast *ast = AST_NEW(AST_COMPOUND_STMT, tok); while (tok.type != TOKEN_RBRACE && tok.type != TOKEN_CASE && tok.type != TOKEN_DEFAULT) { Ast *stmt = TRY_AST_OR(parse_stmt(), &poisoned_ast); @@ -1918,7 +1950,7 @@ static inline Decl *parse_generics_declaration(Visibility visibility) { rtype = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); } - Decl *decl = decl_new_self_type(current_context->module, tok, DECL_GENERIC, TYPE_GENERIC, visibility); + Decl *decl = decl_new_user_defined_type(tok, DECL_GENERIC, visibility); if (!consume_ident("generic function name")) return &poisoned_decl; decl->generic_decl.rtype = rtype; Token *parameters = NULL; @@ -1940,7 +1972,7 @@ static inline Decl *parse_generics_declaration(Visibility visibility) { if (tok.type == TOKEN_CASE) { - Ast *generic_case = NEW_AST(AST_GENERIC_CASE_STMT, tok); + Ast *generic_case = AST_NEW(AST_GENERIC_CASE_STMT, tok); advance_and_verify(TOKEN_CASE); Type **types = NULL; while (!try_consume(TOKEN_COLON)) @@ -1960,7 +1992,7 @@ static inline Decl *parse_generics_declaration(Visibility visibility) } if (tok.type == TOKEN_DEFAULT) { - Ast *generic_case = NEW_AST(AST_GENERIC_DEFAULT_STMT, tok); + Ast *generic_case = AST_NEW(AST_GENERIC_DEFAULT_STMT, tok); advance_and_verify(TOKEN_DEFAULT); CONSUME_OR(TOKEN_COLON, &poisoned_decl); generic_case->generic_default_stmt = TRY_AST_OR(parse_generics_statements(), &poisoned_decl); @@ -1988,7 +2020,7 @@ static inline bool parse_param_decl(Decl *parent, Decl*** parameters, bool type_ LOG_FUNC Type *type = TRY_TYPE_OR(parse_type_expression(), false); - Decl *param = decl_new_var(parent->module, tok, type, VARDECL_PARAM, parent->visibility); + Decl *param = decl_new_var(tok, type, VARDECL_PARAM, parent->visibility); if (!try_consume(TOKEN_IDENT)) { @@ -2141,7 +2173,7 @@ static inline bool parse_func_typedef(Decl *decl, Visibility visibility) static inline Decl *parse_typedef_declaration(Visibility visibility) { LOG_FUNC - Decl *decl = decl_new_in_module(current_context->module, DECL_TYPEDEF, tok, visibility); + Decl *decl = decl_new(DECL_TYPEDEF, tok, visibility); advance_and_verify(TOKEN_TYPEDEF); if (tok.type == TOKEN_FUNC) { @@ -2171,7 +2203,7 @@ static inline Decl *parse_macro_declaration(Visibility visibility) rtype = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); } - Decl *decl = decl_new_in_module(current_context->module, DECL_MACRO, tok, visibility); + Decl *decl = decl_new(DECL_MACRO, tok, visibility); decl->macro_decl.rtype = rtype; TRY_CONSUME_OR(TOKEN_AT_IDENT, "Expected a macro name starting with '@'", &poisoned_decl); @@ -2197,7 +2229,7 @@ static inline Decl *parse_macro_declaration(Visibility visibility) parm_type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); goto TEST_TYPE; } - Decl *param = decl_new_var(current_context->module, tok, parm_type, VARDECL_PARAM, visibility); + Decl *param = decl_new_var(tok, parm_type, VARDECL_PARAM, visibility); advance(); params = VECADD(params, param); COMMA_RPAREN_OR(&poisoned_decl); @@ -2238,7 +2270,7 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa Type *return_type = TRY_TYPE_OR(parse_type_expression(), false); - Decl *func = decl_new_self_type(current_context->module, tok, DECL_FUNC, TYPE_FUNC, visibility); + Decl *func = decl_new_user_defined_type(tok, DECL_FUNC, visibility); func->func.function_signature.rtype = return_type; if (try_consume(TOKEN_IDENT)) @@ -2247,9 +2279,9 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa if (try_consume(TOKEN_SCOPE)) { TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "A type was expected after '::'.", false); - Type *type = type_new(TYPE_UNRESOLVED); + Type *type = type_new(TYPE_USER_DEFINED); type->unresolved.module = func->name; - type->unresolved.name = tok; + type->name_loc = tok; func->func.struct_parent = type; advance_and_verify(TOKEN_TYPE_IDENT); @@ -2263,10 +2295,7 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa else { TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "Expected a function name.", false); - Type *type = type_new(TYPE_UNRESOLVED); - type->unresolved.module = func->name; - type->unresolved.name = tok; - func->func.struct_parent = type; + func->func.struct_parent = TYPE_MODULE_UNRESOLVED(func->name, tok);; advance(); EXPECT_OR(TOKEN_DOT, false); EXPECT_IDENT_FOR_OR("function name", false); @@ -2308,7 +2337,7 @@ static inline Decl *parse_error_declaration(Visibility visibility) advance_and_verify(TOKEN_ERROR_TYPE); - Decl *error_decl = decl_new_self_type(current_context->module, tok, DECL_ERROR, TYPE_ERROR, visibility); + Decl *error_decl = decl_new_user_defined_type(tok, DECL_ERROR, visibility); if (!consume_type_name("error type")) return &poisoned_decl; @@ -2316,7 +2345,9 @@ static inline Decl *parse_error_declaration(Visibility visibility) while (tok.type == TOKEN_CONST_IDENT) { - Decl *err_constant = decl_new_enum_const(error_decl, tok, DECL_ERROR_CONSTANT); + Decl *err_constant = decl_new(DECL_ERROR_CONSTANT, tok, error_decl->visibility); + + err_constant->error_constant.parent = error_decl; VECEACH(error_decl->error.error_constants, i) { Decl *other_constant = error_decl->error.error_constants[i]; @@ -2357,7 +2388,7 @@ static inline Decl *parse_enum_declaration(Visibility visibility) advance_and_verify(TOKEN_ENUM); - Decl *decl = decl_new_self_type(current_context->module, tok, DECL_ENUM, TYPE_ENUM, visibility); + Decl *decl = decl_new_user_defined_type(tok, DECL_ENUM, visibility); if (!consume_type_name("enum")) return &poisoned_decl; @@ -2367,14 +2398,13 @@ static inline Decl *parse_enum_declaration(Visibility visibility) type = TRY_TYPE_OR(parse_base_type(), &poisoned_decl); } - decl->enums.type = type; - CONSUME_OR(TOKEN_LBRACE, false); decl->enums.type = type ? type : &type_int; while (!try_consume(TOKEN_RBRACE)) { - Decl *enum_const = decl_new_enum_const(decl, tok, DECL_ENUM_CONSTANT); + Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, tok, decl->visibility); + enum_const->enum_constant.parent = decl; VECEACH(decl->enums.values, i) { Decl *other_constant = decl->enums.values[i]; @@ -2392,7 +2422,7 @@ static inline Decl *parse_enum_declaration(Visibility visibility) } if (try_consume(TOKEN_EQ)) { - decl->enum_constant.expr = TRY_EXPR_OR(parse_expr(), &poisoned_decl); + enum_const->enum_constant.expr = TRY_EXPR_OR(parse_expr(), &poisoned_decl); } decl->enums.values = VECADD(decl->enums.values, enum_const); // Allow trailing ',' @@ -2443,7 +2473,7 @@ static inline bool parse_conditional_top_level(Decl ***decls) static inline Decl *parse_ct_if_top_level(void) { LOG_FUNC - Decl *ct = decl_new_in_module(NULL, DECL_CT_IF, tok, VISIBLE_LOCAL); + Decl *ct = decl_new(DECL_CT_IF, tok, VISIBLE_LOCAL); advance_and_verify(TOKEN_CT_IF); ct->ct_if_decl.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_decl); @@ -2453,7 +2483,7 @@ static inline Decl *parse_ct_if_top_level(void) while (tok.type == TOKEN_CT_ELIF) { advance_and_verify(TOKEN_CT_ELIF); - Decl *ct_elif = decl_new_in_module(NULL, DECL_CT_ELIF, tok, VISIBLE_LOCAL); + Decl *ct_elif = decl_new(DECL_CT_ELIF, tok, VISIBLE_LOCAL); ct_elif->ct_elif_decl.expr = TRY_EXPR_OR(parse_paren_expr(), &poisoned_decl); if (!parse_conditional_top_level(&ct_elif->ct_elif_decl.then)) return &poisoned_decl; ct_if_decl->elif = ct_elif; @@ -2462,7 +2492,7 @@ static inline Decl *parse_ct_if_top_level(void) if (tok.type == TOKEN_CT_ELSE) { advance_and_verify(TOKEN_CT_ELSE); - Decl *ct_else = decl_new_in_module(NULL, DECL_CT_ELSE, tok, VISIBLE_LOCAL); + Decl *ct_else = decl_new(DECL_CT_ELSE, tok, VISIBLE_LOCAL); ct_if_decl->elif = ct_else; if (!parse_conditional_top_level(&ct_else->ct_else_decl)) return &poisoned_decl; } @@ -2728,6 +2758,8 @@ static Expr *parse_string_literal(Expr *left) { assert(!left && "Had left hand side"); 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); @@ -2747,18 +2779,101 @@ static Expr *parse_string_literal(Expr *left) advance(); } str[len] = '\0'; - expr_string->const_expr = value_new_string(str, (uint32_t)len); + expr_string->const_expr.string.chars = str; + expr_string->const_expr.string.len = len; expr_string->type = &type_string; + expr_string->const_expr.type = CONST_STRING; return expr_string; } + + static Expr *parse_integer(Expr *left) { assert(!left && "Had left hand side"); Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST, tok); - expr_int->const_expr = parse_int(tok.start, tok.span.length); + const char *string = tok.start; + const char *end = string + tok.span.length; + uint64_t i = 0; + switch (tok.span.length > 2 ? string[1] : '0') + { + case 'x': + string += 2; + while (string < end) + { + char c = *(string++); + if (c == '_') continue; + if (i > (UINT64_MAX >> 4u)) + { + SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number."); + return &poisoned_expr; + } + i <<= 4u; + if (c < 'A') + { + i += c - '0'; + } + else if (c < 'a') + { + i += c - 'A' + 10; + } + else + { + i += c - 'a' + 10; + } + } + break; + case 'o': + string += 2; + while (string < end) + { + char c = *(string++); + if (c == '_') continue; + if (i > (UINT64_MAX >> 3u)) + { + SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number."); + return &poisoned_expr; + } + i <<= (unsigned) 3; + i += c - '0'; + } + break; + case 'b': + string += 2; + while (string < end) + { + char c = *(string++); + if (c == '_') continue; + if (i > (UINT64_MAX >> 1u)) + { + SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number."); + return &poisoned_expr; + } + i <<= (unsigned) 1; + i += c - '0'; + } + break; + default: + while (string < end) + { + char c = *(string++); + if (c == '_') continue; + if (i > (UINT64_MAX / 10)) + { + SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number."); + return &poisoned_expr; + } + i *= 10; + i += c - '0'; + } + break; + + } + expr_int->const_expr.i = i; + expr_int->const_expr.type = CONST_INT; + expr_int->type = i > INT64_MAX ? &type_compuint : &type_compint; + expr_int->resolve_status = RESOLVE_DONE; advance(); - if (expr_int->const_expr.type == VALUE_TYPE_ERROR) return &poisoned_expr; return expr_int; } @@ -2776,7 +2891,10 @@ static Expr *parse_double(Expr *left) return &poisoned_expr; } advance(); - number->const_expr = value_new_float(fval); + number->const_expr.f = fval; + number->type = &type_compfloat; + number->const_expr.type = CONST_FLOAT; + number->resolve_status = RESOLVE_DONE; return number; } @@ -2784,7 +2902,9 @@ static Expr *parse_bool(Expr *left) { assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok); - number->const_expr = (Value) { .b = tok.type == TOKEN_TRUE, .type = VALUE_TYPE_BOOL }; + number->const_expr = (ExprConst) { .b = tok.type == TOKEN_TRUE, .type = CONST_BOOL }; + number->type = &type_bool; + number->resolve_status = RESOLVE_DONE; advance(); return number; } @@ -2793,7 +2913,9 @@ static Expr *parse_nil(Expr *left) { assert(!left && "Had left hand side"); Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, tok); - number->const_expr = (Value) { .type = VALUE_TYPE_NIL }; + number->const_expr.type = CONST_NIL; + number->type = type_get_canonical_ptr(&type_void); + number->resolve_status = RESOLVE_DONE; advance(); return number; } @@ -2876,9 +2998,7 @@ static Expr *parse_identifier(Expr *left) advance_and_verify(TOKEN_SCOPE); if (try_consume(TOKEN_TYPE_IDENT)) { - Type *type = type_new(TYPE_UNRESOLVED); - type->unresolved.module = mod; - type->unresolved.name = tok; + Type *type = TYPE_MODULE_UNRESOLVED(mod, tok); if (tok.type == TOKEN_LBRACE) { Expr *expr = EXPR_NEW_TOKEN(EXPR_STRUCT_VALUE, mod); @@ -2924,8 +3044,7 @@ static Expr *parse_identifier(Expr *left) static Expr *parse_type_identifier(Expr *left) { assert(!left && "Unexpected left hand side"); - Type *type = type_new(TYPE_UNRESOLVED); - type->unresolved.name = tok; + Type *type = TYPE_UNRESOLVED(tok); advance_and_verify(TOKEN_TYPE_IDENT); if (tok.type == TOKEN_LBRACE) { @@ -2949,6 +3068,19 @@ static Expr *parse_type_expr(Expr *left) return expr; } +static Expr *parse_cast_expr(Expr *left) +{ + assert(!left && "Unexpected left hand side"); + Expr *expr = EXPR_NEW_TOKEN(EXPR_CAST, tok); + advance_and_verify(TOKEN_CAST); + CONSUME_OR(TOKEN_LPAREN, &poisoned_expr); + expr->type = TRY_TYPE_OR(parse_type_expression(), &poisoned_expr); + CONSUME_OR(TOKEN_COMMA, &poisoned_expr); + expr->expr_cast.expr = TRY_EXPR_OR(parse_expr(), &poisoned_expr); + CONSUME_OR(TOKEN_RPAREN, &poisoned_expr); + return expr; +} + ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_QUESTION] = { NULL, parse_conditional_expr, PREC_CONDITIONAL }, [TOKEN_ELVIS] = { NULL, parse_conditional_expr, PREC_CONDITIONAL }, @@ -2956,6 +3088,7 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_MINUSMINUS] = { parse_unary_expr, parse_post_unary, PREC_CALL }, [TOKEN_LPAREN] = { parse_grouping_expr, parse_call_expr, PREC_CALL }, [TOKEN_TYPE] = { parse_type_expr, NULL, PREC_NONE }, + [TOKEN_CAST] = { parse_cast_expr, NULL, PREC_NONE }, //[TOKEN_SIZEOF] = { parse_sizeof, NULL, PREC_NONE }, [TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL }, [TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE }, diff --git a/src/compiler/parser.h b/src/compiler/parser.h deleted file mode 100644 index c40f6f145..000000000 --- a/src/compiler/parser.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "compiler_common.h" -#include "tokens.h" - -typedef enum _Precedence -{ - PREC_NONE, - PREC_ASSIGNMENT, // =, *=, /=, %=, ... - PREC_CONDITIONAL, // ?: - PREC_LOGICAL, // && || - PREC_RELATIONAL, // < > <= >= == != - PREC_ADDITIVE, // + - - PREC_BIT, // ^ | & - PREC_SHIFT, // << >> >>> - PREC_MULTIPLICATIVE, // * / % - PREC_UNARY, // ! - + ~ * & prefix ++/-- - PREC_CALL, // . () [] postfix ++/-- -} Precedence; - -void parse_file(File *file); \ No newline at end of file diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index f99e1f4f5..2a668eb5c 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "../utils/errors.h" -#include "../utils/lib.h" -#include "semantic_analyser.h" -#include "../utils/file_utils.h" -#include "symtab.h" -#include "ast.h" -#include "diagnostics.h" -#include "context.h" +#include "compiler_internal.h" + +static bool sema_resolve_type(Context *context, Type *type); +static bool sema_analyse_expression(Context *context, Expr *expr); + + void sema_init(File *file) @@ -17,90 +15,399 @@ void sema_init(File *file) LOG_FUNC } +/** + * Symmetrically promotes one expression by inserting an implicit cast. + * + * @param expr1 + * @param expr2 + * @return false if an implicit cast is not allowed. + */ +static bool type_promote(Expr *expr1, Expr *expr2) +{ + if (expr1->type->canonical == expr2->type->canonical) return true; + TODO +} + +/** + * Check if a type is contained in another type. + * + * @param type + * @param possible_subtype + * @return true if it is a subtype + */ +static bool canonical_type_is_subtype(Type *type, Type *possible_subtype) +{ + assert(type == type->canonical && possible_subtype == possible_subtype->canonical); + if (type == possible_subtype) return true; + if (type->type_kind != possible_subtype->type_kind) return false; + if (type->type_kind != TYPE_USER_DEFINED || type->decl->decl_kind != DECL_STRUCT) return false; + + if (!possible_subtype->decl->strukt.members) return false; + + Decl *first_element = possible_subtype->decl->strukt.members[0]; + + if (first_element->decl_kind != DECL_VAR) return false; + + return canonical_type_is_subtype(type, first_element->var.type->canonical); +} + +static bool cast_const_type_expression(Expr *expr, Type *type) +{ + Type *canonical = type->canonical; + ExprConst *expr_const = &expr->const_expr; + switch (canonical->type_kind) + { + case TYPE_POISONED: + case TYPE_USER_DEFINED: + case TYPE_EXPRESSION: + case TYPE_INC_ARRAY: + UNREACHABLE; + break; + case TYPE_ARRAY: + TODO + UNREACHABLE + case TYPE_VARARRAY: + TODO + UNREACHABLE; + case TYPE_POINTER: + + TODO + UNREACHABLE; + case TYPE_VOID: + case TYPE_BOOL: + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_IXX: + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_UXX: + case TYPE_F32: + case TYPE_F64: + case TYPE_FXX: + { + TODO + // BuiltinConv conv = BUILTIN_CONVERSION[expr->type->type_kind - TYPE_VOID][canonical->type_kind - TYPE_VOID]; + // builtin_convert(&expr->const_expr, conv, canonical); + expr->type = type; + return true; + } + case TYPE_STRING: + break; + } + + TODO +} + +static bool expr_insert_cast(Expr *expr, Type *canonical) +{ + assert(canonical == canonical->canonical); + if (expr->expr_kind == EXPR_CONST) return cast_const_type_expression(expr, canonical); + TODO +} + + +typedef enum _AssignCast +{ + ASSIGN_CAST_FAILED, + ASSIGN_CAST_FAILED_ERROR_SHOWN, + ASSIGN_CAST_SKIP, + ASSIGN_CAST, +} AssignCast; + +/** + * Pick the cast to do. + * + * @param expr1 + * @param expr2 + * @return AssignCast + */ +static inline bool type_assign_cast_type(Expr *expr, Type *target_type, bool is_update) +{ + return cast(expr, target_type, CAST_TYPE_IMPLICIT_ASSIGN); + /* + Type *right_type = target_type->canonical; + Type *left_type = expr->type->canonical; + if (right_type == left_type) return true; + + // X = Y where Y is subtype, this is truncation. + if (canonical_type_is_subtype(left_type, right_type)) + { + insert_cast(expr, CAST_TRUNC, target_type); + return true; + } + + // X* = void* + if (right_type == &type_voidptr) + { + if (left_type->type_kind == TYPE_POINTER) + { + insert_cast(expr, CAST_PTRPTR, target_type); + return true; + } + return false; + } + + // void* = X*, void* = X[], void* = X[n], void* = string + if (left_type == &type_voidptr) + { + switch (left_type->type_kind) + { + case TYPE_POINTER: + insert_cast(expr, CAST_PTRPTR, target_type); + return true; + case TYPE_VARARRAY: + insert_cast(expr, CAST_VARRPTR, target_type); + return true; + case TYPE_ARRAY: + insert_cast(expr, CAST_ARRPTR, target_type); + return true; + case TYPE_STRING: + insert_cast(expr, CAST_STRPTR, target_type); + default: + return false; + } + } + + // X* = X[n], X* = X[], X* = Y[], X* = Y[n], X* = Y* if subtype + if (left_type->type_kind == TYPE_POINTER) + { + switch (right_type->type_kind) + { + case TYPE_ARRAY: + insert_cast(expr, CAST_ARRPTR, target_type); + return true; + case TYPE_VARARRAY: + insert_cast(expr, CAST_VARRPTR, target_type); + return true; + case TYPE_POINTER: + if (canonical_type_is_subtype(left_type->base, right_type->base)) return false; + insert_cast(expr, CAST_PTRPTR, target_type); + return true; + case TYPE_STRING: + if (left_type->type_kind == TYPE_I8 || left_type->type_kind == TYPE_U8) + { + insert_cast(expr, CAST_STRPTR, target_type); + return true; + } + return false; + default: + return false; + } + } + + if (!type_is_builtin(left_type->type_kind) || !type_is_builtin(right_type->type_kind)) return false; + + return cast(expr, right_type, target_type, CAST_TYPE_IMPLICIT_ASSIGN);*/ +} + +/** + * Tries to implicitly cast the expression to the recipient type (return, assignment) + * + * @param expr1 + * @param expr2 + * @return false if an implicit cast is not allowed. + */ +static bool type_assign_cast(Expr *expr, Type *type, bool is_update) +{ + assert(type->canonical == type); + if (!type_assign_cast_type(expr, type, is_update)) + { + expr_poison(expr); + return false; + } + return true; +} + +static bool insert_assign_cast_if_needed(Expr *expr, Type *type) +{ + assert(type->canonical == type); + if (expr->type->canonical == type) return true; + if (!type_assign_cast_type(expr, type, false)) + { + expr_poison(expr); + return false; + } + return true; +} + +static bool insert_arith_cast_if_needed(Expr *left, Expr *right, Type *left_type) +{ + Type *right_type = right->type->canonical; + assert(left_type->canonical == left_type); + if (right_type == left_type) return true; + TODO +} + +static bool insert_bool_cast_if_needed(Expr *expr) +{ + Type *canonical = expr->type->canonical; + if (canonical == &type_bool) return true; + TODO +} + +static void show_shadow_error(Decl *decl, Decl *old) +{ + sema_error_range(decl->name.span, "The '%s' would shadow a previous declaration.", decl->name.string); + sema_prev_at_range(old->name.span, "The previous use of '%s' was here.", decl->name.string); +} + static inline Decl *module_find_symbol(Module *module, const char *symbol) { return stable_get(&module->symbols, symbol); } - -static inline bool sema_resolve_unresolved_array(Type *type) +static Decl *context_find_ident(Context *context, const char *symbol) { - TODO + Decl **first = &context->locals[0]; + Decl **current = context->last_local - 1; + while (current >= first) + { + if (current[0]->name.string == symbol) return current[0]; + current--; + } + Decl *found = module_find_symbol(context->module, symbol); + if (found) return found; + // TODO check imports + return NULL; } -static inline bool sema_resolve_unresolved_type_expr(Type *type) + +static inline void context_push_scope(Context *context) { - TODO + if (context->current_scope == &context->scopes[MAX_SCOPE_DEPTH - 1]) + { + FATAL_ERROR("Too deeply nested scopes."); + } + context->current_scope++; + context->current_scope->local_decl_start = context->last_local; } -static inline bool sema_resolve_unresolved_type(Context *context, Type *type) +static inline void context_pop_scope(Context *context) { - assert(type->type_kind == TYPE_UNRESOLVED); - if (type->unresolved.module.string) + assert(context->current_scope != &context->scopes[0]); + context->last_local = context->current_scope->local_decl_start; + context->current_scope--; +} + + + +static bool sema_resolve_ptr_type(Context *context, Type *type) +{ + if (!sema_resolve_type(context, type->base)) { - TODO - } - Decl *decl = stable_get(&context->local_symbols, type->unresolved.name.string); - if (!decl) - { - decl = module_find_symbol(context->module, type->unresolved.name.string); - } - if (!decl) - { - TODO - } - if (!decl) - { - SEMA_ERROR(type->unresolved.name, "Unknown type '%s'.", type->unresolved.name); - type->type_kind = TYPE_POISONED; + type_poison(type); return false; } - switch (decl->decl_kind) - { - case DECL_STRUCT: - type->type_kind = TYPE_STRUCT; - break; - case DECL_UNION: - type->type_kind = TYPE_UNION; - break; - case DECL_TYPEDEF: - type->type_kind = TYPE_TYPEDEF; - break; - case DECL_FUNC_TYPE: - type->type_kind = TYPE_FUNC_TYPE; - break; - case DECL_ENUM: - type->type_kind = TYPE_ENUM; - break; - case DECL_ERROR: - type->type_kind = TYPE_ERROR; - break; - default: - SEMA_ERROR(type->unresolved.name, "Unknown type '%s'.", type->unresolved.name); - type->type_kind = TYPE_POISONED; - return false; - } - type->decl = decl; - type->canonical_type = decl->type; - return true; + type->canonical = type_get_canonical_ptr(type); + type->resolve_status = RESOLVE_DONE; + return true; } + +static bool sema_resolve_array_type(Context *context, Type *type) +{ + if (!sema_resolve_type(context, type->base)) + { + type_poison(type); + return false; + } + type->canonical = type_get_canonical_array(type); + type->resolve_status = RESOLVE_DONE; + return true; +} + static bool sema_resolve_type(Context *context, Type *type) { LOG_FUNC + + if (type->resolve_status == RESOLVE_DONE) return type_ok(type); + + if (type->resolve_status == RESOLVE_RUNNING) + { + SEMA_ERROR(type->name_loc, "Circular dependency resolving type '%s'.", type->name_loc); + type_poison(type); + return false; + } + + type->resolve_status = RESOLVE_RUNNING; + switch (type->type_kind) { case TYPE_POISONED: - return false; - case TYPE_UNRESOLVED: - return sema_resolve_unresolved_type(context, type); - case TYPE_UNRESOLVED_EXPR: - return sema_resolve_unresolved_type_expr(type); - case TYPE_UNRESOLVED_ARRAY: - return sema_resolve_unresolved_array(type); + case TYPE_INC_ARRAY: + UNREACHABLE + case TYPE_USER_DEFINED: + break; + case TYPE_POINTER: + return sema_resolve_ptr_type(context, type); + case TYPE_ARRAY: + return sema_resolve_array_type(context, type); default: - return true; + TODO } + + Decl *decl = stable_get(&context->local_symbols, type->name_loc.string); + if (!decl) + { + decl = module_find_symbol(context->module, type->name_loc.string); + } + + if (!decl) + { + SEMA_ERROR(type->name_loc, "Unknown type '%s'.", type->name_loc.string); + type_poison(type); + return false; + } + + switch (decl->decl_kind) + { + case DECL_STRUCT: + case DECL_UNION: + case DECL_ERROR: + case DECL_ENUM: + type->decl = decl; + type->canonical = decl->self_type; + type->resolve_status = RESOLVE_DONE; + DEBUG_LOG("Resolved %s.", type->name_loc.string); + return true; + case DECL_TYPEDEF: + // TODO func + if (!sema_resolve_type(context, decl->typedef_decl.type)) + { + decl_poison(decl); + type_poison(type); + return false; + } + type->decl = decl; + type->canonical = decl->typedef_decl.type->canonical; + type->resolve_status = RESOLVE_DONE; + DEBUG_LOG("Resolved %s.", type->name_loc.string); + return true; + case DECL_POISONED: + type_poison(type); + return false; + case DECL_FUNC: + case DECL_VAR: + case DECL_ENUM_CONSTANT: + case DECL_ERROR_CONSTANT: + case DECL_ARRAY_VALUE: + case DECL_IMPORT: + case DECL_MACRO: + case DECL_GENERIC: + SEMA_ERROR(type->name_loc, "This is not a type."); + type_poison(type); + return false; + case DECL_MULTI_DECL: + case DECL_CT_ELSE: + case DECL_CT_IF: + case DECL_CT_ELIF: + UNREACHABLE + } + UNREACHABLE } static inline bool sema_analyse_struct_member(Context *context, Decl *decl) @@ -109,11 +416,12 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl) assert(decl->decl_kind == DECL_VAR); assert(decl->var.kind == VARDECL_MEMBER); assert(!decl->var.init_expr); - if (!sema_resolve_type(context, decl->type)) + if (!sema_resolve_type(context, decl->var.type)) { decl_poison(decl); return false; } + assert(decl->var.type->canonical); return true; } static inline void sema_analyse_struct(Context *context, Decl *decl) @@ -142,8 +450,474 @@ static inline void sema_analyse_struct(Context *context, Decl *decl) DEBUG_LOG("Analysing complete."); } +static bool constant_fold(Context *context, Expr *expr) +{ + if (expr->expr_kind == EXPR_CONST) return true; + switch (expr->expr_kind) + { + case EXPR_POISONED: + return false; + case EXPR_TRY: + if ((unsigned)sema_analyse_expression(context, expr->try_expr.expr) & + (unsigned)(!expr->try_expr.else_expr || sema_analyse_expression(context, expr->try_expr.else_expr))) + { + return true; + } + else + { + expr_poison(expr); + return false; + } + case EXPR_CONST: + return true; + case EXPR_BINARY: + TODO + break; + case EXPR_CONDITIONAL: + break; + case EXPR_UNARY: + break; + case EXPR_POST_UNARY: + if (!sema_analyse_expression(context, expr->post_expr.expr)) + case EXPR_TYPE: + break; + case EXPR_IDENTIFIER: + break; + case EXPR_METHOD_REF: + break; + case EXPR_CALL: + break; + case EXPR_SIZEOF: + break; + case EXPR_SUBSCRIPT: + break; + case EXPR_ACCESS: + break; + case EXPR_STRUCT_VALUE: + break; + case EXPR_STRUCT_INIT_VALUES: + break; + case EXPR_INITIALIZER_LIST: + break; + case EXPR_EXPRESSION_LIST: + break; + case EXPR_DEFERRED_TOKENS: + break; + case EXPR_CAST: + break; + } + TODO + return true; +} +/* +static inline void add_integers(ExprConst *result, uint64_t l, bool l_is_negative, uint64_t r, bool r_is_negative) +{ + if (l_is_negative == r_is_negative) + { + result->type = l_is_negative ? CONST_NEGATIVE_INT : CONST_POSITIVE_INT; + result->integer.i = l + r; + return; + } + if (l > r) + { + result->integer.i = l - r; + result->type = l_is_negative ? CONST_NEGATIVE_INT : CONST_POSITIVE_INT; + } + else + { + result->integer.i = r - l; + result->type = l_is_negative ? CONST_POSITIVE_INT : CONST_NEGATIVE_INT; + } +} +*/ +static inline bool sema_analyse_binary_expr_internal_const(Context *context, Expr *expr) +{ + return constant_fold(context, expr); +} + +static inline bool cast_to_common_for_operator(BinOp op, Expr *left, Expr *right) +{ + switch (op) + { + case BINOP_ERROR: + return false; + case BINOP_ASSIGN: + return insert_assign_cast_if_needed(right, left->type->canonical); + case BINOP_MULT: + case BINOP_ADD: + case BINOP_SUB: + case BINOP_DIV: + case BINOP_MOD: + case BINOP_BIT_OR: + case BINOP_BIT_AND: + case BINOP_BIT_XOR: + case BINOP_NE: + case BINOP_EQ: + case BINOP_GE: + case BINOP_GT: + case BINOP_LE: + case BINOP_LT: + return insert_arith_cast_if_needed(left, right, left->type->canonical); + case BINOP_MULT_ASSIGN: + return insert_arith_cast_if_needed(left, right, left->type->canonical); + case BINOP_ADD_ASSIGN: + break; + case BINOP_SUB_ASSIGN: + break; + case BINOP_DIV_ASSIGN: + break; + case BINOP_MOD_ASSIGN: + case BINOP_AND_ASSIGN: + case BINOP_OR_ASSIGN: + break; + case BINOP_AND: + case BINOP_OR: + return insert_bool_cast_if_needed(left) & insert_bool_cast_if_needed(right); + break; + case BINOP_BIT_AND_ASSIGN: + break; + case BINOP_BIT_OR_ASSIGN: + break; + case BINOP_BIT_XOR_ASSIGN: + break; + case BINOP_SHR: + case BINOP_SHL: + TODO + case BINOP_SHR_ASSIGN: + break; + case BINOP_SHL_ASSIGN: + break; + case BINOP_ELVIS: + TODO + } + TODO +} + +static inline bool sema_analyse_binary_expr_internal(Context *context, Expr *expr) +{ + assert(expr->resolve_status == RESOLVE_RUNNING); + Expr *left = expr->binary_expr.left; + Expr *right = expr->binary_expr.right; + bool success = sema_analyse_expression(context, left); + success = success && sema_analyse_expression(context, right); + if (!success) + { + expr_poison(expr); + return false; + } + if (!cast_to_common_for_operator(expr->binary_expr.operator, left, right)) + { + expr_poison(expr); + return false; + } + if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST) + { + if (!sema_analyse_binary_expr_internal_const(context, expr)) + { + expr_poison(expr); + return false; + } + return true; + } + switch (expr->binary_expr.operator) + { + case BINOP_ERROR: + break; + case BINOP_ASSIGN: + break; + case BINOP_MULT: + break; + case BINOP_MULT_ASSIGN: + break; + case BINOP_ADD: + break; + case BINOP_ADD_ASSIGN: + break; + case BINOP_SUB: + break; + case BINOP_SUB_ASSIGN: + break; + case BINOP_DIV: + break; + case BINOP_DIV_ASSIGN: + break; + case BINOP_MOD: + break; + case BINOP_MOD_ASSIGN: + break; + case BINOP_AND: + break; + case BINOP_AND_ASSIGN: + break; + case BINOP_OR: + break; + case BINOP_OR_ASSIGN: + break; + case BINOP_BIT_AND: + break; + case BINOP_BIT_AND_ASSIGN: + break; + case BINOP_BIT_OR: + break; + case BINOP_BIT_OR_ASSIGN: + break; + case BINOP_BIT_XOR: + break; + case BINOP_BIT_XOR_ASSIGN: + break; + case BINOP_NE: + break; + case BINOP_EQ: + break; + case BINOP_GE: + break; + case BINOP_GT: + break; + case BINOP_LE: + break; + case BINOP_LT: + break; + case BINOP_SHR: + break; + case BINOP_SHR_ASSIGN: + break; + case BINOP_SHL: + break; + case BINOP_SHL_ASSIGN: + break; + case BINOP_ELVIS: + break; + } + TODO +} + +static inline bool sema_analyse_unary_expr_internal(Context *context, Expr *expr) +{ + assert(expr->resolve_status == RESOLVE_RUNNING); + Expr *inner = expr->unary_expr.expr; + if (!sema_analyse_expression(context, inner)) + { + expr_poison(expr); + return false; + } + Type *canonical_inner_type = inner->type->canonical; + switch (expr->unary_expr.operator) + { + case UNARYOP_ERROR: + UNREACHABLE; + case UNARYOP_DEREF: + TODO + break; + case UNARYOP_ADDR: + TODO + break; + case UNARYOP_NEG: + if (!type_is_signed(canonical_inner_type) && canonical_inner_type != &type_compuint) + { + bool is_signed = type_is_signed(canonical_inner_type); + bool inneer = canonical_inner_type; + SEMA_ERROR(expr->loc, "Cannot negate %s.", inner->type->name_loc.string); + return false; + } + if (canonical_inner_type == &type_compuint) + { + TODO + } + if (inner->expr_kind == EXPR_CONST) + { + assert(inner->const_expr.type == CONST_INT); + expr->const_expr.type = CONST_INT; + expr->expr_kind = EXPR_CONST; + expr->const_expr.i = ~inner->const_expr.i; + expr->type = inner->type; + return true; + } + return true; + case UNARYOP_BITNEG: + TODO + /* + if (canonical_inner_type->type_kind != TYPE_BUILTIN || !builtin_may_negate(canonical_inner_type)) + { + SEMA_ERROR(expr->loc, "Cannot bit negate %s.", type_to_string(inner->type)); + return false; + }*/ + if (inner->expr_kind == EXPR_CONST) + { + switch (inner->const_expr.type) + { + case CONST_NIL: + case CONST_BOOL: + case CONST_STRING: + case CONST_FLOAT: + UNREACHABLE + case CONST_INT: + + //inner->const_expr.type = CONST_NEGATIVE_INT; + break; + //case CONST_NEGATIVE_INT: + //inner->const_expr.type = CONST_POSITIVE_INT; + break; + TODO + } + } + return true; + case UNARYOP_NOT: + if (inner->expr_kind == EXPR_CONST) + { + switch (inner->const_expr.type) + { + case CONST_NIL: + expr->const_expr.b = true; + break; + case CONST_BOOL: + expr->const_expr.b = !inner->const_expr.b; + break; + case CONST_INT: + expr->const_expr.b = inner->const_expr.i == 0; + break; + case CONST_FLOAT: + expr->const_expr.b = inner->const_expr.f == 0; + break; + case CONST_STRING: + expr->const_expr.b = !inner->const_expr.string.len; + break; + } + expr->const_expr.type = CONST_BOOL; + expr->type = &type_bool; + expr->expr_kind = EXPR_CONST; + return true; + } + switch (canonical_inner_type->type_kind) + { + case TYPE_ARRAY: + case TYPE_POINTER: + case TYPE_VARARRAY: + return true; + default: + SEMA_ERROR(expr->loc, "Cannot use 'not' on %s", inner->type->name_loc.string); + return false; + } + case UNARYOP_INC: + TODO + break; + case UNARYOP_DEC: + TODO + break; + } +} +static inline bool sema_analyse_cast(Context *context, Expr *expr) +{ + Expr *inner = expr->expr_cast.expr; + bool success = sema_analyse_expression(context, inner); + success = sema_resolve_type(context, expr->type) && success; + if (!success) return false; + Type *canonical = expr->type->canonical; + Type *inner_canonical = inner->type->canonical; + if (canonical == inner_canonical) return true; + //BUILTIN_CONVERSION + TODO +} + static inline bool sema_analyse_expression(Context *context, Expr *expr) { + switch (expr->resolve_status) + { + case RESOLVE_NOT_DONE: + expr->resolve_status = RESOLVE_RUNNING; + break; + case RESOLVE_RUNNING: + SEMA_ERROR(expr->loc, "Recursive resolution of expression"); + expr_poison(expr); + return false; + case RESOLVE_DONE: + return expr_ok(expr); + } + switch (expr->expr_kind) + { + case EXPR_POISONED: + UNREACHABLE + case EXPR_TRY: + if (!sema_analyse_expression(context, expr->try_expr.expr)) + { + expr_poison(expr); + return false; + } + if (expr->try_expr.else_expr) + { + if (!sema_analyse_expression(context, expr->try_expr.else_expr)) + { + expr_poison(expr); + return false; + } + if (!type_promote(expr->try_expr.else_expr, expr->try_expr.expr)) + { + expr_poison(expr); + return false; + } + } + expr->type = expr->try_expr.expr->type; + expr->resolve_status = RESOLVE_DONE; + return true; + case EXPR_CONST: + expr->resolve_status = RESOLVE_DONE; + return true; + case EXPR_BINARY: + if (!sema_analyse_binary_expr_internal(context, expr)) + { + expr_poison(expr); + return false; + } + expr->resolve_status = RESOLVE_DONE; + return true; + case EXPR_CONDITIONAL: + TODO + break; + case EXPR_UNARY: + if (!sema_analyse_unary_expr_internal(context, expr)) + { + expr_poison(expr); + return false; + } + expr->resolve_status = RESOLVE_DONE; + return true; + case EXPR_POST_UNARY: + break; + case EXPR_TYPE: + break; + case EXPR_IDENTIFIER: + break; + case EXPR_METHOD_REF: + break; + case EXPR_CALL: + break; + case EXPR_SIZEOF: + break; + case EXPR_SUBSCRIPT: + break; + case EXPR_ACCESS: + break; + case EXPR_STRUCT_VALUE: + break; + case EXPR_STRUCT_INIT_VALUES: + break; + case EXPR_INITIALIZER_LIST: + break; + case EXPR_EXPRESSION_LIST: + break; + case EXPR_DEFERRED_TOKENS: + break; + case EXPR_CAST: + if (!sema_analyse_cast(context, expr)) + { + expr_poison(expr); + return false; + } + return true; + } + { + + } + TODO return false; } @@ -157,6 +931,22 @@ static inline bool sema_analyse_expression(Context *context, Expr *expr) Expr *expr_implicit_conversion(Expr *expr, Type *type) { TODO + /* + assert(expr->type && expr_ok(expr)); + if (expr->type->type_kind == TYPE_NIL && type->type_kind == TYPE_POINTER) + Type *expr_type = expr->type; + if (type->type_kind == TYPE_POINTER && expr_type->type_kind == TYPE_POINTER) + { + if (expr_type) + if (type->type_kind) + } + Decl *canonical_decl = type->canonical; + if (type->canonical) + if (expr->type->canonical->decl_kind == TYPE_BUILTIN && type->canonical->decl_kind == DECL_BUILTIN) + { + + } + TODO*/ return NULL; } @@ -165,7 +955,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo if (!decl_ok(param)) return false; assert(param->decl_kind == DECL_VAR); assert(param->var.kind == VARDECL_PARAM); - if (!sema_resolve_type(context, param->type)) + if (!sema_resolve_type(context, param->var.type)) { return false; } @@ -177,8 +967,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo if (param->var.init_expr) { Expr *expr = param->var.init_expr; - sema_analyse_expression(context, expr); - if (!expr_ok(expr)) return false; + if (!sema_analyse_expression(context, expr)) return false; if (expr->expr_kind != EXPR_CONST) { SEMA_ERROR(expr->loc, "Only constant expressions may be used as default values."); @@ -242,9 +1031,9 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *parent, Ast * Type *expected_rtype = context->active_function_for_analysis->func.function_signature.rtype; if (statement->return_stmt.expr == NULL) { - if (expected_rtype->type_kind != TYPE_VOID) + if (expected_rtype->canonical != &type_void) { - SEMA_ERROR(statement->token, "Expected to return a result of type %s.", type_to_string(expected_rtype)); + SEMA_ERROR(statement->token, "Expected to return a result of type %s.", expected_rtype->name_loc.string); return false; } } @@ -258,6 +1047,54 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *parent, Ast * return true; } +static inline bool sema_analyse_var_decl(Context *context, Ast *parent, 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) + { + show_shadow_error(decl, other); + return false; + } + if (context->last_local == &context->locals[MAX_LOCALS - 1]) + { + FATAL_ERROR("Reached the maximum number of locals"); + } + if (decl->var.init_expr) + { + sema_analyse_expression(context, decl->var.init_expr); + type_assign_cast(decl->var.init_expr, decl->var.type->canonical, false); + } + context->last_local[0] = decl; + context->last_local++; + return true; +} + +static inline bool sema_analyse_multi_decl(Context *context, Ast *parent, Ast *statement) +{ + Decl *decl = statement->declare_stmt; + VECEACH(statement->declare_stmt->multi_decl, i) + { + if (!sema_analyse_var_decl(context, parent, statement->declare_stmt->multi_decl[i])) + { + decl_poison(decl); + return false; + } + } + return true; +} + +static inline bool sema_analyse_declare_stmt(Context *context, Ast *parent, Ast *statement) +{ + Decl *decl = statement->declare_stmt; + if (decl->decl_kind == DECL_MULTI_DECL) + { + return sema_analyse_multi_decl(context, parent, statement); + } + return sema_analyse_var_decl(context, parent, decl); +} + static bool sema_analyse_statement(Context *context, Ast *parent, Ast *statement) { LOG_FUNC @@ -276,6 +1113,9 @@ static bool sema_analyse_statement(Context *context, Ast *parent, Ast *statement case AST_CATCH_STMT: break; case AST_COMPOUND_STMT: + context_push_scope(context); + sema_analyse_compound_statement(context, parent, statement); + context_pop_scope(context); break; case AST_COND_STMT: break; @@ -288,7 +1128,7 @@ static bool sema_analyse_statement(Context *context, Ast *parent, Ast *statement case AST_CT_ELSE_STMT: break; case AST_DECLARE_STMT: - break; + return sema_analyse_declare_stmt(context, parent, statement); case AST_DECL_EXPR_LIST: break; case AST_DEFAULT_STMT: @@ -334,8 +1174,11 @@ static bool sema_analyse_statement(Context *context, Ast *parent, Ast *statement static inline bool sema_analyse_function_body(Context *context, Decl *func) { context->active_function_for_analysis = func; + context->current_scope = &context->scopes[0]; + context->current_scope->local_decl_start = 0; + context->last_local = &context->locals[0]; if (!sema_analyse_compound_statement(context, func->func.body, func->func.body)) return false; - if (func->func.body->exit != EXIT_RETURN && func->func.function_signature.rtype->type_kind != TYPE_VOID) + if (func->func.body->exit != EXIT_RETURN && func->func.function_signature.rtype->type_kind != TYPE_ARRAY) { SEMA_ERROR(func->name, "Missing return statement at the end of the function."); return false; @@ -373,11 +1216,6 @@ static inline void sema_analyse_decl(Context *context, Decl *decl) } } -static void show_shadow_error(Decl *decl, Decl *old) -{ - sema_error_range(decl->name.span, "The '%s' would shadow a previous declaration.", decl->name.string); - sema_prev_at_range(old->name.span, "The previous use of '%s' was here.", decl->name.string); -} bool context_register_global(Context *context, Decl *decl) { @@ -396,7 +1234,6 @@ bool context_register_global(Context *context, Decl *decl) decl_poison(decl); return false; } - context->declarations = VECADD(context->declarations, decl); return true; } diff --git a/src/compiler/semantic_analyser.h b/src/compiler/semantic_analyser.h deleted file mode 100644 index 19d57770d..000000000 --- a/src/compiler/semantic_analyser.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "compiler_common.h" -#include "ast.h" -#include "context.h" - - -void sema_init(File *file); -void sema_analysis(Context *context); - - - - diff --git a/src/compiler/source_file.c b/src/compiler/source_file.c index ac3dc48d8..145815c99 100644 --- a/src/compiler/source_file.c +++ b/src/compiler/source_file.c @@ -4,11 +4,8 @@ #include #include +#include "compiler_internal.h" #include "../build/build_options.h" -#include "source_file.h" -#include "../utils/lib.h" -#include "../utils/file_utils.h" -#include "lexer.h" static const size_t LEXER_FILES_START_CAPACITY = 128; diff --git a/src/compiler/source_file.h b/src/compiler/source_file.h deleted file mode 100644 index e023c68ea..000000000 --- a/src/compiler/source_file.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -#include "compiler_common.h" - -File *source_file_load(const char *filename, bool *already_loaded); -File *source_file_from_position(SourceLoc loc); diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 86bf1f40a..90a52bdc2 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -2,14 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "symtab.h" -#include -#include -#include "../utils/errors.h" -#include -#include "../utils/lib.h" -#include "utils/malloc.h" -#include "tokens.h" +#include "compiler_internal.h" #define TABLE_MAX_LOAD 0.75 #define MAX_HASH_SIZE (1024 * 1024) diff --git a/src/compiler/symtab.h b/src/compiler/symtab.h deleted file mode 100644 index 0824fd51c..000000000 --- a/src/compiler/symtab.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include "tokens.h" - -void symtab_init(uint32_t max_size); -const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type); - -typedef struct _VoidEntry -{ - const char *key; - void *value; -} SEntry; - -typedef struct _STable -{ - uint32_t count; - uint32_t capacity; - SEntry *entries; -} STable; - -void stable_init(STable *table, uint32_t initial_size); -void *stable_set(STable *table, const char *key, void *value); -void *stable_get(STable *table, const char *key); -void *stable_delete(STable *table, const char *key); -void stable_clear(STable *table); diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 9fe67b65c..974297c24 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "tokens.h" -#include "../utils/errors.h" +#include "compiler_internal.h" const char *token_type_to_string(TokenType type) { @@ -271,6 +270,24 @@ const char *token_type_to_string(TokenType type) case TOKEN_HALF: return "half"; + case TOKEN_C_SHORT: + return "c_short"; + case TOKEN_C_INT: + return "c_int"; + case TOKEN_C_LONG: + return "c_long"; + case TOKEN_C_LONGLONG: + return "c_longlong"; + case TOKEN_C_USHORT: + return "c_ushort"; + case TOKEN_C_UINT: + return "c_uint"; + case TOKEN_C_ULONG: + return "c_ulong"; + case TOKEN_C_ULONGLONG: + return "c_ulonglong"; + + case TOKEN_DOCS_EOL: return "EOL"; case TOKEN_DOCS_START: @@ -323,25 +340,6 @@ const char *token_type_to_string(TokenType type) bool token_is_type(TokenType type) { - switch (type) - { - case TOKEN_VOID: - case TOKEN_BYTE: - case TOKEN_BOOL: - case TOKEN_CHAR: - case TOKEN_DOUBLE: - case TOKEN_FLOAT: - case TOKEN_INT: - case TOKEN_ISIZE: - case TOKEN_LONG: - case TOKEN_SHORT: - case TOKEN_UINT: - case TOKEN_ULONG: - case TOKEN_USHORT: - case TOKEN_USIZE: - return true; - default: - return false; - } + return type >= TOKEN_VOID && type <= TOKEN_C_ULONGLONG; } diff --git a/src/compiler/tokens.h b/src/compiler/tokens.h deleted file mode 100644 index 15de9322a..000000000 --- a/src/compiler/tokens.h +++ /dev/null @@ -1,188 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -#include - -typedef enum _TokenType -{ - TOKEN_INVALID_TOKEN = 0, - - // Single-character tokens. - TOKEN_AMP, // & - TOKEN_AT, // @ - TOKEN_BIT_NOT, // ~ - TOKEN_BIT_OR, // = - TOKEN_BIT_XOR, // ^ - TOKEN_COLON, // : - TOKEN_COMMA, // , - TOKEN_EOS, // ; - TOKEN_EQ, // = - TOKEN_GREATER, // > - TOKEN_DIV, // / - TOKEN_DOLLAR, // $ - TOKEN_DOT, // . - TOKEN_HASH, // # - TOKEN_LESS, // < - TOKEN_LBRACE, // { - TOKEN_LBRACKET, // [ - TOKEN_LPAREN, // ( - TOKEN_MINUS, // - - TOKEN_MOD, // % - TOKEN_NOT, // ! - TOKEN_OR, // | - TOKEN_PLUS, // + - TOKEN_QUESTION, // ? - TOKEN_RBRACE, // } - TOKEN_RBRACKET, // ] - TOKEN_RPAREN, // ) - TOKEN_STAR, // * - - // two character tokens. - TOKEN_AND, // && - TOKEN_ARROW, // -> // Not used but reserved - TOKEN_BIT_AND_ASSIGN, // &= - TOKEN_BIT_OR_ASSIGN, // |= - TOKEN_BIT_XOR_ASSIGN, // ^= - TOKEN_DIV_ASSIGN, // /= - TOKEN_DOTDOT, // .. - TOKEN_ELVIS, // ?: - TOKEN_EQEQ, // == - TOKEN_GREATER_EQ, // >= - TOKEN_LESS_EQ, // <= - TOKEN_MINUS_ASSIGN, // -= - TOKEN_MINUSMINUS, // -- - TOKEN_MOD_ASSIGN, // %= - TOKEN_MULT_ASSIGN, // *= - TOKEN_NOT_EQUAL, // != - TOKEN_PLUS_ASSIGN, // += - TOKEN_PLUSPLUS, // ++ - TOKEN_SCOPE, // :: - TOKEN_SHR, // >> - TOKEN_SHL, // >> - - // Three or more - TOKEN_AND_ASSIGN, // &&= - TOKEN_ELIPSIS, // ... - TOKEN_OR_ASSIGN, // ||= - TOKEN_SHR_ASSIGN, // >>= - TOKEN_SHL_ASSIGN, // >>= - - - // Basic types names - TOKEN_VOID, - TOKEN_BYTE, - TOKEN_BOOL, - TOKEN_CHAR, - TOKEN_DOUBLE, - TOKEN_FLOAT, - TOKEN_HALF, - TOKEN_INT, - TOKEN_ISIZE, - TOKEN_LONG, - TOKEN_SHORT, - TOKEN_UINT, - TOKEN_ULONG, - TOKEN_USHORT, - TOKEN_USIZE, - TOKEN_QUAD, - - // Literals. - - - TOKEN_IDENT, // Any normal ident. - TOKEN_CONST_IDENT, // Any purely upper case ident, - TOKEN_TYPE_IDENT, // Any ident on the format FooBar or __FooBar - - // We want to parse @foo / #foo / $foo separately. - // Otherwise we allow things like "@ foo" which would be pretty bad. - TOKEN_AT_IDENT, // @foobar - TOKEN_HASH_IDENT, // #foobar - TOKEN_CT_IDENT, // $foobar - - TOKEN_STRING, // "Teststring" - TOKEN_INTEGER, // 123 0x23 0b10010 0o327 - TOKEN_REAL, // 0x23.2p-2a 43.23e23 - - // Keywords - TOKEN_ALIAS, // Reserved - TOKEN_AS, - TOKEN_ASM, - TOKEN_ATTRIBUTE, - TOKEN_BREAK, - TOKEN_CASE, - TOKEN_CAST, - TOKEN_CATCH, - TOKEN_CONST, - TOKEN_CONTINUE, - TOKEN_DEFAULT, - TOKEN_DEFER, - TOKEN_DO, - TOKEN_ELSE, - TOKEN_ENUM, - TOKEN_ERROR_TYPE, - TOKEN_FALSE, - TOKEN_FOR, - TOKEN_FUNC, - TOKEN_GENERIC, - TOKEN_GOTO, - TOKEN_IF, - TOKEN_IMPORT, - TOKEN_LOCAL, - TOKEN_MACRO, - TOKEN_MODULE, - TOKEN_NEXT, - TOKEN_NIL, - TOKEN_PUBLIC, - TOKEN_RETURN, - TOKEN_STRUCT, - TOKEN_SWITCH, - TOKEN_THROW, - TOKEN_THROWS, - TOKEN_TRUE, - TOKEN_TRY, - TOKEN_TYPE, // Reserved - TOKEN_TYPEDEF, - TOKEN_UNION, - TOKEN_UNTIL, - TOKEN_VAR, // Reserved - TOKEN_VOLATILE, - TOKEN_WHILE, - - TOKEN_AT_PARAM, // @param - TOKEN_AT_THROWS, // @throws - TOKEN_AT_RETURN, // @return - TOKEN_AT_ENSURE, // @ensure - TOKEN_AT_REQUIRE, // @require - TOKEN_AT_PURE, // @pure - TOKEN_AT_CONST, // @const - TOKEN_AT_REQPARSE, // @reqparse - TOKEN_AT_DEPRECATED, // @deprecated - - TOKEN_CT_CASE, // $case - TOKEN_CT_DEFAULT, // $default - TOKEN_CT_EACH, // $each - TOKEN_CT_ELIF, // $elif - TOKEN_CT_ELSE, // $else - TOKEN_CT_IF, // $if - TOKEN_CT_SWITCH, // $switch - - TOKEN_DOCS_START, // /** - TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*` - TOKEN_DOCS_EOL, // "\n" only seen in docs. - TOKEN_DOCS_LINE, // Any line within /** **/ - - TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN. - -} TokenType; - -bool token_is_type(TokenType type); - -const char *token_type_to_string(TokenType type); -static inline const char* struct_union_name_from_token(TokenType type) -{ - return type == TOKEN_STRUCT ? "struct" : "union"; -} diff --git a/src/compiler/types.c b/src/compiler/types.c new file mode 100644 index 000000000..8bab3b4c3 --- /dev/null +++ b/src/compiler/types.c @@ -0,0 +1,224 @@ +// Copyright (c) 2019 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "compiler_internal.h" + +Type type_bool; +Type type_void, type_string; + +Type type_half, type_float, type_double, type_quad; +Type type_char, type_short, type_int, type_long, type_isize; +Type type_byte, type_ushort, type_uint, type_ulong, type_usize; +Type type_compint, type_compuint, type_compfloat; +Type type_c_short, type_c_int, type_c_long, type_c_longlong; +Type type_c_ushort, type_c_uint, type_c_ulong, type_c_ulonglong; + +Type *type_signed_int_by_size(int bitsize) +{ + switch (bitsize) + { + case 1: return &type_char; + case 2: return &type_short; + case 4: return &type_int; + case 8: return &type_long; + default: FATAL_ERROR("Illegal bitsize %d", bitsize); + } +} +Type *type_unsigned_int_by_size(int bitsize) +{ + switch (bitsize) + { + case 1: return &type_byte; + case 2: return &type_ushort; + case 4: return &type_uint; + case 8: return &type_ulong; + default: FATAL_ERROR("Illegal bitsize %d", bitsize); + } +} + +Type *type_new(TypeKind type_kind) +{ + Type *type = malloc_arena(sizeof(Type)); + memset(type, 0, sizeof(Type)); + type->type_kind = type_kind; + return type; +} + +size_t type_size(Type *canonical) +{ + assert(canonical && canonical->canonical == canonical); + switch (canonical->type_kind) + { + case TYPE_POISONED: + case TYPE_INC_ARRAY: + case TYPE_EXPRESSION: + UNREACHABLE; + case TYPE_USER_DEFINED: + TODO + case TYPE_VOID: + return 1; + case TYPE_BOOL: + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_F32: + case TYPE_F64: + return canonical->builtin.bytesize; + case TYPE_IXX: + case TYPE_UXX: + case TYPE_FXX: + return 8; + case TYPE_POINTER: + case TYPE_VARARRAY: + case TYPE_STRING: + return type_isize.canonical->builtin.bytesize; + case TYPE_ARRAY: + return type_size(canonical->base) * canonical->len; + } + TODO +} + +static inline void create_ptr_live_canonical(Type *canonical_type) +{ + assert(canonical_type->canonical == canonical_type); + canonical_type->ptr_like_canonical = VECADD(canonical_type->ptr_like_canonical, NULL); + canonical_type->ptr_like_canonical = VECADD(canonical_type->ptr_like_canonical, NULL); + canonical_type->ptr_like_canonical = VECADD(canonical_type->ptr_like_canonical, NULL); +} + +Type *type_get_canonical_ptr(Type *ptr_type) +{ + Type *canonical_base = ptr_type->base->canonical; + + assert(canonical_base); + + if (!canonical_base->ptr_like_canonical) + { + create_ptr_live_canonical(canonical_base); + } + + Type *canonical_ptr = canonical_base->ptr_like_canonical[(int)ptr_type->nullable]; + if (canonical_ptr == NULL) + { + canonical_ptr = malloc_arena(sizeof(Type)); + *canonical_ptr = *ptr_type; + canonical_ptr->base = canonical_base; + canonical_base->ptr_like_canonical[(int)ptr_type->nullable] = canonical_ptr; + canonical_base->resolve_status = RESOLVE_DONE; + } + + return canonical_ptr; +} + +Type *type_get_canonical_array(Type *arr_type) +{ + Type *canonical_base = arr_type->base->canonical; + if (!arr_type->ptr_like_canonical) + { + create_ptr_live_canonical(canonical_base); + } + + // Dynamic array + if (arr_type->len == 0) + { + Type *canonical = canonical_base->ptr_like_canonical[2]; + if (canonical == NULL) + { + canonical = malloc_arena(sizeof(Type)); + *canonical = *arr_type; + canonical->canonical = canonical_base; + canonical_base->ptr_like_canonical[2] = canonical; + canonical->resolve_status = RESOLVE_DONE; + } + return canonical; + } + + int entries = (int)vec_size(canonical_base->ptr_like_canonical); + for (int i = 3; i < entries; i++) + { + Type *ptr = canonical_base->ptr_like_canonical[i]; + if (ptr->len == arr_type->len) + { + return ptr; + } + } + Type *canonical = malloc_arena(sizeof(Type)); + *canonical = *arr_type; + canonical->base = canonical_base; + canonical->resolve_status = RESOLVE_DONE; + canonical_base->ptr_like_canonical = VECADD(canonical_base->ptr_like_canonical, canonical); + return canonical; +} + +static void create_type(const char *name, Type *location, TypeKind kind, unsigned bytesize, unsigned bitsize) +{ + *location = (Type) { .type_kind = kind, .resolve_status = RESOLVE_DONE, .builtin.bytesize = bytesize, .builtin.bitsize = bitsize }; + location->name_loc.string = name; + location->name_loc.span.length = strlen(name); + location->canonical = location; +} + +static void type_create_alias(const char *name, Type *location, Type *canonical) +{ + *location = (Type) { .type_kind = TYPE_USER_DEFINED, .resolve_status = RESOLVE_DONE }; + location->name_loc.string = name; + location->name_loc.span.length = strlen(name); + location->canonical = canonical; +} + + +void builtin_setup() +{ + create_type("void", &type_void, TYPE_VOID, 1, 8); + + /*TODO + * decl_string = (Decl) { .decl_kind = DECL_BUILTIN, .name.string = "string" }; + create_type(&decl_string, &type_string); + type_string.type_kind = TYPE_STRING; +*/ +#define DEF_TYPE(_name, _type, _bits) \ +create_type(#_name, &type_ ## _name, _type, (_bits + 7) / 8, _bits); + + DEF_TYPE(compint, TYPE_IXX, 64); + DEF_TYPE(compuint, TYPE_UXX, 64); + DEF_TYPE(compfloat, TYPE_FXX, 64); + DEF_TYPE(bool, TYPE_BOOL, 1); + +// DEF_TYPE(half, 2, 16, NUMBER_TYPE_FLOAT, "half", T_F16); + DEF_TYPE(float, TYPE_F32, 32); + DEF_TYPE(double, TYPE_F64, 64); +// DEF_TYPE(quad, 16, 128, NUMBER_TYPE_FLOAT, "long double", T_F128); + + DEF_TYPE(char, TYPE_I8, 8); + DEF_TYPE(short, TYPE_I16, 16); + DEF_TYPE(int, TYPE_I32, 32); + DEF_TYPE(long, TYPE_I64, 64); + + DEF_TYPE(byte, TYPE_U8, 8); + DEF_TYPE(ushort, TYPE_U16, 16); + DEF_TYPE(uint, TYPE_U32, 32); + DEF_TYPE(ulong, TYPE_U64, 64); + + type_create_alias("usize", &type_usize, type_unsigned_int_by_size(build_options.pointer_size)); + type_create_alias("isize", &type_isize, type_signed_int_by_size(build_options.pointer_size)); + + type_create_alias("c_ushort", &type_c_ushort, type_unsigned_int_by_size(build_options.cshort_size)); + type_create_alias("c_uint", &type_c_uint, type_unsigned_int_by_size(build_options.cint_size)); + type_create_alias("c_ulong", &type_c_ulong, type_unsigned_int_by_size(build_options.clong_size)); + type_create_alias("c_ulonglong", &type_c_ulonglong, type_unsigned_int_by_size(build_options.clonglong_size)); + + type_create_alias("c_short", &type_c_short, type_signed_int_by_size(build_options.cshort_size)); + type_create_alias("c_int", &type_c_int, type_signed_int_by_size(build_options.cint_size)); + type_create_alias("c_long", &type_c_long, type_signed_int_by_size(build_options.clong_size)); + type_create_alias("c_longlong", &type_c_longlong, type_signed_int_by_size(build_options.clonglong_size)); + + +#undef DEF_TYPE + +} \ No newline at end of file diff --git a/src/compiler/value.c b/src/compiler/value.c deleted file mode 100644 index 366392cbd..000000000 --- a/src/compiler/value.c +++ /dev/null @@ -1,902 +0,0 @@ -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "value.h" -#include "ast.h" - - -#define ERROR_VALUE (Value) { .type = VALUE_TYPE_ERROR } - - -Value value_new_int_with_bigint(BigInt big_int) -{ - return (Value) { .big_int = big_int, .type = VALUE_TYPE_INT }; -} - -Value value_new_float(long double f) -{ - return (Value) { .f = f, .type = VALUE_TYPE_FLOAT }; -} -Value value_new_int_with_int(int64_t val) -{ - Value value = { .type = VALUE_TYPE_INT }; - bigint_init_signed(&value.big_int, val); - return value; -} - - -Value value_nil() -{ - return (Value) { .b = false, .type = VALUE_TYPE_NIL }; -} - -Value value_not(Value value) -{ - switch (value.type) - { - case VALUE_TYPE_FLOAT: - return (Value) { .b = value.f == 0.0, .type = VALUE_TYPE_BOOL }; - case VALUE_TYPE_INT: - return (Value) { .b = bigint_cmp_zero(&value.big_int) == CMP_EQ, .type = VALUE_TYPE_BOOL }; - case VALUE_TYPE_BOOL: - return (Value) { .b = !value.b, .type = VALUE_TYPE_BOOL }; - case VALUE_TYPE_NIL: - return value_new_bool(true); - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - break; - } - return ERROR_VALUE; -} - -#define BIN_OP(_x, _intop, _floatop) \ -Value value_## _x(Value lhs, Value rhs) { \ - assert(lhs.type == rhs.type); \ - switch (lhs.type)\ - { \ - case VALUE_TYPE_FLOAT: \ - return (Value) { .f = lhs.f _floatop rhs.f, .type = VALUE_TYPE_FLOAT }; \ - case VALUE_TYPE_INT: {\ - Value value = value_new_int_with_int(0);\ - _intop(&value.big_int, &lhs.big_int, &rhs.big_int); \ - return value;\ - }\ - case VALUE_TYPE_BOOL:\ - case VALUE_TYPE_STRING:\ - case VALUE_TYPE_NIL:\ - case VALUE_TYPE_ERROR:\ - return ERROR_VALUE;\ - }\ -} - -#define BIN_OP_W(_x, _intop, _intopwrap, _floatop) \ -Value value_## _x(Value lhs, Value rhs) { \ - assert(lhs.type == rhs.type); \ - switch (lhs.type)\ - { \ - case VALUE_TYPE_FLOAT: \ - return (Value) { .f = lhs.f _floatop rhs.f, .type = VALUE_TYPE_FLOAT }; \ - case VALUE_TYPE_INT: {\ - Value value = value_new_int_with_int(0);\ - if (lhs.int_bits > 0) { \ - value.int_bits = lhs.int_bits; value.is_unsigned = lhs.is_unsigned; \ - _intopwrap(&value.big_int, &lhs.big_int, &rhs.big_int, lhs.int_bits, !lhs.is_unsigned); \ - } else { \ - _intop(&value.big_int, &lhs.big_int, &rhs.big_int); \ - };\ - return value;\ - }\ - case VALUE_TYPE_BOOL:\ - case VALUE_TYPE_STRING:\ - case VALUE_TYPE_NIL:\ - case VALUE_TYPE_ERROR:\ - return ERROR_VALUE;\ - }\ -} - -BIN_OP_W(add, bigint_add, bigint_add_wrap, +) -BIN_OP_W(mult, bigint_mul, bigint_mul_wrap, *) -BIN_OP(div, bigint_div_floor, /) -BIN_OP(mod, bigint_mod, /) - -Value value_sub(Value value1, Value value2) -{ - return value_add(value1, value_negate(value2)); -} - -Value value_and(Value value1, Value value2) -{ - if (value1.type == VALUE_TYPE_BOOL && value2.type == VALUE_TYPE_BOOL) - { - value1.b = value1.b && value2.b; - return value1; - } - - assert(value1.type == VALUE_TYPE_INT && value2.type == VALUE_TYPE_INT); - assert(value1.int_bits == value2.int_bits); - BigInt res; - bigint_and(&res, &value1.big_int, &value2.big_int); - value1.big_int = res; - return value1; -} - -Value value_or(Value value1, Value value2) -{ - if (value1.type == VALUE_TYPE_BOOL && value2.type == VALUE_TYPE_BOOL) - { - value1.b = value1.b || value2.b; - return value1; - } - assert(value1.type == VALUE_TYPE_INT && value2.type == VALUE_TYPE_INT); - assert(value1.int_bits == value2.int_bits); - BigInt res; - bigint_or(&res, &value1.big_int, &value2.big_int); - value1.big_int = res; - return value1; -} - -static inline CmpRes cmp(Value value1, Value value2) -{ - switch (value1.type) - { - case VALUE_TYPE_BOOL: - if (value1.b < value2.b) return CMP_LT; - return value1.b == value2.b ? CMP_EQ : CMP_GT; - case VALUE_TYPE_INT: - return bigint_cmp(&value1.big_int, &value2.big_int); - case VALUE_TYPE_FLOAT: - if (value1.f < value2.b) return CMP_LT; - return value2.f > value2.f ? CMP_GT : CMP_EQ; - default: - UNREACHABLE; - } - UNREACHABLE -} - -bool value_le(Value value1, Value value2) -{ - CmpRes res = cmp(value1, value2); - return res != CMP_GT; -} - -bool value_ge(Value value1, Value value2) -{ - CmpRes res = cmp(value1, value2); - return res != CMP_LT; -} - -bool value_gt(Value value1, Value value2) -{ - CmpRes res = cmp(value1, value2); - return res == CMP_GT; -} - -bool value_lt(Value value1, Value value2) -{ - CmpRes res = cmp(value1, value2); - return res == CMP_LT; -} - -bool value_eq(Value value1, Value value2) -{ - CmpRes res = cmp(value1, value2); - return res == CMP_EQ; -} - -bool value_ne(Value value1, Value value2) -{ - CmpRes res = cmp(value1, value2); - return res != CMP_EQ; -} - -Value value_xor(Value value1, Value value2) -{ - if (value1.type == VALUE_TYPE_BOOL && value2.type == VALUE_TYPE_BOOL) - { - value1.b = value1.b ^ value2.b; - return value1; - } - assert(value1.type == VALUE_TYPE_INT && value2.type == VALUE_TYPE_INT); - assert(value1.int_bits == value2.int_bits); - BigInt res; - bigint_xor(&res, &value1.big_int, &value2.big_int); - value1.big_int = res; - return value1; -} - -Value value_negate(Value value) -{ - switch (value.type) - { - case VALUE_TYPE_INT: - { - Value result = value_new_int_with_int(0); - result.is_unsigned = value.is_unsigned; - result.int_bits = value.int_bits; - if (value.int_bits) - { - bigint_negate_wrap(&result.big_int, &value.big_int, value.int_bits); - } - else - { - bigint_negate(&result.big_int, &value.big_int); - } - return result; - } - case VALUE_TYPE_BOOL: - return value_new_int_with_int(value.b ? -1 : 0); - case VALUE_TYPE_FLOAT: - return value_new_float(-value.f); - case VALUE_TYPE_NIL: - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - break; - } - return ERROR_VALUE; -} - -Value value_bit_not(Value value) -{ - switch (value.type) - { - case VALUE_TYPE_INT: - { - value_print(value); - printf("--%d--\n", value.is_unsigned); - Value result = value_new_int_with_int(0); - result.is_unsigned = value.is_unsigned; - result.int_bits = value.int_bits; - if (!value.int_bits) - { - FATAL_ERROR("Not supported"); - } - bigint_not(&result.big_int, &value.big_int, value.int_bits, !value.is_unsigned); - value_print(result); - printf("--%d--\n", result.is_unsigned); - return result; - } - case VALUE_TYPE_BOOL: - return value_new_int_with_int(value.b ? 0 : 1); - case VALUE_TYPE_FLOAT: - case VALUE_TYPE_NIL: - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - break; - } - return ERROR_VALUE; -} - -inline Value value_new_bool(bool value) -{ - return (Value) { .b = value, .type = VALUE_TYPE_BOOL }; -} - -Value value_new_string(const char *string, uint32_t len) -{ - return (Value) { .str = string, .str_len = len, .type = VALUE_TYPE_STRING }; -} - -bool value_as_bool(Value *value) -{ - switch (value->type) - { - case VALUE_TYPE_FLOAT: - return value->f != 0.0; - case VALUE_TYPE_INT: - return bigint_cmp_zero(&value->big_int) != CMP_EQ; - case VALUE_TYPE_BOOL: - return value->b; - case VALUE_TYPE_NIL: - return false; - case VALUE_TYPE_STRING: - return true; - case VALUE_TYPE_ERROR: - return false; - } -} - -Value value_to_bool(Value value) -{ - switch (value.type) - { - case VALUE_TYPE_FLOAT: - return value_new_bool(value.f != 0.0); - case VALUE_TYPE_INT: - return value_new_bool(bigint_cmp_zero(&value.big_int) != CMP_EQ); - case VALUE_TYPE_BOOL: - return value; - case VALUE_TYPE_NIL: - return value_new_bool(false); - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - break; - } - return ERROR_VALUE; -} - -Value value_float(Value value) -{ - switch (value.type) - { - case VALUE_TYPE_FLOAT: - return value_new_bool(value.f != 0.0); - case VALUE_TYPE_INT: - return value_new_bool(bigint_cmp_zero(&value.big_int) != CMP_EQ); - case VALUE_TYPE_BOOL: - return value; - case VALUE_TYPE_NIL: - return value_new_bool(false); - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - break; - } - return ERROR_VALUE; -} - -const char *value_type_name(const Value *value) -{ - switch (value->type) - { - case VALUE_TYPE_BOOL: - return "bool"; - case VALUE_TYPE_NIL: - return "nil"; - case VALUE_TYPE_FLOAT: - switch (value->float_bits) - { - case 0: return "float"; - case 16: return "f16"; - case 32: return "f32"; - case 64: return "f64"; - case 128: return "f128"; - default: - UNREACHABLE; - } - case VALUE_TYPE_STRING: - return "string"; - case VALUE_TYPE_INT: - switch (value->int_bits) - { - case 0: return "int"; - case 8: return value->is_unsigned ? "u8" : "i8"; - case 16: return value->is_unsigned ? "u16" : "i16"; - case 32: return value->is_unsigned ? "u32" : "i32"; - case 64: return value->is_unsigned ? "u64" : "i64"; - default: - UNREACHABLE; - } - case VALUE_TYPE_ERROR: - return ""; - } - FATAL_ERROR("Can't happen"); -} - - - -bool value_is_number(const Value *value) -{ - return value->type == VALUE_TYPE_INT || value->type == VALUE_TYPE_FLOAT; -} - -Type *value_find_type(const Value *value) -{ - switch (value->type) - { - case VALUE_TYPE_FLOAT: - switch (value->float_bits) - { - case 0: return &type_compfloat; - case 16: return &type_half; - case 32: return &type_float; - case 64: return &type_double; -// case 128: return type_builtin_f128(); - default: break; - } - UNREACHABLE - case VALUE_TYPE_INT: - switch (value->int_bits) - { - case 0: return &type_compint; - case 8: return value->is_unsigned ? &type_byte : &type_char; - case 16: return value->is_unsigned ? &type_ushort : &type_short; - case 32: return value->is_unsigned ? &type_uint : &type_int; - case 64: return value->is_unsigned ? &type_ulong : &type_long; - default: break; - } - UNREACHABLE - case VALUE_TYPE_BOOL: - return &type_bool; - case VALUE_TYPE_NIL: - return &type_nil; - case VALUE_TYPE_STRING: - return &type_string; - case VALUE_TYPE_ERROR: - return &poisoned_type; - } -} - - - -// Assume well-formed hex! -static inline Value parse_hex(const char *string, int len) -{ - Value value = { .type = VALUE_TYPE_INT }; - BigInt *b = &value.big_int; - bigint_init_signed(b, 0); - const char *end = string + len; - BigInt temp = { .digit_count = 0 }; - BigInt add = { .digit_count = 0 }; - while (string < end) - { - char c = *(string++); - if (c == '_') continue; - bigint_shl_int(&temp, b, 4); - if (c < 'A') - { - bigint_init_signed(&add, (c - '0')); - } - else if (c < 'a') - { - bigint_init_signed(&add, (c - 'A' + 10)); - } - else - { - bigint_init_signed(&add, (c - 'a' + 10)); - } - bigint_add(b, &temp, &add); - } - return value; -} - -static inline Value parse_dec(const char *string, int len) -{ - Value value = { .type = VALUE_TYPE_INT }; - BigInt *b = &value.big_int; - bigint_init_signed(b, 0); - const char *end = string + len; - BigInt temp = { .digit_count = 0 }; - BigInt mult; - bigint_init_signed(&mult, 10); - BigInt add = { .digit_count = 0 }; - while (string < end) - { - char c = *(string++); - if (c == '_') continue; - bigint_mul(&temp, b, &mult); - bigint_init_signed(&add, (c - '0')); - bigint_add(b, &temp, &add); - } - return value; -} - -static inline Value parse_oct(const char *string, int len) -{ - Value value = { .type = VALUE_TYPE_INT }; - BigInt *b = &value.big_int; - bigint_init_signed(b, 0); - const char *end = string + len; - BigInt temp = { .digit_count = 0 }; - BigInt add = { .digit_count = 0 }; - while (string < end) - { - char c = *(string++); - if (c == '_') continue; - bigint_shl_int(&temp, b, 3); - bigint_init_signed(&add, (c - '0')); - bigint_add(b, &temp, &add); - } - return value; -} - -static inline Value parse_bin(const char *string, int len) -{ - Value value = { .type = VALUE_TYPE_INT }; - BigInt *b = &value.big_int; - bigint_init_signed(b, 0); - const char *end = string + len; - BigInt temp = { .digit_count = 0 }; - BigInt add = { .digit_count = 0 }; - while (string < end) - { - char c = *(string++); - if (c == '_') continue; - bigint_shl_int(&temp, b, 1); - bigint_init_signed(&add, (c - '0')); - bigint_add(b, &temp, &add); - } - return value; -} - -// Parse normal integers, parse 0xBEEF, parse 0o1337, parse 0b1010101 – positive numbers only -Value parse_int(const char *string, int len) -{ - if (len > 2) - { - switch (string[1]) - { - case 'x': - return parse_hex(string + 2, (uint16_t) (len - 2)); - case 'o': - return parse_oct(string + 2, (uint16_t) (len - 2)); - case 'b': - return parse_bin(string + 2, (uint16_t) (len - 2)); - default: - break; - } - } - return parse_dec(string, (uint16_t) len); -} - -void value_print(Value value) -{ - switch (value.type) - { - case VALUE_TYPE_BOOL: - printf(value.b ? "true" : "false"); - break; - case VALUE_TYPE_STRING: - printf("%.*s", value.str_len, value.str); - break; - case VALUE_TYPE_INT: - bigint_print(&value.big_int, 10); - break; - case VALUE_TYPE_ERROR: - printf("ERROR"); - break; - case VALUE_TYPE_FLOAT: - printf("%Lf", value.f); - break; - case VALUE_TYPE_NIL: - printf("nil"); - break; - } -} - -void value_fprint(FILE *file, Value value) -{ - switch (value.type) - { - case VALUE_TYPE_BOOL: - fprintf(file, value.b ? "true" : "false"); - break; - case VALUE_TYPE_STRING: - fprintf(file, "%.*s", value.str_len, value.str); - break; - case VALUE_TYPE_INT: - bigint_fprint(file, &value.big_int, 10); - break; - case VALUE_TYPE_ERROR: - fprintf(file, "ERROR"); - break; - case VALUE_TYPE_FLOAT: - fprintf(file, "%Lf", value.f); - break; - case VALUE_TYPE_NIL: - fprintf(file, "nil"); - break; - } -} - - -void value_update_to_float(Value *value, long double f, uint16_t bits) -{ - value->f = f; - value->type = VALUE_TYPE_FLOAT; - value->float_bits = bits; -} -/** - * Convert value2 to value1 (note that we have already ordered things in conversion order. - * - * @param value1 - * @param value2 - * @return true if conversion worked. - */ -static bool value_convert_to_type_ordered(Value *value1, Value *value2) -{ - switch (value1->type) - { - case VALUE_TYPE_FLOAT: - switch (value2->type) - { - case VALUE_TYPE_FLOAT: - value1->float_bits = value2->float_bits; - return true; - case VALUE_TYPE_INT: - value_update_to_float(value2, bigint_as_float(&value2->big_int), value1->float_bits); - return true; - case VALUE_TYPE_BOOL: - value_update_to_float(value2, value2->b ? 1.0 : 0.0, value1->float_bits); - return true; - case VALUE_TYPE_NIL: - value_update_to_float(value2, 0.0, value1->float_bits); - return true; - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - return false; - } - UNREACHABLE - case VALUE_TYPE_INT: - switch (value2->type) - { - case VALUE_TYPE_INT: - // First check if we have a comptime int. If so, check that it fits. - if (value2->int_bits == 0) - { - if (value1->int_bits == 0) return true; - if (!bigint_fits_in_bits(&value2->big_int, value1->int_bits, !value1->is_unsigned)) return false; - BigInt res; - bigint_truncate(&res, &value2->big_int, value1->int_bits, !value1->is_unsigned); - value2->big_int = res; - return true; - } - if (!value1->is_unsigned && value2->is_unsigned) - { - // If unsigned value is same or larger, disallow! - if (value1->int_bits <= value2->int_bits) return false; - - value2->is_unsigned = false; - value2->int_bits = value1->int_bits; - return true; - } - // Final case, both has same sign, promote to largest. - value2->int_bits = value1->int_bits; - return true; - case VALUE_TYPE_BOOL: - bigint_init_unsigned(&value2->big_int, value2->b ? 1 : 0); - value2->int_bits = value1->int_bits; - value2->is_unsigned = value1->is_unsigned; - value2->type = VALUE_TYPE_INT; - return true; - case VALUE_TYPE_NIL: - bigint_init_unsigned(&value2->big_int, 0); - value2->int_bits = value1->int_bits; - value2->is_unsigned = value1->is_unsigned; - value2->type = VALUE_TYPE_INT; - return true; - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - return false; - case VALUE_TYPE_FLOAT: - UNREACHABLE; - } - UNREACHABLE; - case VALUE_TYPE_BOOL: - switch (value2->type) - { - case VALUE_TYPE_BOOL: - return true; - case VALUE_TYPE_NIL: - value2->b = false; - value2->type = VALUE_TYPE_BOOL; - return true; - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - return false; - case VALUE_TYPE_FLOAT: - case VALUE_TYPE_INT: - UNREACHABLE; - } - UNREACHABLE; - case VALUE_TYPE_NIL: - switch (value2->type) - { - case VALUE_TYPE_NIL: - return true; - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - return false; - case VALUE_TYPE_FLOAT: - case VALUE_TYPE_BOOL: - case VALUE_TYPE_INT: - UNREACHABLE; - } - UNREACHABLE; - case VALUE_TYPE_STRING: - return value2->type == VALUE_TYPE_STRING; - case VALUE_TYPE_ERROR: - return false; - } - UNREACHABLE; -} - -bool value_convert_to_type(Value *value1, Value *value2) -{ - bool reverse_order = false; - if (value2->type == value1->type) - { - switch (value1->type) - { - case VALUE_TYPE_FLOAT: - reverse_order = value2->float_bits > value1->float_bits; - break; - case VALUE_TYPE_INT: - if (value1->is_unsigned != value2->is_unsigned) - { - reverse_order = value1->is_unsigned; - break; - } - reverse_order = value2->int_bits > value1->int_bits; - break; - case VALUE_TYPE_BOOL: - case VALUE_TYPE_NIL: - case VALUE_TYPE_STRING: - case VALUE_TYPE_ERROR: - break; - } - } - else - { - reverse_order = value2->type < value1->type; - } - return reverse_order ? value_convert_to_type_ordered(value2, value1) : value_convert_to_type_ordered(value1, value2); -} - - -static inline bool set_bits_and_truncate_int_value_if_needed(Value *value, uint16_t bits, bool allow_trunc) -{ - value->int_bits = bits; - - // No truncation - if (bits == 0) return true; - - // If it fits then we're fine. - if (bigint_fits_in_bits(&value->big_int, bits, !value->is_unsigned)) - { - return true; - } - - // If we can truncate, do so. - if (allow_trunc) - { - BigInt temp; - bigint_truncate(&temp, &value->big_int, bits, !value->is_unsigned); - value->big_int = temp; - return true; - } - - // Otherwise fail. - return false; -} - -bool value_int_change_sign(Value *value, bool is_unsigned, bool allow_trunc) -{ - if (value->is_unsigned == is_unsigned) return true; - if (value->is_unsigned) - { - value->is_unsigned = false; - - // No bit limit? Goodie - if (!value->int_bits) return true; - - // If it fits, then we're golden. - if (bigint_fits_in_bits(&value->big_int, value->int_bits, true)) return true; - - // If not and we're not allowed conversion? Exit: - if (!allow_trunc) return false; - - BigInt temp; - bigint_truncate(&temp, &value->big_int, value->int_bits, true); - value->big_int = temp; - // TODO verify that this actually works! - return true; - } - else - { - // Signed to unsigned - value->is_unsigned = true; - - // No bit limit? Goodie - if (!value->int_bits) return true; - - // If the value was positive we're golden - if (!value->big_int.is_negative) return true; - - // If not and we're not allowed conversion? Exit: - if (!allow_trunc) return false; - - BigInt temp; - bigint_truncate(&temp, &value->big_int, value->int_bits, false); - value->big_int = temp; - // TODO verify that this actually works! - return true; - } -} - -bool value_convert(Value *value, ValueType type, uint16_t bits, bool is_unsigned, bool allow_trunc) -{ - switch (type) - { - case VALUE_TYPE_FLOAT: - switch (value->type) - { - case VALUE_TYPE_FLOAT: - // TODO actual truncation - value->float_bits = bits; - break; - case VALUE_TYPE_INT: - value->f = bigint_as_float(&value->big_int); - break; - case VALUE_TYPE_BOOL: - value->f = value->b ? 1.0 : 0.0; - break; - case VALUE_TYPE_NIL: - value->f = 0.0; - break; - case VALUE_TYPE_STRING: - return false; - case VALUE_TYPE_ERROR: - return false; - } - value->float_bits = bits; - value->type = VALUE_TYPE_FLOAT; - return true; - case VALUE_TYPE_INT: - switch (value->type) - { - case VALUE_TYPE_FLOAT: - if (value->f < 0 && is_unsigned) - { - if (!allow_trunc) return false; - // First convert to signed, then convert to unsigned. - bool success = value_convert(value, type, bits, false, true); - assert(success && "Unexpected failure"); - return value_convert(value, type, bits, true, true); - } - // TODO actual expansion - bigint_init_signed(&value->big_int, (int64_t)value->f); - value->is_unsigned = is_unsigned; - value->type = VALUE_TYPE_INT; - return set_bits_and_truncate_int_value_if_needed(value, bits, allow_trunc); - case VALUE_TYPE_INT: - if (!value_int_change_sign(value, is_unsigned, allow_trunc)) return false; - return set_bits_and_truncate_int_value_if_needed(value, bits, allow_trunc); - case VALUE_TYPE_BOOL: - value->type = VALUE_TYPE_INT; - value->int_bits = bits; - value->is_unsigned = is_unsigned; - bigint_init_unsigned(&value->big_int, value->b ? 1 : 0); - return true; - case VALUE_TYPE_NIL: - value->type = VALUE_TYPE_INT; - value->int_bits = bits; - value->is_unsigned = is_unsigned; - bigint_init_unsigned(&value->big_int, 0); - return true; - case VALUE_TYPE_STRING: - return false; - case VALUE_TYPE_ERROR: - return false; - } - UNREACHABLE - case VALUE_TYPE_BOOL: - switch (value->type) - { - case VALUE_TYPE_FLOAT: - if (!allow_trunc) return false; - value->b = value->f != 0.0; - break; - case VALUE_TYPE_INT: - value->b = value->big_int.digit_count != 0; - break; - case VALUE_TYPE_BOOL: - return true; - case VALUE_TYPE_NIL: - value->b = false; - break; - case VALUE_TYPE_STRING: - return false; - case VALUE_TYPE_ERROR: - return false; - } - value->type = VALUE_TYPE_BOOL; - return true; - case VALUE_TYPE_NIL: - return value->type == VALUE_TYPE_NIL; - case VALUE_TYPE_STRING: - return value->type == VALUE_TYPE_STRING; - case VALUE_TYPE_ERROR: - return false; - } - UNREACHABLE -} diff --git a/src/compiler/value.h b/src/compiler/value.h deleted file mode 100644 index 70a0747e8..000000000 --- a/src/compiler/value.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -// Copyright (c) 2019 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "compiler_common.h" -#include "bigint.h" - -// DO NOT CHANGE ORDER! -typedef enum _ValueType -{ - VALUE_TYPE_FLOAT, - VALUE_TYPE_INT, - VALUE_TYPE_BOOL, - VALUE_TYPE_NIL, - VALUE_TYPE_STRING, - VALUE_TYPE_ERROR, -} ValueType; - -typedef struct _BigInt BigInt; - -typedef struct _Value -{ - ValueType type; - union - { - struct - { - BigInt big_int; - bool is_unsigned; - uint16_t int_bits; - }; - struct - { - long double f; - uint16_t float_bits; - }; - bool b; - struct { - const char *str; - uint32_t str_len; - }; - }; - uint32_t len; -} Value; - - -bool value_is_number(const Value *value); -Value value_new_int_with_bigint(BigInt big_int); -Value value_new_int_with_int(int64_t val); -Value value_new_float(long double f); -Value value_new_string(const char *string, uint32_t len); -Value value_new_bool(bool value); -Value value_to_bool(Value value); -Value value_negate(Value value); -Value value_bit_not(Value value); -Value value_mult(Value lhs, Value rhs); -Value value_sub(Value lhs, Value rhs); -Value value_xor(Value lhs, Value rhs); -bool value_ne(Value value1, Value value2); -bool value_eq(Value value1, Value value2); -bool value_gt(Value value1, Value value2); -bool value_lt(Value value1, Value value2); -bool value_ge(Value value1, Value value2); -bool value_le(Value value1, Value value2); - -Value value_and(Value lhs, Value rhs); -Value value_or(Value lhs, Value rhs); -Value value_add(Value lhs, Value rhs); -Value value_mod(Value lhs, Value rhs); -Value value_div(Value lhs, Value rhs); -Value value_not(Value value); -Value value_nil(); -void value_update_to_float(Value *value, long double f, uint16_t bits); -const char *value_type_name(const Value *value); -Type *value_find_type(const Value *value); -void value_print(Value value); -void value_fprint(FILE *file, Value value); -bool value_as_bool(Value *value); - -bool value_convert_to_type(Value *value1, Value *value2); -bool value_convert(Value *value, ValueType type, uint16_t bits, bool is_unsigned, bool allow_trunc); - - -// Parse normal integers, parse 0xBEEF, parse 0o1337, parse 0b1010101 – positive numbers only -Value parse_int(const char *string, int len); diff --git a/src/compiler_tests/tests.c b/src/compiler_tests/tests.c index f7511c4b4..94e843428 100644 --- a/src/compiler_tests/tests.c +++ b/src/compiler_tests/tests.c @@ -2,17 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include #include "tests.h" #include #include #include -#include -#include -#include -#include +#include "compiler/compiler_internal.h" #include "benchmark.h" -#include "../compiler/symtab.h" static void test_lexer(void) { diff --git a/src/main.c b/src/main.c index 9a4839d51..3b9a15fc6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,10 @@ #include -#include +#include "compiler/compiler.h" #include "build/build_options.h" #include "build/project_creation.h" -#include "utils/errors.h" #include "compiler_tests/tests.h" -#include "utils/malloc.h" +#include "utils/lib.h" + int main(int argc, const char *argv[]) { init_arena(); diff --git a/src/utils/common.h b/src/utils/common.h index ba850c2b5..ad0d32398 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -8,7 +8,9 @@ #include #include #include +#include #include #include "errors.h" +#include #define MAX_IDENTIFIER_LENGTH 31 \ No newline at end of file diff --git a/src/utils/file_utils.c b/src/utils/file_utils.c index 61de104d9..357d1008c 100644 --- a/src/utils/file_utils.c +++ b/src/utils/file_utils.c @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "file_utils.h" #include "errors.h" #include "malloc.h" #include "lib.h" diff --git a/src/utils/file_utils.h b/src/utils/file_utils.h index f747691bc..2674c66ab 100644 --- a/src/utils/file_utils.h +++ b/src/utils/file_utils.h @@ -6,8 +6,4 @@ #include "common.h" -const char* expand_path(const char* path); -char *read_file(const char *path, size_t *return_size); - -int filename_to_module(const char *path, char buffer[MAX_IDENTIFIER_LENGTH + 1]); diff --git a/src/utils/lib.h b/src/utils/lib.h index ae52c6f60..45d9ddb0e 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -6,7 +6,18 @@ #include #include -#include "malloc.h" + +const char* expand_path(const char* path); +char *read_file(const char *path, size_t *return_size); +int filename_to_module(const char *path, char buffer[MAX_IDENTIFIER_LENGTH + 1]); +void init_arena(void); +void *malloc_arena(unsigned long mem); +void free_arena(void); + +void run_arena_allocator_tests(void); + +#define MALLOC(mem) malloc_arena(mem) +#define MALLOCS(type) malloc_arena(sizeof(type)) static inline bool is_power_of_two(uint64_t x) { diff --git a/src/utils/malloc.h b/src/utils/malloc.h index 75fcfccd2..78adbee03 100644 --- a/src/utils/malloc.h +++ b/src/utils/malloc.h @@ -6,11 +6,3 @@ #include "common.h" -void init_arena(void); -void *malloc_arena(unsigned long mem); -void free_arena(void); - -void run_arena_allocator_tests(void); - -#define MALLOC(mem) malloc_arena(mem) -#define MALLOCS(type) malloc_arena(sizeof(type)) \ No newline at end of file