diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dcfae407..09a5e7eda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,25 +108,7 @@ set(LLVM_LINK_COMPONENTS XCoreDisassembler XCoreCodeGen ) -# XRay WindowsManifest Symbolize JITLink MCA LTO Passes ObjCARCOpts -#LineEditor LibDriver Interpreter FuzzMutate MCJIT ExecutionEngine -#RuntimeDyld DlltoolDriver Option DebugInfoGSYM Coverage Coroutines -# -# -# -# NVPTXDesc -# -# -# H -#BPFDesc ARMUtils -#AMDGPUDisassembler MIRParser ipo Instrumentation -#Vectorize Linker IRReader AsmParser AMDGPUDesc AMDGPUUtils -# MCDisassembler GlobalISel SelectionDAG -# DebugInfoDWARF CodeGen Target ScalarOpts InstCombine -#AggressiveInstCombine TransformUtils BitWriter Analysis ProfileData Object -#TextAPI BitReader Core Remarks BitstreamReader AArch64AsmParser MCParser -# MC DebugInfoCodeView DebugInfoMSF BinaryFormat AArch64Utils -# Support Demangle + llvm_map_components_to_libnames(llvm_libs support core irreader ${LLVM_LINK_COMPONENTS}) include_directories( @@ -154,7 +136,6 @@ add_executable(c3c src/compiler/bigint.c src/compiler/bigint.h src/compiler/context.c - src/compiler/codegen.c src/compiler/expr_analysis.c src/compiler/enums.h src/compiler/casts.c @@ -162,7 +143,16 @@ add_executable(c3c src/compiler/compiler.h src/compiler/types.c src/compiler/module.c - src/compiler/llvm_codegen.c src/utils/stringutils.c src/compiler/dwarf.h src/compiler/llvm_codegen_stmt.c src/compiler/llvm_codegen_internal.h src/compiler/llvm_codegen_expr.c src/compiler/llvm_codegen_debug_info.c src/compiler/llvm_codegen_module.c src/compiler/llvm_codegen_type.c src/compiler/llvm_codegen_function.c) + src/compiler/llvm_codegen.c + src/utils/stringutils.c + src/compiler/dwarf.h + src/compiler/llvm_codegen_stmt.c + src/compiler/llvm_codegen_internal.h + src/compiler/llvm_codegen_expr.c + src/compiler/llvm_codegen_debug_info.c + src/compiler/llvm_codegen_module.c + src/compiler/llvm_codegen_type.c + src/compiler/llvm_codegen_function.c) target_compile_options(c3c PRIVATE -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 83f016ee8..68d8c91b7 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -1,9 +1,47 @@ module bar; -func void test(int x) +typedef int as Bob; + + +struct Test { + int a; +} + +struct Test2 +{ + Test t; + int b; +} + +union Test3 +{ + long eo; + Test t; + int b; +} + +func int boba(int y, int j) +{ + int x = y * 2; + int z = j; + while (j > 10) + { + z--; + x = x + z * 2; + } + return x; +} +func int test(int x) +{ + Test3 foekf; + Test oef; + Test2 foek; int i = x; - switch (i + 1) + Bob foo = x; + Bob fe = 0; + fe++; + switch (fe + 1) { case 1: i = i + 1; @@ -16,16 +54,27 @@ func void test(int x) i = i * 100; case 7: } - return; + i++; + int y = i--; + return y; } func int test3() { - return 1; + if (test() < 0) return -1; + return 5; } typedef func void(int) as Foo; //typedef int as Foo; +func void printf(char *hello); + +func int main(int x) +{ + printf("Hello worldABC" "D" "E\u2701\n"); + return 4 * test3(); +} + func void test2(int* x, int y, int z) { int i = 3; diff --git a/src/build/build_options.c b/src/build/build_options.c index ca4e86d04..b2e3ad62e 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -56,6 +56,7 @@ static void usage(void) OUTPUT(" -O2 - Default optimization level."); OUTPUT(" -Os - Optimize for size."); OUTPUT(" -O3 - Aggressive optimization."); + OUTPUT(" --emit-llvm - Emit LLVM IR as a .ll file per module."); } @@ -216,10 +217,20 @@ static void parse_option() { build_options.optimization_level = OPTIMIZATION_LESS; } - else if (match_shortopt("O2") || match_shortopt("Os")) + else if (match_shortopt("O2")) { build_options.optimization_level = OPTIMIZATION_DEFAULT; } + else if (match_shortopt("Os")) + { + build_options.optimization_level = OPTIMIZATION_DEFAULT; + build_options.size_optimization_level = SIZE_OPTIMIZATION_SMALL; + } + else if (match_shortopt("Oz")) + { + build_options.optimization_level = OPTIMIZATION_DEFAULT; + build_options.size_optimization_level = SIZE_OPTIMIZATION_TINY; + } else if (match_shortopt("O3")) { build_options.optimization_level = OPTIMIZATION_AGGRESSIVE; @@ -250,6 +261,11 @@ static void parse_option() OUTPUT("C3 is low level programming language based on C."); exit(EXIT_SUCCESS); } + if (match_longopt("emit-llvm")) + { + build_options.emit_llvm = true; + return; + } if (match_longopt("lib")) { if (at_end() || next_is_opt()) error_exit("error: --lib needs a directory."); @@ -300,8 +316,11 @@ void parse_arguments(int argc, const char *argv[]) build_options.clonglong_size = sizeof(long long); build_options.pointer_size = sizeof(void *); build_options.path = "."; + build_options.emit_llvm = false; + build_options.emit_bitcode = true; build_options.optimization_level = OPTIMIZATION_NOT_SET; - build_options.debug_info = true; + build_options.size_optimization_level = SIZE_OPTIMIZATION_NOT_SET; + build_options.debug_info = false; build_options.command = COMMAND_MISSING; build_options.symtab_size = DEFAULT_SYMTAB_SIZE; build_options.files = VECNEW(const char *, MAX_FILES); @@ -348,4 +367,9 @@ void parse_arguments(int argc, const char *argv[]) { build_options.optimization_level = OPTIMIZATION_DEFAULT; } + if (build_options.size_optimization_level == SIZE_OPTIMIZATION_NOT_SET) + { + build_options.size_optimization_level = SIZE_OPTIMIZATION_NONE; + } + } diff --git a/src/build/build_options.h b/src/build/build_options.h index ea0bb518c..8d2c89017 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -71,13 +71,21 @@ typedef enum typedef enum { - OPTIMIZATION_NOT_SET, - OPTIMIZATION_NONE, - OPTIMIZATION_LESS, - OPTIMIZATION_DEFAULT, - OPTIMIZATION_AGGRESSIVE + OPTIMIZATION_NOT_SET = -1, + OPTIMIZATION_NONE = 0, // -O0 + OPTIMIZATION_LESS = 1, // -O1 + OPTIMIZATION_DEFAULT = 2, // -O2 + OPTIMIZATION_AGGRESSIVE = 3, // -O3 } OptimizationLevel; +typedef enum +{ + SIZE_OPTIMIZATION_NOT_SET = -1, + SIZE_OPTIMIZATION_NONE = 0, // None + SIZE_OPTIMIZATION_SMALL = 1, // -Os + SIZE_OPTIMIZATION_TINY = 2, // -Oz +} SizeOptimizationLevel; + typedef struct { const char* lib_dir[MAX_LIB_DIRS]; @@ -98,7 +106,10 @@ typedef struct int clonglong_size; int clongdouble_size; OptimizationLevel optimization_level; + SizeOptimizationLevel size_optimization_level; bool debug_info; + bool emit_llvm; + bool emit_bitcode; } BuildOptions; diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 00c3fc01b..bc567f6d4 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -14,28 +14,82 @@ Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility) return decl; } -Type poisoned_type = { .type_kind = TYPE_POISONED, .resolve_status = RESOLVE_DONE }; +Type poisoned_type = { .type_kind = TYPE_POISONED }; + +TypeInfo poisoned_type_info = { .kind = TYPE_INFO_POISON }; - -Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility) +Decl *decl_new_with_type(Token name, DeclKind decl_type, Visibility visibility) { Decl *decl = decl_new(decl_type, name, visibility); - Type *type = type_new(TYPE_USER_DEFINED); - type->resolve_status = RESOLVE_DONE; + TypeKind kind = TYPE_POISONED; + switch (decl_type) + { + case DECL_FUNC: + kind = TYPE_FUNC; + break; + case DECL_UNION: + kind = TYPE_UNION; + break; + case DECL_STRUCT: + kind = TYPE_STRUCT; + break; + case DECL_ERROR: + kind = TYPE_ERROR; + break; + case DECL_ENUM: + kind = TYPE_ENUM; + break; + case DECL_TYPEDEF: + kind = TYPE_TYPEDEF; + break; + case DECL_POISONED: + case DECL_VAR: + case DECL_ENUM_CONSTANT: + case DECL_ERROR_CONSTANT: + case DECL_ARRAY_VALUE: + case DECL_IMPORT: + case DECL_MACRO: + case DECL_MULTI_DECL: + case DECL_GENERIC: + case DECL_CT_IF: + case DECL_CT_ELSE: + case DECL_CT_ELIF: + case DECL_ATTRIBUTE: + UNREACHABLE + } + Type *type = type_new(kind, name.string); type->canonical = type; type->decl = decl; - decl->self_type = type; + decl->type = type; return decl; } +const char *decl_var_to_string(VarDeclKind kind) +{ + switch (kind) + { + case VARDECL_CONST: + return "const"; + case VARDECL_GLOBAL: + return "global"; + case VARDECL_LOCAL: + return "local"; + case VARDECL_PARAM: + return "param"; + case VARDECL_MEMBER: + return "member"; + } + UNREACHABLE +} + Decl poisoned_decl = { .decl_kind = DECL_POISONED, .resolve_status = RESOLVE_DONE }; -Decl *decl_new_var(Token name, Type *type, VarDeclKind kind, Visibility visibility) +Decl *decl_new_var(Token name, TypeInfo *type, VarDeclKind kind, Visibility visibility) { Decl *decl = decl_new(DECL_VAR, name, visibility); decl->var.kind = kind; - decl->var.type = type; + decl->var.type_info = type; return decl; } @@ -218,6 +272,15 @@ void fprint_indent(FILE *file, int indent) for (int i = 0; i < indent * 2; i++) fprintf(file, " "); } +static void fprintf_indented(FILE *file, int indent, const char *string, ...) +{ + fprint_indent(file, indent); + va_list list; + va_start(list, string); + vfprintf(file, string, list); + va_end(list); +} + void fprint_endparen(FILE *file, int indent) { fprint_indent(file, indent); @@ -228,77 +291,60 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent); void fprint_type_recursive(FILE *file, Type *type, int indent) { - fprint_indent(file, indent); if (!type) { - fprintf(file, "(none)\n"); + fprintf_indented(file, indent, "(none)\n"); return; } switch (type->type_kind) { case TYPE_POISONED: - fprintf(file, "(POISON)\n"); + fprintf_indented(file, indent, "(type poison)\n"); return; case TYPE_FUNC: - fprintf(file, "(FUNC %s)\n", type->func.signature->mangled_signature); + fprintf_indented(file, indent, "(type-func %s)\n", type->func.signature->mangled_signature); + return; + case TYPE_STRUCT: + fprintf_indented(file, indent, "(struct %s::%s)\n", type->decl->module->name, type->decl->name.string); + return; + case TYPE_UNION: + fprintf_indented(file, indent, "(union %s::%s)\n", type->decl->module->name, type->decl->name.string); + return; + case TYPE_ENUM: + fprintf_indented(file, indent, "(enum %s::%s)\n", type->decl->module->name, type->decl->name.string); + return; + case TYPE_ERROR: + fprintf_indented(file, indent, "(error %s::%s)\n", type->decl->module->name, type->decl->name.string); + return; + case TYPE_TYPEDEF: + if (type->canonical != type) + { + fprintf_indented(file, indent, "(user-defined %s::%s\n", type->decl->module->name, type->decl->name.string); + fprint_type_recursive(file, type->canonical, indent + 1); + fprint_endparen(file, indent); + break; + } break; - case TYPE_USER_DEFINED: - if (type->resolve_status == RESOLVE_DONE) - { - 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 - { - if (type->unresolved.path) - { - if (type->unresolved.path->module.string) - { - fprintf(file, "(unresolved %s::%s::%s)\n", type->unresolved.path->module.string, type->unresolved.path->module.string, type->name_loc.string); - } - else - { - fprintf(file, "(unresolved %s::%s)\n", type->unresolved.path->module.string, type->name_loc.string); - } - return; - } - fprintf(file, "(unresolved %s)\n", type->name_loc.string); - return; - } case TYPE_POINTER: - fprintf(file, "(pointer\n"); - fprint_type_recursive(file, type->base, indent + 1); + fprintf_indented(file, indent, "(pointer\n"); + fprint_type_recursive(file, type->pointer, indent + 1); + fprint_endparen(file, indent); + break; + case TYPE_SUBARRAY: + fprintf_indented(file, indent, "(subarray\n"); + fprint_type_recursive(file, type->array.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); + fprintf_indented(file, indent, "(vararray\n"); + fprint_type_recursive(file, type->array.base, indent + 1); + fprint_endparen(file, indent); 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); - } + fprintf_indented(file, indent, "(array [%zu]\n", type->array.len); + fprint_type_recursive(file, type->array.base, indent + 1); + fprint_endparen(file, indent); break; - case TYPE_INC_ARRAY: - fprintf(file, "(TYPETODO)\n"); - return; case TYPE_VOID: case TYPE_BOOL: case TYPE_I8: @@ -311,20 +357,93 @@ void fprint_type_recursive(FILE *file, Type *type, int indent) case TYPE_U64: case TYPE_F32: case TYPE_F64: - fprintf(file, "(%s)\n", type->name_loc.string); - return; + fprintf_indented(file, indent, "(type %s)\n", type->name); + break; case TYPE_IXX: - fprintf(file, "(comp time int)\n"); - return; + fprintf_indented(file, indent, "(comp time int)\n"); + break; case TYPE_UXX: - fprintf(file, "(comp time uint)\n"); - return; + fprintf_indented(file, indent, "(comp time uint)\n"); + break; case TYPE_FXX: - fprintf(file, "(comp time float)\n"); - return; + fprintf_indented(file, indent, "(comp time float)\n"); + break; case TYPE_STRING: TODO } +} + +const char *resolve_status_to_string(ResolveStatus status) +{ + switch (status) + { + case RESOLVE_NOT_DONE: + return "not_done"; + case RESOLVE_DONE: + return "done"; + case RESOLVE_RUNNING: + return "running"; + default: + UNREACHABLE + } +} + +void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent) +{ + fprint_indent(file, indent); + if (!type_info) + { + fprintf(file, "(type_info missing)\n"); + return; + } + fprintf(file, "(type_info\n"); + fprint_indent(file, indent + 1); + fprintf(file, "(resolve_status %s)\n", resolve_status_to_string(type_info->resolve_status)); + if (type_info->resolve_status == RESOLVE_DONE) + { + fprint_type_recursive(file, type_info->type, indent + 1); + fprint_indent(file, indent); + fprintf(file, ")\n"); + return; + } + switch (type_info->kind) + { + case TYPE_INFO_POISON: + fprintf(file, "(POISON)\n"); + return; + case TYPE_INFO_IDENTIFIER: + if (type_info->unresolved.path) + { + if (type_info->unresolved.path->module.string) + { + fprintf(file, "(unresolved %s::%s::%s)\n", type_info->unresolved.path->module.string, type_info->unresolved.path->module.string, type_info->unresolved.name_loc.string); + } + else + { + fprintf(file, "(unresolved %s::%s)\n", type_info->unresolved.path->module.string, type_info->unresolved.name_loc.string); + } + return; + } + fprintf(file, "(unresolved %s)\n", type_info->unresolved.name_loc.string); + break; + case TYPE_INFO_ARRAY: + fprintf(file, "(unresolved-array\n"); + fprint_type_info_recursive(file, type_info->array.base, indent + 1); + fprint_expr_recursive(file, type_info->array.len, indent + 1); + break; + case TYPE_INFO_POINTER: + fprintf(file, "(pointer\n"); + fprint_type_info_recursive(file, type_info->pointer, indent + 1); + break; + case TYPE_INFO_INC_ARRAY: + fprintf(file, "(incarray\n"); + fprint_type_info_recursive(file, type_info->array.base, indent + 1); + break; + case TYPE_INFO_EXPRESSION: + fprintf(file, "(typexpr\n"); + fprint_expr_recursive(file, type_info->unresolved_type_expr, indent + 1); + break; + } fprint_endparen(file, indent); } void fprint_expr_recursive(FILE *file, Expr *expr, int indent) @@ -378,11 +497,11 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) break; case EXPR_TYPE_ACCESS: fprintf(file, "(typeaccess .%s\n", expr->type_access.name.string); - fprint_type_recursive(file, expr->type_access.type, indent + 1); + fprint_type_info_recursive(file, expr->type_access.type, indent + 1); break; case EXPR_STRUCT_VALUE: fprintf(file, "(structvalue\n"); - fprint_type_recursive(file, expr->struct_value_expr.type, indent + 1); + fprint_type_info_recursive(file, expr->struct_value_expr.type, indent + 1); fprint_expr_recursive(file, expr->struct_value_expr.init_expr, indent + 1); break; case EXPR_ACCESS: @@ -391,7 +510,7 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) break; case EXPR_TYPE: fprintf(file, "(type\n"); - fprint_type_recursive(file, expr->type_expr.type, indent + 1); + fprint_type_info_recursive(file, expr->type_expr.type, indent + 1); break; case EXPR_CALL: fprintf(file, "(call\n"); @@ -456,9 +575,13 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent); void fprint_func_signature(FILE *file, FunctionSignature *signature, int indent) { - fprint_type_recursive(file, signature->rtype, indent); - fprint_indent(file, indent); - fprintf(file, "(params\n"); + fprint_type_info_recursive(file, signature->rtype, indent); + if (!vec_size(signature->params)) + { + fprintf_indented(file, indent, "(params none)\n"); + return; + } + fprintf_indented(file, indent, "(params\n"); fprint_decl_list(file, signature->params, indent + 1); fprint_endparen(file, indent); // TODO throws, variable @@ -469,64 +592,80 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent) switch (decl->decl_kind) { case DECL_MULTI_DECL: - fprintf(file, "(multi-decl\n"); + fprintf_indented(file, indent, "(multi-decl\n"); fprint_decl_list(file, decl->multi_decl, indent + 1); + fprint_endparen(file, indent); break; case DECL_VAR: - if (!decl->var.init_expr) + fprintf(file, "(var-%s %s\n", decl_var_to_string(decl->var.kind), decl->name.string ?: ""); + fprint_type_info_recursive(file, decl->var.type_info, indent + 1); + if (decl->var.init_expr) { - fprintf(file, "(var %s)\n", decl->name.string); - return; + fprint_expr_recursive(file, decl->var.init_expr, indent + 1); } - fprintf(file, "(var %s\n", decl->name.string); - fprint_expr_recursive(file, decl->var.init_expr, indent + 1); + fprint_endparen(file, indent); break; case DECL_MACRO: - fprintf(file, "(macro %s\n", decl->name.string); - fprint_type_recursive(file, decl->macro_decl.rtype, indent + 1); + fprintf_indented(file, indent, "(macro %s\n", decl->name.string); + fprint_type_info_recursive(file, decl->macro_decl.rtype, indent + 1); fprint_indent(file, indent + 1); fprintf(file, "(params\n"); fprint_decl_list(file, decl->macro_decl.parameters, indent + 2); fprint_endparen(file, indent + 1); fprint_ast_recursive(file, decl->macro_decl.body, indent + 1); + fprint_endparen(file, indent); break; case DECL_FUNC: - fprintf(file, "(func %s\n", decl->name.string); - fprint_type_recursive(file, decl->func.type_parent, indent + 1); + fprintf_indented(file, indent, "(func %s\n", decl->name.string); + if (decl->func.type_parent) + { + fprint_indent(file, indent + 1); + fprintf(file, "(parent_type\n"); + fprint_type_info_recursive(file, decl->func.type_parent, indent + 2); + fprint_indent(file, indent + 1); + fprintf(file, ")\n"); + } fprint_func_signature(file, &decl->func.function_signature, indent + 1); fprint_ast_recursive(file, decl->func.body, indent + 1); + fprint_endparen(file, indent); break; case DECL_STRUCT: - fprintf(file, "(struct %s\n", decl->name.string); + fprintf_indented(file, indent, "(struct %s\n", decl->name.string); fprint_decl_list(file, decl->strukt.members, indent + 1); + fprint_endparen(file, indent); break; case DECL_UNION: - fprintf(file, "(union %s\n", decl->name.string); + fprintf_indented(file, indent, "(union %s\n", decl->name.string); fprint_decl_list(file, decl->strukt.members, indent + 1); + fprint_endparen(file, indent); break; case DECL_ENUM: - fprintf(file, "(enum %s\n", decl->name.string); - fprint_type_recursive(file, decl->enums.type, indent + 1); + fprintf_indented(file, indent, "(enum %s\n", decl->name.string); + fprint_type_info_recursive(file, decl->enums.type_info, indent + 1); fprint_decl_list(file, decl->enums.values, indent + 1); + fprint_endparen(file, indent); break; case DECL_ERROR: - fprintf(file, "(error %s\n", decl->name.string); + fprintf_indented(file, indent, "(error %s\n", decl->name.string); fprint_decl_list(file, decl->error.error_constants, indent + 1); + fprint_endparen(file, indent); break; case DECL_ENUM_CONSTANT: if (!decl->enum_constant.expr) { - fprintf(file, "(enum-constant %s)\n", decl->name.string); + fprintf_indented(file, indent, "(enum-constant %s)\n", decl->name.string); return; } - fprintf(file, "(enum-constant %s\n", decl->name.string); + fprintf_indented(file, indent, "(enum-constant %s\n", decl->name.string); fprint_expr_recursive(file, decl->enum_constant.expr, indent + 1); + fprint_endparen(file, indent); break; case DECL_ERROR_CONSTANT: - fprintf(file, "(error-constant %s)\n", decl->name.string); + fprintf_indented(file, indent, "(error-constant %s)\n", decl->name.string); + fprint_endparen(file, indent); return; case DECL_GENERIC: - fprintf(file, "(generic %s\n", decl->name.string); + fprintf_indented(file, indent, "(generic %s\n", decl->name.string); fprint_indent(file, indent + 1); fprintf(file, "(params\n"); { @@ -546,54 +685,59 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent) } } fprint_endparen(file, indent + 2); + fprint_endparen(file, indent); break; case DECL_TYPEDEF: - fprintf(file, "(typedef %s\n", decl->name.string); + fprintf_indented(file, indent, "(typedef %s\n", decl->name.string); if (decl->typedef_decl.is_func) { fprint_func_signature(file, &decl->typedef_decl.function_signature, indent + 1); } else { - fprint_type_recursive(file, decl->typedef_decl.type, indent + 1); + fprint_type_info_recursive(file, decl->typedef_decl.type_info, indent + 1); } + fprint_endparen(file, indent); break; case DECL_CT_IF: - fprintf(file, "(ct-if\n"); + fprintf_indented(file, indent, "(ct-if\n"); fprint_expr_recursive(file, decl->ct_if_decl.expr, indent + 1); fprint_decl_list(file, decl->ct_if_decl.then, indent + 1); if (decl->ct_if_decl.elif) { fprint_decl_recursive(file, decl->ct_if_decl.elif, indent + 1); } + fprint_endparen(file, indent); break; case DECL_CT_ELIF: - fprintf(file, "(ct-elif\n"); + fprintf_indented(file, indent, "(ct-elif\n"); fprint_expr_recursive(file, decl->ct_elif_decl.expr, indent + 1); fprint_decl_list(file, decl->ct_elif_decl.then, indent + 1); if (decl->ct_elif_decl.elif) { fprint_decl_recursive(file, decl->ct_elif_decl.elif, indent + 1); } + fprint_endparen(file, indent); break; case DECL_CT_ELSE: - fprintf(file, "(ct-else\n"); + fprintf_indented(file, indent, "(ct-else\n"); fprint_decl_list(file, decl->ct_else_decl, indent + 1); + fprint_endparen(file, indent); break; case DECL_POISONED: - fprintf(file, "(poisoned-decl)\n"); + fprintf_indented(file, indent, "(poisoned-decl)\n"); return; case DECL_ARRAY_VALUE: TODO break; case DECL_IMPORT: - fprintf(file, "(import %s", decl->name.string); + fprintf_indented(file, indent, "(import %s", decl->name.string); TODO + fprint_endparen(file, indent); break; case DECL_ATTRIBUTE: TODO } - fprint_endparen(file, indent); } static void fprint_decl_list(FILE *file, Decl **decls, int indent) @@ -742,7 +886,7 @@ static void fprint_ast_recursive(FILE *file, Ast *ast, int indent) { VECEACH(ast->generic_case_stmt.types, i) { - fprint_type_recursive(file, ast->generic_case_stmt.types[i], indent + 2); + fprint_type_info_recursive(file, ast->generic_case_stmt.types[i], indent + 2); } } fprint_endparen(file, indent + 1); diff --git a/src/compiler/casts.c b/src/compiler/casts.c index c775e5051..bc7c5f8bc 100644 --- a/src/compiler/casts.c +++ b/src/compiler/casts.c @@ -11,13 +11,13 @@ static inline void insert_cast(Expr *expr, CastKind kind, Type *canonical) { Expr *inner = malloc_arena(sizeof(Expr)); assert(expr->resolve_status == RESOLVE_DONE); - assert(expr->type->canonical); - assert(canonical->resolve_status == RESOLVE_DONE); + assert(expr->type); assert(canonical->canonical == canonical); *inner = *expr; expr->expr_kind = EXPR_CAST; expr->expr_cast.kind = kind; expr->expr_cast.expr = inner; + expr->expr_cast.type_info = NULL; expr->type = canonical; } @@ -43,12 +43,12 @@ static bool sema_type_mismatch(Expr *expr, Type *type, CastType cast_type) } -bool erro(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool erro(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { EXIT_T_MISMATCH(); } -bool ptxi(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool ptxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -63,7 +63,7 @@ bool ptxi(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool ptbo(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool ptbo(Expr* left, Type *ignored, Type *canonical, Type *type, CastType cast_type) { if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -84,16 +84,55 @@ static inline bool may_implicitly_cast_ptr_to_ptr(Type *current_type, Type *targ assert(target_type->canonical == target_type); // Neither is void* or have matching bases: - if (target_type->base != type_void && current_type->base != type_void && target_type->base != current_type->base) return false; + if (target_type->pointer != type_void && current_type->pointer != type_void && target_type->pointer != current_type->pointer) return false; return true; } -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)) +bool ptfu(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool fupt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool stst(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool unst(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool stun(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool unun(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool arpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool arsa(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool ptpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) +{ + if (cast_type != CAST_TYPE_EXPLICIT && !may_implicitly_cast_ptr_to_ptr(from_canonical, canonical)) { return sema_type_mismatch(left, type, cast_type); } @@ -107,9 +146,16 @@ bool ptpt(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool stpt(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool strpt(Expr* left, Type *from_canonical, Type *canonical, Type *type, CastType cast_type) { - if (canonical->base != type_char && canonical->base != type_byte) + // TODO + insert_cast(left, CAST_PTRPTR, canonical); + return true; +} + +bool stpt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +{ + if (canonical->pointer != type_char && canonical->pointer != type_byte) { return sema_type_mismatch(left, type, cast_type); } @@ -118,13 +164,13 @@ bool stpt(Expr* left, Type *canonical, Type *type, CastType cast_type) } -bool boxi(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool boxi(Expr* left, Type *from, 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.type = CONST_INT; left->const_expr.i = left->const_expr.b ? 1 : 0; left->type = type; return true; @@ -133,7 +179,7 @@ bool boxi(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool bofp(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool bofp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -148,7 +194,7 @@ bool bofp(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool xibo(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool xibo(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -163,7 +209,7 @@ bool xibo(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool fpbo(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool fpbo(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (cast_type >= CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -179,10 +225,9 @@ bool fpbo(Expr* left, Type *canonical, Type *type, CastType cast_type) } -bool fpfp(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool fpfp(Expr* left, Type *from, 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; + bool is_narrowing = from->builtin.bytesize < canonical->builtin.bytesize && from->type_kind != TYPE_FXX; // Is this correct? TODO if (is_narrowing && cast_type == CAST_TYPE_IMPLICIT_ASSIGN) EXIT_T_MISMATCH(); @@ -201,7 +246,7 @@ bool fpfp(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool fpui(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool fpui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -216,7 +261,7 @@ bool fpui(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool fpsi(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool fpsi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { if (cast_type != CAST_TYPE_EXPLICIT) EXIT_T_MISMATCH(); if (left->expr_kind == EXPR_CONST) @@ -236,21 +281,20 @@ 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) +bool sisi(Expr* left, Type *from, 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_IXX; + bool is_narrowing = from->builtin.bytesize > canonical->builtin.bytesize && from->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 (from->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); + SEMA_ERROR(left->loc, "'%lld' does not fit into '%s'", i, canonical->name); return false; } } @@ -268,16 +312,14 @@ bool sisi(Expr* left, Type *canonical, Type *type, CastType cast_type) left->type = type; return true; } - assert(left_canonical->type_kind != TYPE_IXX); + assert(from->type_kind != TYPE_IXX); insert_cast(left, CAST_SISI, canonical); return true; } -bool siui(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool siui(Expr* left, Type *from, 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; + bool is_narrowing = from->builtin.bytesize < canonical->builtin.bytesize && from->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) { @@ -291,7 +333,7 @@ bool siui(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool xiptr(Expr* left, Type *canonical, Type *type) +bool xiptr(Expr* left, Type *from, Type *canonical, Type *type) { if (left->expr_kind == EXPR_CONST) { @@ -306,7 +348,7 @@ bool xiptr(Expr* left, Type *canonical, Type *type) return true; } -bool sifp(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool sifp(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { // TODO if (left->expr_kind == EXPR_CONST) @@ -330,14 +372,14 @@ bool sifp(Expr* left, Type *canonical, Type *type, CastType cast_type) } -bool uisi(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool uisi(Expr* left, Type *from, 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 (cast_type != CAST_TYPE_EXPLICIT && from->type_kind == TYPE_UXX) { if (left->const_expr.i > (uint64_t)int_type_max[index]) { @@ -360,14 +402,14 @@ bool uisi(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool uiui(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool uiui(Expr* left, Type *from, 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(left->const_expr.type == CONST_INT && type_is_unsigned(from)); 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 (cast_type != CAST_TYPE_EXPLICIT && from->type_kind == TYPE_UXX) { if (left->const_expr.i > uint_type_max[index]) { @@ -384,12 +426,12 @@ bool uiui(Expr* left, Type *canonical, Type *type, CastType cast_type) } -bool uifp(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool uifp(Expr* left, Type *from, 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(left->const_expr.type == CONST_INT && type_is_unsigned(from)); assert(canonical->type_kind >= TYPE_F32 && canonical->type_kind <= TYPE_F64); left->const_expr.f = left->const_expr.i; left->type = type; @@ -399,15 +441,14 @@ bool uifp(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool ussi(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool ussi(Expr* left, Type *from, 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 (type->type_kind != TYPE_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) { + // TODO Expr *value = left->identifier_expr.decl->enum_constant.expr; assert(value->expr_kind == EXPR_CONST); assert(value->const_expr.type == CONST_INT); @@ -418,31 +459,30 @@ bool ussi(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool sius(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool sius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool uius(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool uius(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool xipt(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool xipt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool usus(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool usus(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { - Type *left_canonical = left->type->canonical; assert(canonical->canonical == canonical); assert(canonical->type_kind == TYPE_POINTER); - assert(left_canonical->type_kind == TYPE_POINTER); + assert(from->type_kind == TYPE_POINTER); if (cast_type != CAST_TYPE_EXPLICIT) { - if (type_is_subtype(left_canonical->base, canonical->base)) + if (type_is_subtype(from->pointer, canonical->pointer)) { insert_cast(left, CAST_PTRPTR, canonical); return true; @@ -454,46 +494,136 @@ bool usus(Expr* left, Type *canonical, Type *type, CastType cast_type) return true; } -bool usui(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool enxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} +bool erxi(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool ptva(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool vava(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -bool usbo(Expr* left, Type *canonical, Type *type, CastType cast_type) +bool sapt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) { TODO } -CastFunc BUILTIN_CONVERSION[19][19] = { -//to bool, char, short, int, long, ctint, byte, ushort, uint, ulong,ctuint, float,double,ctreal, user, ptr, str, arr, varr // from: - { &erro, &boxi, &boxi, &boxi, &boxi, &erro, &boxi, &boxi, &boxi, &boxi, &erro, &bofp, &bofp, &erro, &erro, &erro, &erro, &erro, &erro }, // bool - { &xibo, &erro, &sisi, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &erro, &erro, &erro, &erro }, // char - { &xibo, &sisi, &erro, &sisi, &sisi, &erro, &siui, &siui, &siui, &siui, &erro, &sifp, &sifp, &erro, &sius, &erro, &erro, &erro, &erro }, // short - { &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, &sifp, &sius, &xipt, &erro, &erro, &erro }, // ixx - { &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, &uifp, &uius, &xipt, &erro, &erro, &erro }, // uxx - { &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 }, // fxx - { &usbo, &ussi, &ussi, &ussi, &ussi, &erro, &usui, &usui, &usui, &usui, &erro, &erro, &erro, &erro, &usus, &erro, &erro, &erro, &erro }, // user - { &ptbo, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &ptxi, &ptxi, &ptxi, &ptxi, &erro, &erro, &erro, &erro, &erro, &ptpt, &erro, &erro, &ptva }, // ptr - { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &stpt, &erro, &erro, &erro }, // str - { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro }, // arr - { &fpbo, &fpsi, &fpsi, &fpsi, &fpsi, &erro, &fpui, &fpui, &fpui, &fpui, &erro, &fpfp, &erro, &erro, &erro, &erro, &erro, &erro, &erro }, // varr -}; +bool vasa(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} -Type t_cpy = { .name_loc.string = "cpy" }; -Type t_err = { .name_loc.string = "err" }; +bool usui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool ptva(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool usbo(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +bool vapt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type) +{ + TODO +} + +CastFunc conversion(TypeKind from, Type *to) +{ + switch (from) + { + case TYPE_POISONED: + return &erro; + case TYPE_VOID: + return &erro; + case TYPE_BOOL: + if (type_is_integer(to)) return &boxi; + if (type_is_float(to)) return &bofp; + return &erro; + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_IXX: + if (type_is_unsigned_integer(to)) return &siui; + if (type_is_signed_integer(to)) return &sisi; + if (type_is_float(to)) return &sifp; + if (to->type_kind == TYPE_POINTER) return &ptxi; + return &erro; + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_UXX: + if (type_is_unsigned_integer(to)) return &uiui; + if (type_is_signed_integer(to)) return &uisi; + if (type_is_float(to)) return &uifp; + if (to->type_kind == TYPE_POINTER) return &ptxi; + return &erro; + case TYPE_F32: + case TYPE_F64: + case TYPE_FXX: + if (type_is_unsigned_integer(to)) return &fpui; + if (type_is_signed_integer(to)) return &fpsi; + if (type_is_float(to)) return &fpfp; + return &erro; + case TYPE_POINTER: + if (type_is_integer(to)) return &ptxi; + if (to->type_kind == TYPE_BOOL) return &ptbo; + if (to->type_kind == TYPE_POINTER) return &ptpt; + if (to->type_kind == TYPE_FUNC) return &ptfu; + if (to->type_kind == TYPE_VARARRAY) return &ptva; + return &erro; + case TYPE_ENUM: + if (type_is_integer(to)) return &enxi; + return &erro; + case TYPE_ERROR: + if (type_is_integer(to)) return &erxi; + return &erro; + case TYPE_FUNC: + if (type_is_integer(to)) return &ptxi; + if (to->type_kind == TYPE_POINTER) return &fupt; + return &erro; + case TYPE_STRUCT: + if (to->type_kind == TYPE_STRUCT) return &stst; + if (to->type_kind == TYPE_UNION) return &stun; + return &erro; + case TYPE_UNION: + if (to->type_kind == TYPE_STRUCT) return &unst; + if (to->type_kind == TYPE_UNION) return &unun; + return &erro; + case TYPE_TYPEDEF: + UNREACHABLE + case TYPE_STRING: + if (to->type_kind == TYPE_POINTER) return &strpt; + return &erro; + case TYPE_ARRAY: + return &erro; + case TYPE_VARARRAY: + if (to->type_kind == TYPE_SUBARRAY) return &vasa; + if (to->type_kind == TYPE_VARARRAY) return &vava; + if (to->type_kind == TYPE_POINTER) return &vapt; + return &erro; + case TYPE_SUBARRAY: + if (to->type_kind == TYPE_POINTER) return &sapt; + // if (to->type_kind == ) + return &erro; + } + UNREACHABLE +} + +Type t_cpy = { .name = "cpy" }; +Type t_err = { .name = "err" }; Type *ARITHMETIC_PROMOTION[19][19] = { //other bool, char, short, int, long, ctint, byte, ushort, int, ulong, ctuint, float, double, ctreal, user, ptr, str, arr, varr // from: @@ -520,7 +650,7 @@ Type *ARITHMETIC_PROMOTION[19][19] = { static inline bool cannot_convert(TypeKind type_kind) { - return type_kind <= TYPE_VOID || type_kind >= TYPE_INC_ARRAY; + return type_kind <= TYPE_VOID || type_kind > TYPE_ARRAY; } bool cast_arithmetic(Expr *expr, Expr *other, const char *action) @@ -568,6 +698,6 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type) sema_type_mismatch(expr, to_type, cast_type); return false; } - CastFunc func = BUILTIN_CONVERSION[from_type->type_kind - TYPE_BOOL][to_type->type_kind - TYPE_BOOL]; - return func(expr, canonical, to_type, cast_type); + CastFunc func = conversion(from_type->type_kind, canonical); + return func(expr, from_type, canonical, to_type, cast_type); } diff --git a/src/compiler/codegen.c b/src/compiler/codegen.c deleted file mode 100644 index d85ac4280..000000000 --- a/src/compiler/codegen.c +++ /dev/null @@ -1,1020 +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 "compiler_internal.h" - - -#define PRINTF(...) fprintf(context->codegen_output, __VA_ARGS__) -#define PRINTTYPE(_t) print_typename(context->codegen_output, _t) -#define INDENT() indent_line(context, indent) - -static void codegen_ast(Context *context, Ast *ast, int indent); -static int codegen_emit_expr(Context *context, Expr *expr, 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, "uint32_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_FUNC: - fprintf(file, "%s", type->name_loc.string); - break; - case TYPE_EXPRESSION: - UNREACHABLE - } -} - -static void indent_line(Context *context, int indent) -{ - for (int i = 0; i < indent; i++) - { - PRINTF(" "); - } -} - -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 int codegen_emit_call_expr(Context *context, Expr *expr, int indent) -{ - // TODO properly - int *params = NULL; - VECEACH(expr->call_expr.arguments, i) - { - vec_add(params, codegen_emit_expr(context, expr->call_expr.arguments[i], indent)); - } - INDENT(); - bool has_return = expr->type->type_kind != TYPE_VOID; - if (has_return) PRINTTYPE(expr->type); - if (expr->call_expr.function->expr_kind == EXPR_IDENTIFIER) - { - Decl *func = expr->call_expr.function->identifier_expr.decl; - if (has_return) PRINTF(" _%d = ", ++context->unique_index); - if (strcmp(func->name.string, "printf") == 0) - { - PRINTF("%s", func->name.string); - } - else - { - PRINTF("%s__%s", func->module->name, func->name.string); - } - } - else - { - TODO - } - PRINTF("("); - VECEACH(params, i) - { - if (i != 0) PRINTF(", "); - PRINTF("_%d", params[i]); - } - PRINTF(");\n"); - return context->unique_index; -} - -static inline int codegen_emit_identifier_expr(Context *context, Expr *expr, int indent) -{ - // TODO properly - INDENT(); - PRINTTYPE(expr->type); - Decl *decl = expr->identifier_expr.decl; - PRINTF(" _%d = _%d_%s;\n", ++context->unique_index, decl->var.id, decl->name.string); - return context->unique_index; -} - -static inline void codegen_emit_const_expr_raw(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_FUNC: - TODO - break; - case TYPE_BOOL: - assert(expr->const_expr.type == CONST_BOOL); - PRINTF(expr->const_expr.b ? "true" : "false"); - return; - case TYPE_I8: - case TYPE_I16: - case TYPE_I32: - case TYPE_I64: - case TYPE_IXX: - assert(expr->const_expr.type == CONST_INT); - PRINTF("("); - PRINTTYPE(canonical); - PRINTF(")"); - PRINTF("%lld", (long long)expr->const_expr.i); - return; - case TYPE_U8: - case TYPE_U16: - case TYPE_U32: - case TYPE_U64: - case TYPE_UXX: - assert(expr->const_expr.type == CONST_INT); - PRINTF("("); - PRINTTYPE(canonical); - PRINTF(")"); - PRINTF("%llu", (long long)expr->const_expr.i); - return; - case TYPE_F32: - case TYPE_F64: - case TYPE_FXX: - assert(expr->const_expr.type == CONST_FLOAT); - PRINTF("("); - PRINTTYPE(canonical); - PRINTF(")"); - PRINTF("%Lf", expr->const_expr.f); - return; - case TYPE_POINTER: - if (expr->const_expr.type == CONST_NIL) - { - PRINTF("(("); - PRINTTYPE(canonical); - PRINTF(")0)"); - } - else - { - assert(expr->const_expr.type == CONST_STRING); - PRINTF("(("); - PRINTTYPE(canonical); - - PRINTF(")%.*s)", expr->const_expr.string.len, expr->const_expr.string.chars); - } - return; - case TYPE_STRING: - TODO - case TYPE_ARRAY: - case TYPE_VARARRAY: - case TYPE_INC_ARRAY: - case TYPE_EXPRESSION: - UNREACHABLE - } -} - -static inline int codegen_emit_const_expr(Context *context, Expr *expr, int indent) -{ - assert(expr->expr_kind == EXPR_CONST); - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = ", ++context->unique_index); - codegen_emit_const_expr_raw(context, expr); - PRINTF(";\n"); - return context->unique_index; -} - -static inline int codegen_emit_cast_expr(Context *context, Expr *expr, int indent) -{ - int index = codegen_emit_expr(context, expr->expr_cast.expr, indent); - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = (", ++context->unique_index); - PRINTTYPE(expr->type); - PRINTF(") _%d;\n", index); - return context->unique_index; -} - -static int codegen_emit_simple_binary_expr(Context *context, Expr *expr, int indent) -{ - int l_index = codegen_emit_expr(context, expr->binary_expr.left, indent); - int r_index = codegen_emit_expr(context, expr->binary_expr.right, indent); - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = _%d %s _%d;\n", ++context->unique_index, l_index, token_type_to_string(expr->binary_expr.operator), r_index); - return context->unique_index; -} - -static int codegen_emit_assign_expr(Context *context, Expr *expr, int indent) -{ - Expr *left = expr->binary_expr.left; - Expr *right = expr->binary_expr.right; - int index = codegen_emit_expr(context, right, indent); - if (expr->binary_expr.left->expr_kind == EXPR_IDENTIFIER) - { - INDENT(); - PRINTF("_%d_%s = _%d;\n", left->identifier_expr.decl->var.id, left->identifier_expr.identifier.string, index); - return index; - } - else - { - TODO - } -} - -static int codegen_emit_binary_expr(Context *context, Expr *expr, int indent) -{ - switch (expr->binary_expr.operator) - { - case TOKEN_EQ: - return codegen_emit_assign_expr(context, expr, indent); - case TOKEN_PLUS: - case TOKEN_MINUS: - case TOKEN_GREATER: - case TOKEN_GREATER_EQ: - case TOKEN_LESS_EQ: - case TOKEN_LESS: - case TOKEN_EQEQ: - case TOKEN_NOT_EQUAL: - case TOKEN_MOD: - case TOKEN_DIV: - case TOKEN_AND: - case TOKEN_OR: - case TOKEN_STAR: - case TOKEN_BIT_OR: - case TOKEN_AMP: - case TOKEN_BIT_XOR: - case TOKEN_SHL: - case TOKEN_SHR: - return codegen_emit_simple_binary_expr(context, expr, indent); - case TOKEN_MULT_ASSIGN: - case TOKEN_DIV_ASSIGN: - case TOKEN_MINUS_ASSIGN: - case TOKEN_PLUS_ASSIGN: - case TOKEN_MOD_ASSIGN: - case TOKEN_AND_ASSIGN: - case TOKEN_OR_ASSIGN: - case TOKEN_SHR_ASSIGN: - case TOKEN_SHL_ASSIGN: - case TOKEN_BIT_XOR_ASSIGN: - case TOKEN_BIT_OR_ASSIGN: - case TOKEN_BIT_AND_ASSIGN: - case TOKEN_ELVIS: - UNREACHABLE - default: - UNREACHABLE - } -} - -static int codegen_emit_post_unary_expr(Context *context, Expr *expr, int indent) -{ - int index = ++context->unique_index; - int index2; - Expr *inner = expr->post_expr.expr; - switch (expr->post_expr.operator) - { - case TOKEN_PLUSPLUS: - case TOKEN_MINUSMINUS: - INDENT(); - PRINTTYPE(expr->type); - if (inner->expr_kind == EXPR_IDENTIFIER) - { - - PRINTF(" _%d = _%d_%s%s;\n", index, inner->identifier_expr.decl->var.id, inner->identifier_expr.decl->name.string, token_type_to_string(expr->post_expr.operator)); - return index; - } - else - { - assert(inner->expr_kind == EXPR_UNARY && inner->unary_expr.operator == TOKEN_STAR); - index2 = codegen_emit_expr(context, inner->unary_expr.expr, indent); - PRINTF(" _%d = (*_%d)%s;\n", index, index2, token_type_to_string(expr->post_expr.operator)); - return index; - } - default: - UNREACHABLE - } -} - -static int codegen_emit_initializer_list(Context *context, Expr *expr, int indent) -{ - int index = ++context->unique_index; - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d;\n", index); - Decl *decl = expr->type->canonical->decl; - // Todo, fully clear. - VECEACH(expr->initializer_expr, i) - { - int index2 = codegen_emit_expr(context, expr->initializer_expr[i], indent); - INDENT(); - PRINTF("_%d.%s = _%d;\n", index, decl->strukt.members[i]->name.string, index2); - } - return index; -} - -static int codegen_emit_access(Context *context, Expr *expr, int indent) -{ - int left = codegen_emit_expr(context, expr->access_expr.parent, indent); - int index = ++context->unique_index; - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = _%d.%s;\n", index, left, expr->access_expr.sub_element.string); - return index; -} - -static int codegen_emit_unary_expr(Context *context, Expr *expr, int indent) -{ - int index = ++context->unique_index; - int index2; - Expr *inner = expr->unary_expr.expr; - switch (expr->unary_expr.operator) - { - case TOKEN_MINUS: - case TOKEN_NOT: - index2 = codegen_emit_expr(context, inner, indent); - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = %s_%d;\n", index, token_type_to_string(expr->unary_expr.operator), index2); - return index; - case TOKEN_BIT_NOT: - index2 = codegen_emit_expr(context, inner, indent); - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = (", index); - PRINTTYPE(expr->type); - PRINTF(")~(("); - PRINTTYPE(type_unsigned_int_by_size(inner->type->canonical->builtin.bytesize)); - PRINTF(")_%d);\n", index2); - return index; - case TOKEN_PLUSPLUS: - case TOKEN_MINUSMINUS: - case TOKEN_STAR: - if (inner->expr_kind == EXPR_IDENTIFIER) - { - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = %s_%d_%s;\n", index, token_type_to_string(expr->post_expr.operator), inner->identifier_expr.decl->var.id, inner->identifier_expr.decl->name.string); - return index; - } - else - { - index2 = codegen_emit_expr(context, inner->unary_expr.expr, indent); - INDENT(); - PRINTTYPE(expr->type); - PRINTF(" _%d = %s_%d;\n", index, token_type_to_string(expr->post_expr.operator), index2); - return index; - } - case TOKEN_AMP: - INDENT(); - PRINTTYPE(expr->type); - assert(inner->expr_kind == EXPR_IDENTIFIER); - PRINTF(" _%d = &_%d_%s;\n", index, inner->identifier_expr.decl->var.id, inner->identifier_expr.decl->name.string); - return index; - default: - UNREACHABLE - } -} - -static int codegen_emit_expr(Context *context, Expr *expr, int indent) -{ - switch (expr->expr_kind) - { - case EXPR_CONST: - return codegen_emit_const_expr(context, expr, indent); - case EXPR_CALL: - return codegen_emit_call_expr(context, expr, indent); - case EXPR_IDENTIFIER: - return codegen_emit_identifier_expr(context, expr, indent); - case EXPR_CAST: - return codegen_emit_cast_expr(context, expr, indent); - case EXPR_BINARY: - return codegen_emit_binary_expr(context, expr, indent); - case EXPR_POST_UNARY: - return codegen_emit_post_unary_expr(context, expr, indent); - case EXPR_UNARY: - return codegen_emit_unary_expr(context, expr, indent); - case EXPR_INITIALIZER_LIST: - return codegen_emit_initializer_list(context, expr, indent); - case EXPR_ACCESS: - return codegen_emit_access(context, expr, indent); - default: - TODO - } -} - -static inline int codegen_var_decl(Context *context, Decl *decl, int indent) -{ - assert(decl->decl_kind == DECL_VAR); - if (!decl->var.init_expr) return -1; - int index = codegen_emit_expr(context, decl->var.init_expr, indent); - INDENT(); - PRINTF("_%d_%s = _%d;\n", decl->var.id, decl->name.string, index); - return index; -} - - -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 inline void codegen_emit_goto_stmt(Context *context, Ast *ast, int indent) -{ - INDENT(); - PRINTF("goto _L_%s;\n", ast->token.string); -} - -static inline void codegen_emit_label_smt(Context *context, Ast *ast, int indent) -{ - PRINTF("_L_%s:;\n", ast->token.string); -} - -static inline void codegen_emit_for_stmt(Context *context, Ast *ast, int indent) -{ - INDENT(); - int loop = ++context->unique_index; - PRINTF("// --- Begin for id:%d ---\n", loop); - Ast **stmts = ast->for_stmt.cond->cond_stmt.stmts; - if (stmts) - { - INDENT(); - PRINTF("// --- Prelude ---\n"); - VECEACH(stmts, i) - { - codegen_ast(context, stmts[i], indent); - } - } - INDENT(); - PRINTF("// --- Loop condition ---\n"); - INDENT(); - PRINTF("_FOR_%d:;\n", loop); - if (ast->for_stmt.cond->cond_stmt.expr) - { - int res = codegen_emit_expr(context, ast->for_stmt.cond->cond_stmt.expr, indent); - INDENT(); - PRINTF("if (!_%i) goto _FOR_EXIT_%d;\n", res, loop); - } - INDENT(); - PRINTF("// --- Body ---\n"); - codegen_ast(context, ast->for_stmt.body, indent); - INDENT(); - PRINTF("// --- End ---\n"); - INDENT(); - PRINTF("goto _FOR_%d;\n", loop); - INDENT(); - PRINTF("_FOR_EXIT_%d:;\n", loop); - INDENT(); - PRINTF("// --- End for id:%d --- \n", loop); -} - - -static inline void codegen_emit_do_stmt(Context *context, Ast *ast, int indent) -{ - INDENT(); - int loop = ++context->unique_index; - PRINTF("// --- Begin do id:%d ---\n", loop); - INDENT(); - PRINTF("_DO_%d_BEGIN:;\n", loop); - INDENT(); - PRINTF("// --- Body ---\n"); - codegen_ast(context, ast->do_stmt.body, indent); - INDENT(); - PRINTF("// --- End ---\n"); - INDENT(); - PRINTF("_DO_%d_CONTINUE:;\n", loop); - INDENT(); - PRINTF("// --- Loop condition ---\n"); - int res = codegen_emit_expr(context, ast->do_stmt.expr, indent); - INDENT(); - PRINTF("if (_%i) goto _DO_%d_BEGIN;\n", res, loop); - INDENT(); - PRINTF("_DO_%d_EXIT:;\n", loop); - INDENT(); - PRINTF("// --- End do id:%d --- \n", loop); -} - -static inline void codegen_emit_if_stmt(Context *context, Ast *ast, int indent) -{ - INDENT(); - PRINTF("// --- Begin if ---\n"); - Ast **stmts = ast->if_stmt.cond->cond_stmt.stmts; - if (stmts) - { - INDENT(); - PRINTF("// --- Prelude ---\n"); - VECEACH(stmts, i) - { - codegen_ast(context, stmts[i], indent); - } - } - int res = codegen_emit_expr(context, ast->if_stmt.cond->cond_stmt.expr, indent); - INDENT(); - PRINTF("if (!_%i)\n", res); - if (ast->if_stmt.then_body->ast_kind == AST_COMPOUND_STMT) - { - codegen_ast(context, ast->if_stmt.then_body, indent + 0); - } - else - { - INDENT(); - PRINTF("{\n"); - codegen_ast(context, ast->if_stmt.then_body, indent + 1); - INDENT(); - PRINTF("}\n"); - } - if (ast->if_stmt.else_body) - { - INDENT(); - PRINTF("else\n"); - codegen_ast(context, ast->if_stmt.else_body, indent); - } - INDENT(); - PRINTF("// --- End for if --- \n"); -} - -static inline void codegen_emit_stmt_list(Context *context, Ast *ast, int indent) -{ - VECEACH(ast->stmt_list, i) - { - codegen_ast(context, ast->stmt_list[i], indent); - } -} - -static void codegen_emit_switch_stmt(Context *context, Ast *ast, int indent) -{ - Ast *cond = ast->switch_stmt.cond; - VECEACH(cond->cond_stmt.stmts, i) - { - codegen_ast(context, cond->cond_stmt.stmts[i], indent); - } - int expr = codegen_emit_expr(context, cond->cond_stmt.expr, indent); - INDENT(); - PRINTF("switch(_%d)\n", expr); - INDENT(); - PRINTF("{\n"); - indent++; - VECEACH(ast->switch_stmt.cases, i) - { - Ast *the_case = ast->switch_stmt.cases[i]; - assert(the_case->ast_kind == AST_CASE_STMT); - INDENT(); - switch (the_case->case_stmt.value_type) - { - case CASE_VALUE_INT: - PRINTF("case %lld:;\n", (int64_t) the_case->case_stmt.val); - break; - case CASE_VALUE_UINT: - PRINTF("case %llu:;\n", (int64_t) the_case->case_stmt.val); - break; - case CASE_VALUE_DEFAULT: - PRINTF("default:;\n"); - break; - } - indent++; - bool ends_with_next = false; - Ast *block = the_case->case_stmt.block; - if (block) - { - if (VECLAST(block->compound_stmt.stmts)->ast_kind == AST_NEXT_STMT) - { - ends_with_next = true; - vec_pop(block->compound_stmt.stmts); - } - codegen_ast(context, block, indent); - } - if (!ends_with_next) - { - INDENT(); - PRINTF("break;\n"); - if (the_case->case_stmt.has_next) - { - INDENT(); - PRINTF("_EXIT_%zx:;\n", (size_t)the_case); - } - } - indent--; - } - indent--; - INDENT(); - PRINTF("}\n"); -} - - -static void codegen_emit_break_stmt(Context *context, Ast *ast, int indent) -{ - INDENT(); - PRINTF("break;\n"); -} - -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_BREAK_STMT: - codegen_emit_break_stmt(context, ast, indent); - return; - case AST_CASE_STMT: - case AST_CATCH_STMT: - case AST_DEFAULT_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_DECLARE_STMT: - codegen_declare_stmt(context, ast, indent); - return; - case AST_DEFER_STMT: - return; - case AST_DO_STMT: - codegen_emit_do_stmt(context, ast, indent); - return; - case AST_IF_STMT: - codegen_emit_if_stmt(context, ast, indent); - return; - case AST_EXPR_STMT: - codegen_emit_expr(context, ast->expr_stmt, indent); - return; - case AST_FOR_STMT: - codegen_emit_for_stmt(context, ast, indent); - return; - case AST_GOTO_STMT: - codegen_emit_goto_stmt(context, ast, indent); - return; - case AST_LABEL: - codegen_emit_label_smt(context, ast, indent); - return; - case AST_NOP_STMT: - INDENT(); - PRINTF("// NOP"); - return; - case AST_SWITCH_STMT: - codegen_emit_switch_stmt(context, ast, indent); - return; - case AST_RETURN_STMT: - if (ast->return_stmt.expr) - { - int index = codegen_emit_expr(context, ast->return_stmt.expr, indent); - INDENT(); - PRINTF("return _%d", index); - PRINTF(";\n"); - } - else - { - INDENT(); - PRINTF("return;\n"); - } - return; - case AST_THROW_STMT: - break; - case AST_TRY_STMT: - break; - case AST_NEXT_STMT: - INDENT(); - PRINTF("goto _EXIT_%zx;\n", (size_t)ast->next_stmt); - return; - case AST_VOLATILE_STMT: - break; - case AST_STMT_LIST: - codegen_emit_stmt_list(context, ast, indent); - return; - case AST_CT_SWITCH_STMT: - case AST_CT_DEFAULT_STMT: - case AST_CT_IF_STMT: - case AST_CT_ELIF_STMT: - case AST_CT_ELSE_STMT: - case AST_CT_CASE_STMT: - case AST_ATTRIBUTE: - case AST_CT_FOR_STMT: - case AST_GENERIC_CASE_STMT: - case AST_GENERIC_DEFAULT_STMT: - case AST_WHILE_STMT: - UNREACHABLE - } - TODO -} - -static inline void codegen_func_decl(Context *context, Decl *decl) -{ - if (strcmp("main", decl->name.string) == 0) - { - // TODO - PRINTF("int main()"); - return; - } - if (decl->visibility != VISIBLE_PUBLIC) - { - PRINTF("static "); - } - print_typename(context->codegen_output, decl->func.function_signature.rtype); - if (strcmp("main", decl->name.string) == 0) - { - PRINTF(" %s(", decl->name.string); - } - else - { - PRINTF(" %s__%s(", decl->module->name, decl->name.string); - } - Decl **params = decl->func.function_signature.params; - VECEACH(params, i) - { - if (i != 0) PRINTF(", "); - Decl *param = params[i]; - PRINTTYPE(param->var.type); - PRINTF(" _%d_%s", param->var.id, param->name.string); - } - PRINTF(")"); -} - -static inline void codegen_func(Context *context, Decl *decl) -{ - codegen_func_decl(context, decl); - Ast *const body = decl->func.body; - assert(body->ast_kind == AST_COMPOUND_STMT); - PRINTF("\n{\n"); - Decl **const vars = decl->func.annotations->vars; - Type *type = NULL; - VECEACH(vars, i) - { - Decl *var = vars[i]; - assert(var->decl_kind == DECL_VAR); - if (var->var.kind == VARDECL_PARAM) continue; - Type *current = var->var.type->canonical; - if (type == current) - { - PRINTF(", "); - } - else - { - if (type) PRINTF(";\n"); - indent_line(context, 1); - print_typename(context->codegen_output, var->var.type); - PRINTF(" "); - } - type = current; - PRINTF("_%u_%s", var->var.id, var->name.string); - } - if (type) PRINTF(";\n"); - VECEACH(body->compound_stmt.stmts, i) - { - codegen_ast(context, body->compound_stmt.stmts[i], 1); - } - PRINTF("}\n"); -} - -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_top_level_func(Context *context, Decl *decl) -{ - codegen_func_decl(context, decl); - PRINTF(";\n"); -} - -static inline void codegen_top_level_struct_union(Context *context, Decl *decl) -{ - const char* type = decl->decl_kind == DECL_UNION ? "union" : "struct"; - PRINTF("typedef %s _%s_%s %s_%s;\n", type, decl->module->name, decl->name.string, decl->module->name, decl->name.string); -} - -static inline void codegen_top_level_decl_header(Context *context, Decl *decl) -{ - switch (decl->decl_kind) - { - case DECL_POISONED: - FATAL_ERROR("Tried to codegen broken code"); - return; - case DECL_FUNC: - codegen_top_level_func(context, decl); - return; - case DECL_VAR: - if (decl->visibility != VISIBLE_PUBLIC) PRINTF("static "); - PRINTTYPE(decl->var.type); - PRINTF(" %s", decl->name.string); - if (decl->var.init_expr) - { - PRINTF(" = "); - codegen_emit_const_expr_raw(context, decl->var.init_expr); - } - PRINTF(";\n"); - return; - case DECL_TYPEDEF: - TODO - case DECL_STRUCT: - case DECL_UNION: - codegen_top_level_struct_union(context, decl); - return; - case DECL_ENUM: - TODO - // codegen_top_level_enum(context, decl); - return; - case DECL_ERROR: - TODO - case DECL_MULTI_DECL: - TODO - break; - case DECL_CT_IF: - case DECL_CT_ELSE: - case DECL_CT_ELIF: - case DECL_ENUM_CONSTANT: - case DECL_ARRAY_VALUE: - case DECL_IMPORT: - case DECL_ERROR_CONSTANT: - UNREACHABLE - case DECL_MACRO: - case DECL_GENERIC: - case DECL_ATTRIBUTE: - break; - } - TODO - -} - -static inline void codegen_top_level_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: - return; - 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; - return; - case DECL_MULTI_DECL: - break; - case DECL_CT_IF: - case DECL_CT_ELSE: - case DECL_CT_ELIF: - UNREACHABLE - case DECL_MACRO: - case DECL_GENERIC: - case DECL_ATTRIBUTE: - break; - } - TODO -} -void codegen(Context *context) -{ - VECEACH(context->header_declarations, i) - { - codegen_top_level_decl_header(context, context->header_declarations[i]); - } - VECEACH(context->header_declarations, i) - { - codegen_top_level_decl(context, context->header_declarations[i]); - } - VECEACH(context->vars, i) - { - codegen_top_level_decl(context, context->vars[i]); - } - - - -} \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 56f23e392..841c02033 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -120,6 +120,12 @@ Decl *compiler_find_symbol(Token token) return stable_get(&compiler.global_symbols, token.string); } +void compiler_add_type(Type *type) +{ + DEBUG_LOG("Created type %s.", type->name); + assert(type_ok(type)); + VECADD(compiler.type, type); +} Module *compiler_find_or_create_module(const char *module_name) { Module *module = stable_get(&compiler.modules, module_name); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 7f389a3a5..3043b72ae 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -19,11 +19,12 @@ typedef uint32_t SourceLoc; typedef struct _Ast Ast; typedef struct _Decl Decl; -typedef struct _Type Type; +typedef struct _TypeInfo TypeInfo; typedef struct _Expr Expr; typedef struct _Module Module; +typedef struct _Type Type; -typedef bool(*CastFunc)(Expr*, Type*, Type*, CastType cast_type); +typedef bool(*CastFunc)(Expr *, Type *, Type *, Type *, CastType cast_type); typedef struct { @@ -100,17 +101,14 @@ typedef struct typedef struct { + Token name_loc; Path *path; } TypeUnresolved; typedef struct { Type *base; - union - { - Expr *unresolved_len; - size_t len; - }; + size_t len; } TypeArray; typedef struct @@ -120,28 +118,37 @@ typedef struct struct _Type { - TypeKind type_kind : 6; - ResolveStatus resolve_status : 2; - Type *canonical; - Token name_loc; - Type **ptr_like_canonical; + TypeKind type_kind : 8; + struct _Type *canonical; + const char *name; + struct _Type **ptr_cache; void *backend_type; void *backend_debug_type; union { Decl *decl; TypeBuiltin builtin; + TypeArray array; + TypeFunc func; + Type *pointer; + }; +}; + +struct _TypeInfo +{ + ResolveStatus resolve_status : 2; + Type *type; + TypeInfoKind kind; + union + { TypeUnresolved unresolved; Expr *unresolved_type_expr; - struct { - Type *base; - union - { - Expr *unresolved_len; - size_t len; - }; - }; - TypeFunc func; + union + { + TypeInfo *base; + Expr *len; + } array; + TypeInfo *pointer; }; }; @@ -178,7 +185,7 @@ typedef struct _VarDecl { unsigned id : 16; VarDeclKind kind : 3; - Type *type; + TypeInfo *type_info; Expr *init_expr; void *backend_ref; void *backend_debug_ref; @@ -208,14 +215,14 @@ typedef struct typedef struct { Decl** values; - Type *type; + TypeInfo *type_info; } EnumDecl; typedef struct _FunctionSignature { bool variadic : 1; - Type *rtype; + TypeInfo *rtype; Decl** params; Token *throws; const char *mangled_signature; @@ -229,7 +236,7 @@ typedef struct typedef struct { const char *full_name; - Type *type_parent; + TypeInfo *type_parent; FunctionSignature function_signature; Ast *body; FuncAnnotations *annotations; @@ -250,6 +257,7 @@ typedef struct union { FunctionSignature function_signature; + TypeInfo *type_info; Type *type; }; } TypedefDecl; @@ -257,7 +265,7 @@ typedef struct typedef struct { Decl **parameters; - Type *rtype; // May be null! + TypeInfo *rtype; // May be null! struct _Ast *body; } MacroDecl; @@ -265,7 +273,7 @@ typedef struct { struct _Ast **cases; Token *parameters; - Type *rtype; // May be null! + TypeInfo *rtype; // May be null! Path *path; // For redefinition } GenericDecl; @@ -288,9 +296,9 @@ typedef struct _Decl uint32_t counter; }; uint32_t size;*/ - Type *self_type; Module *module; Attr** attributes; + Type *type; union { struct @@ -328,7 +336,7 @@ typedef struct typedef struct { - Type *type; + TypeInfo *type; union { Token name; @@ -338,7 +346,7 @@ typedef struct typedef struct { - Type *type; + TypeInfo *type; Expr *init_expr; } ExprStructValue; @@ -407,6 +415,8 @@ typedef struct Token sub_element; Decl *ref; }; + // TODO cleanup + int index; } ExprAccess; typedef struct @@ -419,7 +429,7 @@ typedef struct typedef struct { - Type *type; + TypeInfo *type; } ExprType; @@ -427,6 +437,7 @@ typedef struct { CastKind kind; Expr *expr; + TypeInfo *type_info; union { size_t truncated_size; @@ -439,10 +450,7 @@ struct _Expr 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; @@ -584,7 +592,7 @@ typedef struct _AstCtIfStmt typedef struct _AstGenericCaseStmt { - Type **types; + TypeInfo **types; struct _Ast *body; } AstGenericCaseStmt; @@ -596,7 +604,7 @@ typedef struct typedef struct { - Type **types; + TypeInfo **types; Ast *body; } AstCtCaseStmt; @@ -702,12 +710,10 @@ typedef struct _Context Ast **defers; Decl *active_function_for_analysis; Type *left_type_in_assignment; - FILE *codegen_output; Decl **last_local; Ast **labels; Ast **gotos; DynamicScope *current_scope; - int unique_index; Decl *evaluating_macro; Type *rtype; int in_volatile_section; @@ -720,6 +726,7 @@ typedef struct STable modules; STable global_symbols; STable qualified_symbols; + Type **type; } Compiler; extern Context *current_context; @@ -728,6 +735,7 @@ extern Ast poisoned_ast; extern Decl poisoned_decl; extern Expr poisoned_expr; extern Type poisoned_type; +extern TypeInfo poisoned_type_info; extern Module poisoned_module; extern Diagnostics diagnostics; @@ -811,7 +819,7 @@ static inline bool builtin_may_bit_negate(Type *canonical) 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; + return (type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX) ? CONST_INT : CONST_INT; } bool cast(Expr *expr, Type *to_type, CastType cast_type); @@ -822,7 +830,9 @@ void llvm_codegen(Context *context); void codegen(Context *context); bool sema_analyse_expr(Context *context, Expr *expr); +bool sema_analyse_decl(Context *context, Decl *decl); +void compiler_add_type(Type *type); Decl *compiler_find_symbol(Token token); Module *compiler_find_or_create_module(const char *module_name); void compiler_register_public_symbol(Decl *decl); @@ -839,8 +849,9 @@ void context_add_header_decl(Context *context, Decl *decl); bool context_add_local(Context *context, Decl *decl); Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility); -Decl *decl_new_user_defined_type(Token name, DeclKind decl_type, Visibility visibility); -Decl *decl_new_var(Token name, Type *type, VarDeclKind kind, Visibility visibility); +Decl *decl_new_with_type(Token name, DeclKind decl_type, Visibility visibility); +Decl *decl_new_var(Token name, TypeInfo *type, VarDeclKind kind, Visibility visibility); +const char *decl_var_to_string(VarDeclKind kind); static inline bool decl_ok(Decl *decl) { return decl->decl_kind != DECL_POISONED; } static inline bool decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return false; } @@ -870,7 +881,7 @@ static inline void expr_replace(Expr *expr, Expr *replacement) 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_type_info_recursive(FILE *file, TypeInfo *type_info, int indent); void fprint_expr_recursive(FILE *file, Expr *expr, int indent); @@ -904,6 +915,8 @@ Decl *module_find_symbol(Module *module, const char *symbol); void parse_file(Context *context); +const char *resolve_status_to_string(ResolveStatus status); + #define SEMA_ERROR(_tok, ...) sema_error_range(_tok.span, __VA_ARGS__) void sema_init(File *file); void sema_analysis_pass_conditional_compilation(Context *context); @@ -911,8 +924,8 @@ void sema_analysis_pass_decls(Context *context); void sema_analysis_pass_3(Context *context); bool sema_analyse_statement(Context *context, Ast *statement); -bool sema_resolve_type(Context *context, Type *type); -bool sema_resolve_type_shallow(Context *context, Type *type); +bool sema_resolve_type_info(Context *context, TypeInfo *type_info); +bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info); 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); @@ -940,6 +953,7 @@ const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, Toke void target_setup(); int target_alloca_addr_space(); void *target_data_layout(); +void *target_machine(); #define TOKEN_MAX_LENGTH 0xFFFF #define TOK2VARSTR(_token) _token.span.length, _token.start @@ -950,9 +964,8 @@ 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_get_ptr(Type *ptr_type); +Type *type_get_array(Type *arr_type, uint64_t len); Type *type_signed_int_by_size(int bitsize); Type *type_unsigned_int_by_size(int bitsize); bool type_is_subtype(Type *type, Type *possible_subtype); @@ -964,7 +977,7 @@ static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && 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; } +static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; } bool type_may_have_method_functions(Type *type); static inline bool type_is_integer(Type *type) { @@ -972,12 +985,61 @@ static inline bool type_is_integer(Type *type) return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_UXX; } +static inline bool type_is_signed_integer(Type *type) +{ + assert(type == type->canonical); + return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_IXX; +} + +static inline bool type_is_unsigned_integer(Type *type) +{ + assert(type == type->canonical); + return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_UXX; +} + +static inline bool type_info_poison(TypeInfo *type) +{ + type->type = &poisoned_type; + type->resolve_status = RESOLVE_DONE; + return false; +} + static inline bool type_is_float(Type *type) { assert(type == type->canonical); return type->type_kind >= TYPE_F32 && type->type_kind <= TYPE_FXX; } +static inline TypeInfo *type_info_new(TypeInfoKind kind) +{ + TypeInfo *type_info = malloc_arena(sizeof(TypeInfo)); + memset(type_info, 0, sizeof(TypeInfo)); + type_info->kind = kind; + type_info->resolve_status = RESOLVE_NOT_DONE; + return type_info; +} + +static inline TypeInfo *type_info_new_base(Type *type) +{ + TypeInfo *type_info = malloc_arena(sizeof(TypeInfo)); + memset(type_info, 0, sizeof(TypeInfo)); + type_info->kind = TYPE_INFO_IDENTIFIER; + type_info->resolve_status = RESOLVE_DONE; + type_info->type = type; + return type_info; +} + +static inline Type *type_new(TypeKind kind, const char *name) +{ + Type *type = malloc_arena(sizeof(Type)); + memset(type, 0, sizeof(Type)); + type->type_kind = kind; + type->name = name; + compiler_add_type(type); + return type; +} + + static inline bool type_convert_will_trunc(Type *destination, Type *source) { assert(type_is_builtin(destination->canonical->type_kind)); @@ -993,7 +1055,7 @@ static inline bool type_is_number(Type *type) #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; }) +#define TYPE_UNRESOLVED(_name) ({ TypeInfo *__type = type_new(TYPE_USER_DEFINED); __type->name_loc = _name; __type; }) AssignOp assignop_from_token(TokenType type); UnaryOp unaryop_from_token(TokenType type); @@ -1009,7 +1071,8 @@ static inline const char* struct_union_name_from_token(TokenType type) return type == TOKEN_STRUCT ? "struct" : "union"; } - - +#define BACKEND_TYPE(type) gencontext_get_llvm_type(context, type) +#define BACKEND_TYPE_GLOBAL(type) gencontext_get_llvm_type(NULL, type) +#define DEBUG_TYPE(type) gencontext_get_debug_type(context, type) diff --git a/src/compiler/context.c b/src/compiler/context.c index e6ee17722..e4a22ac36 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -153,7 +153,7 @@ void context_register_global_decl(Context *context, Decl *decl) vec_add(context->ct_ifs, decl); return; } - DEBUG_LOG("Registering symbol %s.", decl->name.string); + DEBUG_LOG("Registering symbol '%s'.", decl->name.string); Decl *old = stable_set(&context->local_symbols, decl->name.string, decl); if (!old && decl->visibility != VISIBLE_LOCAL) diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 80d3ae811..0ae5348a7 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -300,6 +300,16 @@ typedef enum RESOLVE_DONE } ResolveStatus; +typedef enum +{ + TYPE_INFO_POISON, + TYPE_INFO_IDENTIFIER, + TYPE_INFO_EXPRESSION, + TYPE_INFO_ARRAY, + TYPE_INFO_INC_ARRAY, + TYPE_INFO_POINTER, +} TypeInfoKind; + typedef enum { TOKEN_INVALID_TOKEN = 0, @@ -503,14 +513,17 @@ typedef enum TYPE_F32, TYPE_F64, TYPE_FXX, - TYPE_FUNC, - TYPE_USER_DEFINED, TYPE_POINTER, + TYPE_ENUM, + TYPE_ERROR, + TYPE_FUNC, + TYPE_STRUCT, + TYPE_UNION, + TYPE_TYPEDEF, TYPE_STRING, TYPE_ARRAY, TYPE_VARARRAY, - TYPE_INC_ARRAY, - TYPE_EXPRESSION, + TYPE_SUBARRAY, } TypeKind; typedef enum diff --git a/src/compiler/expr_analysis.c b/src/compiler/expr_analysis.c index 1e10c9219..5295cf268 100644 --- a/src/compiler/expr_analysis.c +++ b/src/compiler/expr_analysis.c @@ -20,6 +20,8 @@ static bool expr_is_ltype(Expr *expr) return expr->identifier_expr.decl->decl_kind == DECL_VAR && (expr->identifier_expr.decl->var.kind == VARDECL_LOCAL || expr->identifier_expr.decl->var.kind == VARDECL_GLOBAL); case EXPR_UNARY: return expr->unary_expr.operator == TOKEN_STAR; + case EXPR_ACCESS: + return expr_is_ltype(expr->access_expr.parent); default: return false; } @@ -55,10 +57,10 @@ static inline bool sema_expr_analyse_identifier(Context *context, Expr *expr) SEMA_ERROR(expr->loc, "Unknown identifier %s.", expr->identifier_expr.identifier.string); return false; } - if (!decl_ok(decl)) return expr_poison(expr); + assert(decl->type); expr->identifier_expr.decl = decl; - expr->type = decl->var.type; + expr->type = decl->type; return true; } @@ -70,7 +72,7 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Expr *expr, De Decl *stored_macro = context->evaluating_macro; Type *stored_rtype = context->rtype; context->evaluating_macro = macro; - context->rtype = macro->macro_decl.rtype; + context->rtype = macro->macro_decl.rtype->type; // Handle escaping macro bool success = sema_analyse_statement(context, macro->macro_decl.body); context->evaluating_macro = stored_macro; @@ -94,9 +96,9 @@ static inline bool sema_expr_analyse_func_call(Context *context, Expr *expr, Dec { Expr *arg = args[i]; if (!sema_analyse_expr(context, arg)) return false; - if (!cast(arg, func_params[i]->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + if (!cast(arg, func_params[i]->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; } - expr->type = decl->func.function_signature.rtype; + expr->type = decl->func.function_signature.rtype->type; return true; } @@ -190,7 +192,7 @@ static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr if (error_constant->name.string == name) { assert(error_constant->resolve_status == RESOLVE_DONE); - expr->type = decl->self_type; + expr->type = decl->type; expr->expr_kind = EXPR_CONST; expr->const_expr.type = CONST_INT; expr->const_expr.i = decl->error_constant.value; @@ -201,15 +203,16 @@ static inline bool sema_expr_analyse_error_constant(Context *context, Expr *expr return false; } -static Decl *strukt_recursive_search_member(Decl *strukt, const char *name) +static Decl *strukt_recursive_search_member(Decl *strukt, const char *name, int *index) { VECEACH(strukt->strukt.members, i) { + (*index)++; Decl *member = strukt->strukt.members[i]; if (member->name.string == name) return member; if (!member->name.string && decl_is_struct_type(member)) { - Decl *result = strukt_recursive_search_member(member, name); + Decl *result = strukt_recursive_search_member(member, name, index); if (result) return result; } } @@ -225,7 +228,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) bool is_pointer = type->type_kind == TYPE_POINTER; if (is_pointer) { - type = type->base; + type = type->pointer; } if (!type_may_have_method_functions(type)) { @@ -244,7 +247,8 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) default: UNREACHABLE } - Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string); + int index = -1; + Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string, &index); if (!member) { SEMA_ERROR(expr->access_expr.sub_element, "There is no element '%s.%s'.", decl->name.string, expr->access_expr.sub_element.string); @@ -259,27 +263,21 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) deref->type = type; expr->access_expr.parent = deref; } - if (member->decl_kind == DECL_VAR) - { - expr->type = member->var.type; - } - else - { - expr->type = member->self_type; - } + expr->type = member->type; + expr->access_expr.index = index; return true; } static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr) { - Type *type = expr->type_access.type; - if (!sema_resolve_type(context, type)) return false; - if (!type_may_have_method_functions(type)) + TypeInfo *type_info = expr->type_access.type; + if (!sema_resolve_type_info(context, type_info)) return false; + if (!type_may_have_method_functions(type_info->type)) { - SEMA_ERROR(expr->loc, "'%s' does not have method functions.", type_to_error_string(type)); + SEMA_ERROR(expr->loc, "'%s' does not have method functions.", type_to_error_string(type_info->type)); return false; } - Decl *decl = type->decl; + Decl *decl = type_info->type->decl; // TODO add more constants that can be inspected? // e.g. SomeEnum.values, MyUnion.x.offset etc? switch (decl->decl_kind) @@ -296,17 +294,17 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr) default: UNREACHABLE } - VECEACH(type->decl->method_functions, i) + VECEACH(type_info->type->decl->method_functions, i) { - Decl *function = type->decl->method_functions[i]; + Decl *function = type_info->type->decl->method_functions[i]; if (expr->type_access.name.string == function->name.string) { expr->type_access.method = function; - expr->type = function->func.function_signature.rtype; + expr->type = function->func.function_signature.rtype->type; return true; } } - SEMA_ERROR(expr->loc, "No function '%s.%s' found.", type_to_error_string(type), expr->type_access.name.string); + SEMA_ERROR(expr->loc, "No function '%s.%s' found.", type_to_error_string(type_info->type), expr->type_access.name.string); return false; } @@ -356,7 +354,7 @@ static inline bool sema_expr_analyse_struct_initializer_list(Context *context, T } decl = members[i]; } - if (!cast(field, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + if (!cast(field, decl->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; } expr->type = assigned; return true; @@ -368,7 +366,8 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Expr *ex assert(assigned); switch (assigned->type_kind) { - case TYPE_USER_DEFINED: + case TYPE_STRUCT: + case TYPE_UNION: if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer_list(context, assigned, expr); break; case TYPE_ARRAY: @@ -391,11 +390,12 @@ static inline bool sema_expr_analyse_sizeof(Context *context, Expr *expr) static inline bool sema_expr_analyse_cast(Context *context, Expr *expr) { Expr *inner = expr->expr_cast.expr; - if (!sema_resolve_type(context, expr->type)) return false; + if (!sema_resolve_type_info(context, expr->expr_cast.type_info)) return false; if (!sema_analyse_expr(context, inner)) return false; - if (!cast(inner, expr->type, CAST_TYPE_EXPLICIT)) return false; + if (!cast(inner, expr->expr_cast.type_info->type, CAST_TYPE_EXPLICIT)) return false; + // TODO above is probably not right, cast type not set. // Overwrite cast. Token loc = expr->loc; *expr = *inner; @@ -792,7 +792,7 @@ static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner) return false; } Type *deref_type = inner->type->type_kind != TYPE_POINTER ? inner->type : canonical; - expr->type = deref_type->base; + expr->type = deref_type->pointer; return true; } @@ -803,14 +803,7 @@ static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *inner) SEMA_ERROR(inner->loc, "Cannot take the address of a value of type '%s'", type_to_error_string(inner->type)); return false; } - Type *type = type_new(TYPE_POINTER); - type->name_loc = inner->type->name_loc; - type->base = inner->type; - type->resolve_status = RESOLVE_DONE; - type->canonical = type_get_canonical_ptr(type); - assert(type->resolve_status == RESOLVE_DONE); - assert(type->canonical->resolve_status == RESOLVE_DONE); - expr->type = type; + expr->type = type_get_ptr(inner->type); return true; } @@ -903,13 +896,13 @@ static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner) case TYPE_IXX: case TYPE_UXX: case TYPE_FXX: - case TYPE_INC_ARRAY: - case TYPE_EXPRESSION: + case TYPE_TYPEDEF: UNREACHABLE case TYPE_FUNC: case TYPE_ARRAY: case TYPE_POINTER: case TYPE_VARARRAY: + case TYPE_SUBARRAY: case TYPE_BOOL: case TYPE_I8: case TYPE_I16: @@ -922,9 +915,12 @@ static bool sema_expr_analyse_not(Context *context, Expr *expr, Expr *inner) case TYPE_F32: case TYPE_F64: return true; - case TYPE_USER_DEFINED: + case TYPE_STRUCT: + case TYPE_UNION: case TYPE_VOID: case TYPE_STRING: + case TYPE_ENUM: + case TYPE_ERROR: SEMA_ERROR(expr->loc, "Cannot use 'not' on %s", type_to_error_string(inner->type)); return false; } diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index aa8cbea76..36b70e2a8 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -38,7 +38,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl { // Tentative definition, initialized to zero, but only // emitted at the end of the translation unit. - init = gencontext_emit_null_constant(context, decl->var.type); + init = gencontext_emit_null_constant(context, decl->type); } else { @@ -46,7 +46,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl } // TODO fix name - decl->var.backend_ref = LLVMAddGlobal(context->module, gencontext_get_llvm_type(context, decl->var.type), decl->name.string); + decl->var.backend_ref = LLVMAddGlobal(context->module, decl->type->backend_type, decl->name.string); // If read only: LLVMSetGlobalConstant(decl->var.backend_ref, 1); @@ -75,7 +75,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl 2, context->debug.file, 12 /* lineno */, - decl->var.type->backend_debug_type, + decl->type->backend_debug_type, decl->visibility == VISIBLE_LOCAL, /* expr */ NULL, /** declaration **/ @@ -97,10 +97,27 @@ static void gencontext_verify_ir(GenContext *context) error_exit("Could not verify module IR."); } } + +void gencontext_emit_object_file(GenContext *context) +{ + char *err = ""; + LLVMSetTarget(context->module, build_options.target); + char *layout = LLVMCopyStringRepOfTargetData(target_data_layout()); + LLVMSetDataLayout(context->module, layout); + LLVMDisposeMessage(layout); + + // Generate .o or .obj file + char *filename = strformat("%.*s.o", (int)strlen(context->ast_context->file->name) - 3, context->ast_context->file->name); + if (LLVMTargetMachineEmitToFile(target_machine(), context->module, filename, LLVMObjectFile, &err) != 0) + { + error_exit("Could not emit object file: %s", err); + } +} + void gencontext_print_llvm_ir(GenContext *context) { char *err = NULL; - char *filename = strformat("xx.llvmir" /*, context->module_name*/); + char *filename = strformat("%.*s.ll", (int)strlen(context->ast_context->file->name) - 3, context->ast_context->file->name); if (LLVMPrintModuleToFile(context->module, filename, &err) != 0) { error_exit("Could not emit ir to file: %s", err); @@ -113,11 +130,31 @@ LLVMValueRef gencontext_emit_alloca(GenContext *context, Decl *decl) { LLVMBasicBlockRef current_block = LLVMGetInsertBlock(context->builder); LLVMPositionBuilderBefore(context->builder, context->alloca_point); - LLVMValueRef alloca = LLVMBuildAlloca(context->builder, gencontext_get_llvm_type(context, decl->var.type->canonical), decl->name.string); + LLVMValueRef alloca = LLVMBuildAlloca(context->builder, BACKEND_TYPE(decl->type), decl->name.string); LLVMPositionBuilderAtEnd(context->builder, current_block); return alloca; } +/** + * Values here taken from LLVM. + * @return return the inlining threshold given the build options. + */ +static int get_inlining_threshold(void) +{ + if (build_options.optimization_level == OPTIMIZATION_AGGRESSIVE) + { + return 250; + } + switch (build_options.size_optimization_level) + { + case SIZE_OPTIMIZATION_TINY: + return 5; + case SIZE_OPTIMIZATION_SMALL: + return 50; + default: + return 250; + } +} void llvm_codegen(Context *context) { GenContext gen_context; @@ -128,9 +165,46 @@ void llvm_codegen(Context *context) { gencontext_emit_function_decl(&gen_context, context->functions[i]); } - LLVMDumpModule(gen_context.module); - gencontext_print_llvm_ir(&gen_context); - LLVMDumpModule(gen_context.module); + + // Starting from here we could potentially thread this: + LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate(); + LLVMPassManagerBuilderSetOptLevel(pass_manager_builder, build_options.optimization_level); + LLVMPassManagerBuilderSetSizeLevel(pass_manager_builder, build_options.size_optimization_level); + LLVMPassManagerBuilderSetDisableUnrollLoops(pass_manager_builder, build_options.optimization_level == OPTIMIZATION_NONE); + LLVMPassManagerBuilderUseInlinerWithThreshold(pass_manager_builder, get_inlining_threshold()); + LLVMPassManagerRef pass_manager = LLVMCreatePassManager(); + LLVMPassManagerRef function_pass_manager = LLVMCreateFunctionPassManagerForModule(gen_context.module); + LLVMAddAnalysisPasses(target_machine(), pass_manager); + LLVMAddAnalysisPasses(target_machine(), function_pass_manager); + LLVMPassManagerBuilderPopulateModulePassManager(pass_manager_builder, pass_manager); + LLVMPassManagerBuilderPopulateFunctionPassManager(pass_manager_builder, function_pass_manager); + + // IMPROVE + // In LLVM Opt, LoopVectorize and SLPVectorize settings are part of the PassManagerBuilder + // Anything else we need to manually add? + + LLVMPassManagerBuilderDispose(pass_manager_builder); + + // Run function passes + LLVMInitializeFunctionPassManager(function_pass_manager); + LLVMValueRef current_function = LLVMGetFirstFunction(gen_context.module); + while (current_function) + { + LLVMRunFunctionPassManager(function_pass_manager, current_function); + current_function = LLVMGetNextFunction(current_function); + } + LLVMFinalizeFunctionPassManager(function_pass_manager); + LLVMDisposePassManager(function_pass_manager); + + // Run module pass + LLVMRunPassManager(pass_manager, gen_context.module); + LLVMDisposePassManager(pass_manager); + + // Serialize the LLVM IR, if requested + if (build_options.emit_llvm) gencontext_print_llvm_ir(&gen_context); + + if (build_options.emit_bitcode) gencontext_emit_object_file(&gen_context); + gencontext_end_module(&gen_context); gencontext_destroy(&gen_context); } diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 68360a8f8..3368a6777 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -4,6 +4,53 @@ #include "llvm_codegen_internal.h" +static inline LLVMMetadataRef gencontext_create_debug_type_from_decl(GenContext *context, Decl *decl) +{ + static LLVMMetadataRef debug_params[512]; + switch (decl->decl_kind) + { + case DECL_ATTRIBUTE: + case DECL_ENUM_CONSTANT: + case DECL_POISONED: + case DECL_GENERIC: + case DECL_MULTI_DECL: + case DECL_MACRO: + case DECL_CT_IF: + case DECL_CT_ELSE: + case DECL_CT_ELIF: + case DECL_VAR: + case DECL_ERROR_CONSTANT: + case DECL_ARRAY_VALUE: + case DECL_IMPORT: + UNREACHABLE; + case DECL_FUNC: + { + VECEACH(decl->func.function_signature.params, i) + { + Type *param_type = decl->func.function_signature.params[i]->type; + debug_params[i + 1] = gencontext_get_debug_type(context, param_type); + } + unsigned param_size = vec_size(decl->func.function_signature.params); + debug_params[0] = decl->func.function_signature.rtype->type->backend_debug_type; + return LLVMDIBuilderCreateSubroutineType(context->debug.builder, + context->debug.file, + debug_params, param_size + 1, + /** TODO **/ 0); + } + case DECL_TYPEDEF: + TODO + case DECL_STRUCT: + TODO + case DECL_UNION: + TODO + case DECL_ENUM: + TODO + case DECL_ERROR: + TODO + } + UNREACHABLE +} + void gencontext_set_debug_location(GenContext *context, SourceRange source_range) { if (source_range.loc == INVALID_LOC) return; @@ -44,40 +91,80 @@ void gencontext_emit_debug_location(GenContext *context, SourceRange location) static LLVMMetadataRef gencontext_simple_debug_type(GenContext *context, Type *type, int dwarf_code) { - return LLVMDIBuilderCreateBasicType(context->debug.builder, - type->name_loc.string, - type->name_loc.span.length, - type->builtin.bitsize, - dwarf_code, 0); + return type->backend_debug_type = LLVMDIBuilderCreateBasicType(context->debug.builder, + type->name, + strlen(type->name), + type->builtin.bitsize, + dwarf_code, 0); } -LLVMMetadataRef gencontext_create_builtin_debug_type(GenContext *context, Type *builtin_type) +LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type) { - assert(builtin_type->canonical == builtin_type); + if (type->backend_debug_type) return type->backend_debug_type; // Consider special handling of UTF8 arrays. - switch (builtin_type->type_kind) + switch (type->type_kind) { + case TYPE_POISONED: + case TYPE_IXX: + case TYPE_UXX: + case TYPE_FXX: + UNREACHABLE case TYPE_BOOL: - return gencontext_simple_debug_type(context, builtin_type, DW_ATE_boolean); + return gencontext_simple_debug_type(context, type, DW_ATE_boolean); case TYPE_I8: - return gencontext_simple_debug_type(context, builtin_type, DW_ATE_signed_char); // DW_ATE_UTF? + return gencontext_simple_debug_type(context, type, DW_ATE_signed_char); // DW_ATE_UTF? case TYPE_U8: - return gencontext_simple_debug_type(context, builtin_type, DW_ATE_unsigned_char); + return gencontext_simple_debug_type(context, type, DW_ATE_unsigned_char); case TYPE_I16: case TYPE_I32: case TYPE_I64: - return gencontext_simple_debug_type(context, builtin_type, DW_ATE_signed); + return gencontext_simple_debug_type(context, type, DW_ATE_signed); case TYPE_U16: case TYPE_U32: case TYPE_U64: - return gencontext_simple_debug_type(context, builtin_type, DW_ATE_unsigned); + return gencontext_simple_debug_type(context, type, DW_ATE_unsigned); case TYPE_F32: case TYPE_F64: - return gencontext_simple_debug_type(context, builtin_type, DW_ATE_float); + return gencontext_simple_debug_type(context, type, DW_ATE_float); case TYPE_VOID: return NULL; - default: - UNREACHABLE + case TYPE_POINTER: + return type->backend_debug_type = LLVMDIBuilderCreatePointerType(context->debug.builder, type->pointer->backend_debug_type, type_size(type->canonical->pointer), 0, 0, type->name, strlen(type->name)); + case TYPE_ENUM: + break; + case TYPE_ERROR: + break; + case TYPE_FUNC: + break; + case TYPE_STRUCT: + break; + case TYPE_UNION: + break; + case TYPE_TYPEDEF: + break; + case TYPE_STRING: + break; + case TYPE_ARRAY: + { + LLVMMetadataRef *ranges = NULL; + Type *current_type = type; + while (current_type->canonical->type_kind == TYPE_ARRAY) + { + VECADD(ranges, LLVMDIBuilderGetOrCreateSubrange(context->debug.builder, 0, current_type->canonical->array.len)); + current_type = current_type->canonical->array.base; + } + return type->backend_debug_type = LLVMDIBuilderCreateArrayType( + context->debug.builder, + type->array.len, + 0 /* ALIGN */, + type->array.base->backend_debug_type, + ranges, vec_size(ranges)); + } + case TYPE_VARARRAY: + break; + case TYPE_SUBARRAY: + break; } + TODO } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 9c1362c3a..c2e6653d2 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -20,8 +20,38 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) assert(op == UNARYOP_DEREF); return gencontext_emit_expr(context, expr->unary_expr.expr); } - default: + case EXPR_ACCESS: TODO; + { + // LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent); + // LLVMBuildExtractValue(context->builder, value, (unsigned)expr->access_expr.index, expr->access_expr.ref->name.string); + } + case EXPR_POISONED: + case EXPR_TRY: + case EXPR_SIZEOF: + UNREACHABLE + case EXPR_BINARY: + TODO; + case EXPR_CONDITIONAL: + TODO; + case EXPR_POST_UNARY: + TODO; + case EXPR_TYPE_ACCESS: + TODO + case EXPR_CALL: + TODO + case EXPR_SUBSCRIPT: + TODO + case EXPR_STRUCT_VALUE: + TODO + case EXPR_STRUCT_INIT_VALUES: + TODO + case EXPR_INITIALIZER_LIST: + TODO + case EXPR_EXPRESSION_LIST: + TODO + case EXPR_CAST: + TODO } return NULL; } @@ -34,9 +64,9 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr * case CAST_ERROR: UNREACHABLE case CAST_PTRPTR: - return LLVMBuildPointerCast(context->builder, rhs, LLVMTYPE(expr->type), "ptrptr"); + return LLVMBuildPointerCast(context->builder, rhs, BACKEND_TYPE(expr->type), "ptrptr"); case CAST_PTRXI: - return LLVMBuildPtrToInt(context->builder, rhs, LLVMTYPE(expr->type), "ptrxi"); + return LLVMBuildPtrToInt(context->builder, rhs, BACKEND_TYPE(expr->type), "ptrxi"); case CAST_VARRPTR: TODO case CAST_ARRPTR: @@ -44,46 +74,46 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr * case CAST_STRPTR: TODO case CAST_PTRBOOL: - return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstPointerNull(LLVMTYPE(expr->type->canonical->base)), "ptrbool"); + return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstPointerNull(BACKEND_TYPE(expr->type->canonical->pointer)), "ptrbool"); case CAST_BOOLINT: - return LLVMBuildTrunc(context->builder, rhs, LLVMTYPE(expr->type), "boolsi"); + return LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "boolsi"); case CAST_FPBOOL: return LLVMBuildFCmp(context->builder, LLVMRealUNE, rhs, LLVMConstNull(LLVMTypeOf(rhs)), "fpbool"); case CAST_BOOLFP: - return LLVMBuildSIToFP(context->builder, rhs, LLVMTYPE(expr->type), "boolfp"); + return LLVMBuildSIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "boolfp"); case CAST_INTBOOL: return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstNull(LLVMTypeOf(rhs)), "intbool"); case CAST_FPFP: return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type) - ? LLVMBuildFPTrunc(context->builder, rhs, LLVMTYPE(expr->type), "fpfptrunc") - : LLVMBuildFPExt(context->builder, rhs, LLVMTYPE(expr->type), "fpfpext"); + ? LLVMBuildFPTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfptrunc") + : LLVMBuildFPExt(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfpext"); case CAST_FPSI: - return LLVMBuildFPToSI(context->builder, rhs, LLVMTYPE(expr->type), "fpsi"); + return LLVMBuildFPToSI(context->builder, rhs, BACKEND_TYPE(expr->type), "fpsi"); case CAST_FPUI: - return LLVMBuildFPToUI(context->builder, rhs, LLVMTYPE(expr->type), "fpui"); + return LLVMBuildFPToUI(context->builder, rhs, BACKEND_TYPE(expr->type), "fpui"); case CAST_SISI: return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type) - ? LLVMBuildTrunc(context->builder, rhs, LLVMTYPE(expr->type), "sisitrunc") - : LLVMBuildSExt(context->builder, rhs, LLVMTYPE(expr->type), "sisiext"); + ? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "sisitrunc") + : LLVMBuildSExt(context->builder, rhs, BACKEND_TYPE(expr->type), "sisiext"); case CAST_SIUI: return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type) - ? LLVMBuildTrunc(context->builder, rhs, LLVMTYPE(expr->type), "siuitrunc") - : LLVMBuildZExt(context->builder, rhs, LLVMTYPE(expr->type), "siuiext"); + ? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "siuitrunc") + : LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "siuiext"); break; case CAST_SIFP: - return LLVMBuildSIToFP(context->builder, rhs, LLVMTYPE(expr->type), "sifp"); + return LLVMBuildSIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "sifp"); case CAST_XIPTR: - return LLVMBuildIntToPtr(context->builder, rhs, LLVMTYPE(expr->type), "xiptr"); + return LLVMBuildIntToPtr(context->builder, rhs, BACKEND_TYPE(expr->type), "xiptr"); case CAST_UISI: return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type) - ? LLVMBuildTrunc(context->builder, rhs, LLVMTYPE(expr->type), "uisitrunc") - : LLVMBuildZExt(context->builder, rhs, LLVMTYPE(expr->type), "uisiext"); + ? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uisitrunc") + : LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uisiext"); case CAST_UIUI: return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type) - ? LLVMBuildTrunc(context->builder, rhs, LLVMTYPE(expr->type), "uiuitrunc") - : LLVMBuildZExt(context->builder, rhs, LLVMTYPE(expr->type), "uiuiext"); + ? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuitrunc") + : LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuiext"); case CAST_UIFP: - return LLVMBuildUIToFP(context->builder, rhs, LLVMTYPE(expr->type), "uifp"); + return LLVMBuildUIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "uifp"); case CAST_ENUMSI: TODO } @@ -118,6 +148,7 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr) } + static LLVMValueRef gencontext_emit_assign(GenContext *context, Expr *left, LLVMValueRef right) { LLVMValueRef addr = gencontext_emit_address(context, left); @@ -200,7 +231,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, bool { if (lhs->type->canonical == rhs->type->canonical) return LLVMBuildPtrDiff(context->builder, lhs_value, rhs_value, "ptrdiff"); rhs_value = LLVMBuildNeg(context->builder, rhs_value, ""); - return LLVMBuildGEP2(context->builder, gencontext_get_llvm_type(context, lhs->type->canonical), lhs_value, &rhs_value, 1, "ptrsub"); + return LLVMBuildGEP2(context->builder, BACKEND_TYPE(lhs->type), lhs_value, &rhs_value, 1, "ptrsub"); } if (is_float) return LLVMBuildFSub(context->builder, lhs_value, rhs_value, "fsub"); // Consider UB version instead. @@ -209,7 +240,7 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, bool if (lhs->type->canonical->type_kind == TYPE_POINTER) { assert(type_is_integer(lhs->type->canonical)); - return LLVMBuildGEP2(context->builder, gencontext_get_llvm_type(context, lhs->type->canonical), lhs_value, &rhs_value, 1, "ptradd"); + return LLVMBuildGEP2(context->builder, BACKEND_TYPE(lhs->type), lhs_value, &rhs_value, 1, "ptradd"); } if (is_float) return LLVMBuildFAdd(context->builder, lhs_value, rhs_value, "fadd"); // Consider UB version instead. @@ -283,6 +314,35 @@ static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, bool } } +LLVMValueRef gencontext_emit_post_unary_expr(GenContext *context, Expr *expr) +{ + Expr *lhs = expr->unary_expr.expr; + LLVMValueRef value = gencontext_emit_expr(context, lhs); + bool is_add = expr->post_expr.operator == TOKEN_PLUSPLUS; +/* if (expr->type->canonical->type_kind == TYPE_POINTER) + { + LLVMValueRef offset = LLVMConstInt(is_add ? type_isize->backend_type : type_usize->backend_type, is_add ? 1 : -1, true); + LLVMBuildStore(context->builder, LLVMBuildGEP2(context->builder, gencontext_get_llvm_type(context, expr->type->canonical), value, &offset, 1, "postunary"), gencontext_emit_address(context, left);) + return ; + } + if (type_is_float(expr->type->canonical)) + { + LLVMValueRef offset = LLVMConstReal(LLVMTypeOf(value), is_add ? 1); + LLVMBuildAdd(context->builder, value, offset, name); + } + if (lhs->type->canonical->type_kind == TYPE_POINTER) + { + rhs_value = LLVMBuildNeg(context->builder, rhs_value, ""); + return LLVMBuildGEP2(context->builder, , lhs_value, &rhs_value, 1, "ptrsub"); + } + */ + const char *name = is_add ? "add" : "sub"; + LLVMValueRef constVal = LLVMConstInt(LLVMTypeOf(value), 1, !is_add); + LLVMValueRef result = is_add ? LLVMBuildAdd(context->builder, value, constVal, name) + : LLVMBuildSub(context->builder, value, constVal, name); + LLVMBuildStore(context->builder, result, gencontext_emit_address(context, lhs)); + return value; +} static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr) { @@ -306,13 +366,13 @@ static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr) static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *expr) { - return LLVMBuildLoad2(context->builder, expr->identifier_expr.decl->var.type->canonical->backend_type, + return LLVMBuildLoad2(context->builder, expr->identifier_expr.decl->type->canonical->backend_type, expr->identifier_expr.decl->var.backend_ref, expr->identifier_expr.decl->name.string); } LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr) { - LLVMTypeRef type = gencontext_get_llvm_type(context, expr->type->canonical); + LLVMTypeRef type = BACKEND_TYPE(expr->type); switch (expr->const_expr.type) { case CONST_INT: @@ -324,14 +384,36 @@ LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr) case CONST_BOOL: return LLVMConstInt(type, expr->const_expr.b ? 1 : 0, false); case CONST_STRING: - return LLVMConstStringInContext(context->context, - expr->const_expr.string.chars, - expr->const_expr.string.len, - false); + { + LLVMValueRef global_name = LLVMAddGlobal(context->module, type, "string"); + LLVMSetLinkage(global_name, LLVMInternalLinkage); + LLVMSetGlobalConstant(global_name, 1); + LLVMSetInitializer(global_name, LLVMConstStringInContext(context->context, + expr->const_expr.string.chars, + expr->const_expr.string.len, + 1)); + return global_name; + } } UNREACHABLE } +LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr) +{ + size_t args = vec_size(expr->call_expr.arguments); + LLVMValueRef *values = args ? malloc_arena(args * sizeof(LLVMValueRef)) : NULL; + VECEACH(expr->call_expr.arguments, i) + { + values[i] = gencontext_emit_expr(context, expr->call_expr.arguments[i]); + } + LLVMValueRef func = expr->call_expr.function->identifier_expr.decl->func.backend_value; + + return LLVMBuildCall2(context->builder, LLVMTYPE(expr->call_expr.function->identifier_expr.decl->type), func, values, args, "call"); + /* + if (fndcl->flags & FlagSystem) { + LLVMSetInstructionCallConv(fncallret, LLVMX86StdcallCallConv); + }*/ +} LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr) { switch (expr->expr_kind) @@ -349,7 +431,7 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr) case EXPR_CONDITIONAL: break; case EXPR_POST_UNARY: - break; + return gencontext_emit_post_unary_expr(context, expr); case EXPR_TYPE: break; case EXPR_IDENTIFIER: @@ -357,7 +439,7 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr) case EXPR_TYPE_ACCESS: break; case EXPR_CALL: - break; + return gencontext_emit_call_expr(context, expr); case EXPR_SIZEOF: break; case EXPR_SUBSCRIPT: diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 152bdcb20..44cf0a343 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -8,7 +8,7 @@ static char *mangle_name(char *buffer, Decl *decl) { - sprintf(buffer, "mangled_name_%*s", decl->name.span.length, decl->name.start); + sprintf(buffer, "%*s", decl->name.span.length, decl->name.start); return buffer; } @@ -114,7 +114,7 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl) // Insert a return if needed. if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(context->builder))) { - assert(decl->func.function_signature.rtype->type_kind == TYPE_VOID); + assert(decl->func.function_signature.rtype->type->type_kind == TYPE_VOID); LLVMBuildRetVoid(context->builder); } @@ -138,7 +138,7 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) char *external_name = mangle_name(workbuf, decl); // Resolve function backend type for function. decl->func.backend_value = LLVMAddFunction(context->module, external_name, - gencontext_get_llvm_type(context, decl->self_type)); + BACKEND_TYPE(decl->type)); // Specify appropriate storage class, visibility and call convention // extern functions (linkedited in separately): @@ -175,7 +175,7 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) decl->name.string, decl->name.span.length, context->debug.file, decl_position.line, - decl->self_type->backend_debug_type, + decl->type->backend_debug_type, decl->visibility == VISIBLE_LOCAL, 1, decl_position.line, @@ -183,5 +183,5 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl) 0); LLVMSetSubprogram(decl->func.backend_value, context->debug.function); } - gencontext_emit_function_body(context, decl); + if (decl->func.body) gencontext_emit_function_body(context, decl); } diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 400227b20..01765e1fc 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -11,10 +11,13 @@ #include #include #include +#include +#include +#include +#include #include #include #include -#include #include "dwarf.h" typedef struct @@ -39,8 +42,6 @@ typedef struct typedef struct { - const char *filename; - const char *dirname; LLVMModuleRef module; LLVMContextRef context; LLVMValueRef function; @@ -51,7 +52,7 @@ typedef struct Decl *cur_code_decl; Decl *cur_func_decl; bool did_call_stack_save; - Type *current_return_type; + TypeInfo *current_return_type; int block_global_unique_count; int ast_alloca_addr_space; BreakContinue return_block; @@ -63,7 +64,7 @@ typedef struct Context *ast_context; BreakContinue break_continue_stack[BREAK_STACK_MAX]; size_t break_continue_stack_index; - + LLVMTypeRef error_type; } GenContext; @@ -71,6 +72,7 @@ void gencontext_begin_module(GenContext *context); void gencontext_end_module(GenContext *context); void gencontext_emit_stmt(GenContext *context, Ast *ast); LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr); +LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type); void gencontext_emit_debug_location(GenContext *context, SourceRange location); LLVMMetadataRef gencontext_create_builtin_debug_type(GenContext *context, Type *builtin_type); LLVMValueRef gencontext_emit_alloca(GenContext *context, Decl *decl); @@ -85,12 +87,12 @@ static inline LLVMBasicBlockRef gencontext_create_free_block(GenContext *context void gencontext_emit_function_decl(GenContext *context, Decl *decl); LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr); -#define LLVMTYPE(type) gencontext_get_llvm_type(context, type->canonical) +#define LLVMTYPE(type) type->backend_type LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type); static inline bool gencontext_use_debug(GenContext *context) { - return context->debug.builder != NULL; + return context && context->debug.builder != NULL; } diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index f24a7de9e..b53dae092 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -38,10 +38,6 @@ static inline LLVMTypeRef gencontext_create_basic_llvm_type(GenContext *context, static inline void gencontext_init_basic_llvm_type(GenContext *context, Type *type) { type->backend_type = gencontext_create_basic_llvm_type(context, type); - if (context->debug.builder) - { - type->backend_debug_type = gencontext_create_builtin_debug_type(context, type); - } } void gencontext_begin_module(GenContext *context) { @@ -93,6 +89,10 @@ void gencontext_begin_module(GenContext *context) context->block_global_unique_count = 0; context->ast_alloca_addr_space = target_alloca_addr_space(); + VECEACH(compiler.type, i) + { + compiler.type[i]->backend_type = NULL; + } /* SizeSizeInBytes = C.toCharUnitsFromBits(C.getTargetInfo().getMaxPointerWidth()).getQuantity(); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index ee03417ff..3cab987ac 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -4,15 +4,15 @@ #include "llvm_codegen_internal.h" - +#define LLVMCONTEXT(gen_context) (gen_context ? gen_context->context : LLVMGetGlobalContext()) static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *context, Decl *decl) { static LLVMTypeRef params[512]; - static LLVMMetadataRef debug_params[512]; switch (decl->decl_kind) { case DECL_ATTRIBUTE: + case DECL_ENUM_CONSTANT: case DECL_POISONED: case DECL_GENERIC: case DECL_MULTI_DECL: @@ -20,81 +20,79 @@ static inline LLVMTypeRef gencontext_create_llvm_type_from_decl(GenContext *cont case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: + case DECL_VAR: + case DECL_ERROR_CONSTANT: + case DECL_ARRAY_VALUE: + case DECL_IMPORT: UNREACHABLE; case DECL_FUNC: { VECEACH(decl->func.function_signature.params, i) { - Type *param_type = decl->func.function_signature.params[i]->var.type; - params[i] = gencontext_get_llvm_type(context, param_type); - if (build_options.debug_info) - { - assert(param_type->backend_debug_type); - debug_params[i + 1] = param_type->backend_debug_type; - } + params[i] = BACKEND_TYPE(decl->func.function_signature.params[i]->type); } unsigned param_size = vec_size(decl->func.function_signature.params); - if (gencontext_use_debug(context)) - { - gencontext_get_llvm_type(context, decl->func.function_signature.rtype); - debug_params[0] = decl->func.function_signature.rtype->backend_debug_type; - LLVMMetadataRef function_type = LLVMDIBuilderCreateSubroutineType(context->debug.builder, - context->debug.file, - debug_params, param_size + 1, - /** TODO **/ 0); - decl->self_type->backend_debug_type = function_type; - } - return LLVMFunctionType(gencontext_get_llvm_type(context, decl->func.function_signature.rtype), + return LLVMFunctionType(BACKEND_TYPE(decl->func.function_signature.rtype->type), params, param_size, decl->func.function_signature.variadic); } - - case DECL_VAR: - break; - case DECL_ENUM_CONSTANT: - break; case DECL_TYPEDEF: - break; + return BACKEND_TYPE(decl->typedef_decl.type); case DECL_STRUCT: { LLVMTypeRef *types = NULL; VECEACH(decl->strukt.members, i) { - VECADD(types, gencontext_get_llvm_type(context, decl->strukt.members[i]->var.type)); + VECADD(types, BACKEND_TYPE(decl->strukt.members[i]->type)); } - LLVMTypeRef type = LLVMStructCreateNamed(context->context, decl->name.string); + // TODO fix name. + LLVMTypeRef type = LLVMStructCreateNamed(LLVMCONTEXT(context), decl->name.string); LLVMStructSetBody(type, types, vec_size(types), decl->is_packed); return type; } case DECL_UNION: - break; + { + LLVMTypeRef max_type = NULL; + unsigned long long max_size = 0; + VECEACH(decl->strukt.members, i) + { + LLVMTypeRef type = BACKEND_TYPE(decl->strukt.members[i]->type); + unsigned long long size = LLVMStoreSizeOfType(target_data_layout(), type); + if (size > max_size || !max_type) + { + max_size = size; + max_type = type; + } + } + LLVMTypeRef type = LLVMStructCreateNamed(LLVMCONTEXT(context), decl->name.string); + LLVMStructSetBody(type, &max_type, 1, false); + return type; + } case DECL_ENUM: - break; + return BACKEND_TYPE(decl->type); case DECL_ERROR: - break; - case DECL_ERROR_CONSTANT: - break; - case DECL_ARRAY_VALUE: - break; - case DECL_IMPORT: - UNREACHABLE + if (!context->error_type) + { + LLVMTypeRef domain_type = LLVMInt64TypeInContext(LLVMCONTEXT(context)); + LLVMTypeRef pointer_type = BACKEND_TYPE(type_voidptr); + LLVMTypeRef error_type = LLVMStructCreateNamed(LLVMCONTEXT(context), "error"); + LLVMTypeRef types[2] = { domain_type, pointer_type }; + LLVMStructSetBody(error_type, types, 2, false); + context->error_type = error_type; + } + return context->error_type; } UNREACHABLE } static inline LLVMTypeRef gencontext_create_llvm_type_from_ptr(GenContext *context, Type *type) { - LLVMTypeRef base_llvm_type = gencontext_get_llvm_type(context, type->base); - - if (gencontext_use_debug(context)) - { - type->backend_debug_type = LLVMDIBuilderCreatePointerType(context->debug.builder, type->base->backend_debug_type, type_size(type->canonical->base), 0, 0, /* TODO */ "TODO", 4); - } + LLVMTypeRef base_llvm_type = BACKEND_TYPE(type->pointer); if (type->canonical != type) { - return type->backend_type = gencontext_get_llvm_type(context, type->canonical); + return type->backend_type = BACKEND_TYPE(type->canonical); } return type->backend_type = LLVMPointerType(base_llvm_type, /** TODO **/0); @@ -102,28 +100,12 @@ static inline LLVMTypeRef gencontext_create_llvm_type_from_ptr(GenContext *conte static inline LLVMTypeRef gencontext_create_llvm_type_from_array(GenContext *context, Type *type) { - LLVMTypeRef base_llvm_type = gencontext_get_llvm_type(context, type->base); + LLVMTypeRef base_llvm_type = BACKEND_TYPE(type->array.base); - if (gencontext_use_debug(context)) - { - LLVMMetadataRef *ranges = NULL; - Type *current_type = type; - while (current_type->canonical->type_kind == TYPE_ARRAY) - { - VECADD(ranges, LLVMDIBuilderGetOrCreateSubrange(context->debug.builder, 0, current_type->canonical->len)); - current_type = current_type->canonical->base; - } - type->backend_debug_type = LLVMDIBuilderCreateArrayType( - context->debug.builder, - type->len, - 0 /* ALIGN */, - type->base->backend_debug_type, - ranges, vec_size(ranges)); - } if (type->canonical != type) { - return type->backend_type = gencontext_get_llvm_type(context, type->canonical); + return type->backend_type = BACKEND_TYPE(type->canonical); } return type->backend_type = LLVMPointerType(base_llvm_type, /** TODO **/0); @@ -139,20 +121,27 @@ LLVMTypeRef gencontext_create_llvm_func_type(GenContext *context, Type *type) params = malloc_arena(sizeof(LLVMTypeRef) * vec_size(signature->params)); VECEACH(signature->params, i) { - params[i] = gencontext_get_llvm_type(context, signature->params[i]->var.type->canonical); + params[i] = BACKEND_TYPE(signature->params[i]->type->canonical); } } return LLVMFunctionType( - gencontext_get_llvm_type(context, type->func.signature->rtype), + BACKEND_TYPE(type->func.signature->rtype->type), params, vec_size(signature->params), signature->variadic); } + LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type) { if (type->backend_type) return type->backend_type; + DEBUG_LOG("Generating type %s", type->name); switch (type->type_kind) { - case TYPE_USER_DEFINED: + case TYPE_TYPEDEF: + return type->backend_type = BACKEND_TYPE(type->canonical); + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_ENUM: + case TYPE_ERROR: return type->backend_type = gencontext_create_llvm_type_from_decl(context, type->decl); case TYPE_FUNC: return type->backend_type = gencontext_create_llvm_func_type(context, type); @@ -172,17 +161,27 @@ LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type) case TYPE_U32: case TYPE_UXX: case TYPE_FXX: - case TYPE_EXPRESSION: - case TYPE_INC_ARRAY: UNREACHABLE; case TYPE_POINTER: return type->backend_type = gencontext_create_llvm_type_from_ptr(context, type); case TYPE_STRING: - TODO; + // TODO + return type->backend_type = LLVMPointerType(LLVMTYPE(type_char), 0); case TYPE_ARRAY: return type->backend_type = gencontext_create_llvm_type_from_array(context, type); + case TYPE_SUBARRAY: + { + LLVMTypeRef base_type = BACKEND_TYPE(type->array.base); + LLVMTypeRef size_type = BACKEND_TYPE(type_usize); + assert(type->array.base->canonical->type_kind == TYPE_POINTER); + LLVMTypeRef array_type = LLVMStructCreateNamed(LLVMCONTEXT(context), type->name); + LLVMTypeRef types[2] = { base_type, size_type }; + LLVMStructSetBody(array_type, types, 2, false); + return type->backend_type = array_type; + } case TYPE_VARARRAY: - TODO + return type->backend_type = LLVMPointerType(BACKEND_TYPE(type->array.base), 0); } UNREACHABLE; } + diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 1e0eaaa32..2600752a1 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -13,7 +13,7 @@ static Expr *parse_paren_expr(void); static Expr *parse_precedence(Precedence precedence); static Expr *parse_initializer_list(void); static Expr *parse_initializer(void); -static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr); +static bool parse_type_or_expr(Expr **exprPtr, TypeInfo **typePtr); static Decl *parse_top_level(void); typedef Expr *(*ParseFn)(Expr *); @@ -180,7 +180,7 @@ void error_at_current(const char* message, ...) #define TRY_AST_OR(_ast_stmt, _res) ({ Ast* _ast = (_ast_stmt); if (!ast_ok(_ast)) return _res; _ast; }) #define TRY_AST(_ast_stmt) TRY_AST_OR(_ast_stmt, &poisoned_ast) #define TRY_EXPR_OR(_expr_stmt, _res) ({ Expr* _expr = (_expr_stmt); if (!expr_ok(_expr)) return _res; _expr; }) -#define TRY_TYPE_OR(_type_stmt, _res) ({ Type* _type = (_type_stmt); if (!type_ok(_type)) return _res; _type; }) +#define TRY_TYPE_OR(_type_stmt, _res) ({ TypeInfo* _type = (_type_stmt); if (!type_info_ok(_type)) return _res; _type; }) #define TRY_DECL_OR(_decl_stmt, _res) ({ Decl* _decl = (_decl_stmt); if (!decl_ok(_decl)) return _res; _decl; }) #define COMMA_RPAREN_OR(_res) \ @@ -255,107 +255,113 @@ static Path *parse_path(void) * Assume prev_token is the type. * @return Type (poisoned if fails) */ -static inline Type *parse_base_type(void) +static inline TypeInfo *parse_base_type(void) { Path *path = parse_path(); if (path) { - Type *type = type_new(TYPE_USER_DEFINED); - type->unresolved.path = path; - type->name_loc = tok; - if (!consume_type_name("types")) return &poisoned_type; - return type; + TypeInfo *type_info = type_info_new(TYPE_INFO_IDENTIFIER); + type_info->unresolved.path = path; + type_info->unresolved.name_loc = tok; + if (!consume_type_name("types")) return &poisoned_type_info; + return type_info; } - Type *type; + TypeInfo *type_info = NULL; + Type *type_found = NULL; switch (tok.type) { case TOKEN_TYPE_IDENT: - type = TYPE_UNRESOLVED(tok); - break; + type_info = type_info_new(TYPE_INFO_IDENTIFIER); + type_info->unresolved.name_loc = tok; + break; case TOKEN_TYPE: + type_info = type_info_new(TYPE_INFO_IDENTIFIER); advance_and_verify(TOKEN_TYPE); - CONSUME_OR(TOKEN_LPAREN, &poisoned_type); - { - type = type_new(TYPE_EXPRESSION); - type->unresolved_type_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_type); - } - EXPECT_OR(TOKEN_RPAREN, &poisoned_type); + CONSUME_OR(TOKEN_LPAREN, &poisoned_type_info); + type_info->resolve_status = RESOLVE_NOT_DONE; + type_info->unresolved_type_expr = TRY_EXPR_OR(parse_initializer(), &poisoned_type_info); + EXPECT_OR(TOKEN_RPAREN, &poisoned_type_info); break; case TOKEN_VOID: - type = type_void; + type_found = type_void; break; case TOKEN_BOOL: - type = type_bool; + type_found = type_bool; break; case TOKEN_BYTE: - type = type_byte; + type_found = type_byte; break; case TOKEN_CHAR: - type = type_char; + type_found = type_char; break; case TOKEN_DOUBLE: - type = type_double; + type_found = type_double; break; case TOKEN_FLOAT: - type = type_float; + type_found = type_float; break; case TOKEN_INT: - type = type_int; + type_found = type_int; break; case TOKEN_ISIZE: - type = type_isize; + type_found = type_isize; break; case TOKEN_LONG: - type = type_long; + type_found = type_long; break; case TOKEN_SHORT: - type = type_short; + type_found = type_short; break; case TOKEN_UINT: - type = type_uint; + type_found = type_uint; break; case TOKEN_ULONG: - type = type_ulong; + type_found = type_ulong; break; case TOKEN_USHORT: - type = type_ushort; + type_found = type_ushort; break; case TOKEN_USIZE: - type = type_usize; + type_found = type_usize; break; case TOKEN_C_SHORT: - type = type_c_short; + type_found = type_c_short; break; case TOKEN_C_INT: - type = type_c_int; + type_found = type_c_int; break; case TOKEN_C_LONG: - type = type_c_long; + type_found = type_c_long; break; case TOKEN_C_LONGLONG: - type = type_c_longlong; + type_found = type_c_longlong; break; case TOKEN_C_USHORT: - type = type_c_ushort; + type_found = type_c_ushort; break; case TOKEN_C_UINT: - type = type_c_uint; + type_found = type_c_uint; break; case TOKEN_C_ULONG: - type = type_c_ulong; + type_found = type_c_ulong; break; case TOKEN_C_ULONGLONG: - type = type_c_ulonglong; + type_found = type_c_ulonglong; break; - default: SEMA_ERROR(tok, "A type name was expected here."); - type = &poisoned_type; - break; + return &poisoned_type_info; } advance(); - return type; + if (type_found) + { + assert(!type_info); + type_info = type_info_new(TYPE_INFO_IDENTIFIER); + type_info->resolve_status = RESOLVE_DONE; + type_info->type = type_found; + } + return type_info; } /** @@ -368,31 +374,29 @@ static inline Type *parse_base_type(void) * @param type the type to wrap, may not be poisoned. * @return type (poisoned if fails) */ -static inline Type *parse_array_type_index(Type *type) +static inline TypeInfo *parse_array_type_index(TypeInfo *type) { - - assert(type_ok(type)); + assert(type_info_ok(type)); advance_and_verify(TOKEN_LBRACKET); if (try_consume(TOKEN_PLUS)) { - 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; + CONSUME_OR(TOKEN_RBRACKET, &poisoned_type_info); + TypeInfo *incr_array = type_info_new(TYPE_INFO_INC_ARRAY); + incr_array->array.base = type; return incr_array; } if (try_consume(TOKEN_RBRACKET)) { - Type *array = type_new(TYPE_VARARRAY); - array->base = type; - array->len = 0; + TypeInfo *array = type_info_new(TYPE_INFO_ARRAY); + array->array.base = type; + array->array.len = NULL; return 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); + TypeInfo *array = type_info_new(TYPE_INFO_ARRAY); + array->array.base = type; + array->array.len = TRY_EXPR_OR(parse_expr(), &poisoned_type_info); + CONSUME_OR(TOKEN_RBRACKET, &poisoned_type_info); return array; } @@ -406,33 +410,33 @@ static inline Type *parse_array_type_index(Type *type) * Assume already stepped into. * @return Type, poisoned if parsing is invalid. */ -static Type *parse_type_expression(void) +static TypeInfo *parse_type_expression(void) { - Type *type = parse_base_type(); - while (type->type_kind != TYPE_POISONED) + TypeInfo *type_info = parse_base_type(); + while (type_info_ok(type_info)) { switch (tok.type) { case TOKEN_LBRACKET: - type = parse_array_type_index(type); + type_info = parse_array_type_index(type_info); break; case TOKEN_STAR: advance(); { - Type *ptr_type = type_new(TYPE_POINTER); - assert(type); - ptr_type->base = type; - type = ptr_type; + TypeInfo *ptr_type = type_info_new(TYPE_INFO_POINTER); + assert(type_info); + ptr_type->pointer = type_info; + type_info = ptr_type; } break; default: - return type; + return type_info; } } - return type; + return type_info; } -static inline Decl *parse_decl_after_type(bool local, Type *type) +static inline Decl *parse_decl_after_type(bool local, TypeInfo *type) { if (tok.type == TOKEN_LPAREN) { @@ -519,7 +523,8 @@ static Decl *parse_decl(void) bool constant = tok.type == TOKEN_CONST; if (local || constant) advance(); - Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); + TypeInfo *type_info = parse_type_expression(); + TypeInfo *type = TRY_TYPE_OR(type_info, &poisoned_decl); Decl *decl = TRY_DECL_OR(parse_decl_after_type(local, type), &poisoned_decl); @@ -599,7 +604,7 @@ static inline Ast *parse_expression_list(void) static inline bool parse_decl_expr_list(Ast ***stmt_list) { Expr *expr = NULL; - Type *type = NULL; + TypeInfo *type = NULL; if (!parse_type_or_expr(&expr, &type)) return false; @@ -735,7 +740,7 @@ static inline Ast* parse_catch_stmt(void) CONSUME_OR(TOKEN_LPAREN, &poisoned_ast); - Type *type = NULL; + TypeInfo *type = NULL; if (!try_consume(TOKEN_ERROR_TYPE)) { type = TRY_TYPE_OR(parse_type_expression(), &poisoned_ast); @@ -921,7 +926,7 @@ static inline Ast* parse_ct_switch_stmt(void) advance(); while (1) { - Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_ast); + TypeInfo *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_ast); vec_add(stmt->ct_case_stmt.types, type); if (!try_consume(TOKEN_COMMA)) break; } @@ -1117,7 +1122,7 @@ static inline bool is_expr_after_type_ident(void) return next_tok.type == TOKEN_DOT || next_tok.type == TOKEN_LPAREN; } -static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr) +static bool parse_type_or_expr(Expr **exprPtr, TypeInfo **typePtr) { switch (tok.type) { @@ -1147,7 +1152,7 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr) case TOKEN_TYPE_IDENT: if (next_tok.type == TOKEN_DOT || next_tok.type == TOKEN_LPAREN) break; *typePtr = parse_type_expression(); - return type_ok(*typePtr); + return type_info_ok(*typePtr); case TOKEN_IDENT: if (next_tok.type == TOKEN_SCOPE) { @@ -1159,7 +1164,7 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr) { lexer_restore_state(); *typePtr = parse_type_expression(); - return type_ok(*typePtr); + return type_info_ok(*typePtr); } lexer_restore_state(); } @@ -1170,12 +1175,12 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr) advance_and_verify(TOKEN_TYPE); CONSUME_OR(TOKEN_LPAREN, false); Expr* inner_expr = NULL; - Type* inner_type = NULL; + TypeInfo* inner_type = NULL; if (!parse_type_or_expr(&inner_expr, &inner_type)) return false; CONSUME_OR(TOKEN_RPAREN, false); if (inner_expr) { - *typePtr = type_new(TYPE_EXPRESSION); + *typePtr = type_info_new(TYPE_INFO_EXPRESSION); (**typePtr).unresolved_type_expr = inner_expr; return true; } @@ -1196,7 +1201,7 @@ static bool parse_type_or_expr(Expr **exprPtr, Type **typePtr) static inline Ast *parse_decl_or_expr_stmt(void) { Expr *expr = NULL; - Type *type = NULL; + TypeInfo *type = NULL; if (!parse_type_or_expr(&expr, &type)) return &poisoned_ast; @@ -1697,7 +1702,7 @@ static inline Decl *parse_const_declaration(Visibility visibility) else { if (!consume_const_name("constant")) return &poisoned_decl; - decl->var.type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); + decl->var.type_info = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); } CONSUME_OR(TOKEN_EQ, &poisoned_decl); @@ -1719,7 +1724,7 @@ static inline Decl *parse_const_declaration(Visibility visibility) */ static inline Decl *parse_global_declaration(Visibility visibility) { - Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); + TypeInfo *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); Decl *decl = decl_new_var(tok, type, VARDECL_GLOBAL, visibility); @@ -1820,13 +1825,13 @@ bool parse_struct_body(Decl *parent, Decl *visible_parent) { Token name_replacement = tok; name_replacement.string = NULL; - member = decl_new_user_defined_type(name_replacement, decl_kind, parent->visibility); + member = decl_new_with_type(name_replacement, decl_kind, parent->visibility); advance(); } else { advance(); - member = decl_new_user_defined_type(tok, decl_kind, parent->visibility); + member = decl_new_with_type(tok, decl_kind, parent->visibility); Decl *other = struct_find_name(visible_parent, tok.string); if (other) { @@ -1847,7 +1852,7 @@ bool parse_struct_body(Decl *parent, Decl *visible_parent) } continue; } - Type *type = TRY_TYPE_OR(parse_type_expression(), false); + TypeInfo *type = TRY_TYPE_OR(parse_type_expression(), false); while (1) { @@ -1890,7 +1895,7 @@ static inline Decl *parse_struct_declaration(Visibility visibility) Token name = tok; if (!consume_type_name(type_name)) return &poisoned_decl; - Decl *decl = decl_new_user_defined_type(name, decl_from_token(type), visibility); + Decl *decl = decl_new_with_type(name, decl_from_token(type), visibility); if (!parse_attributes(decl)) { @@ -1937,13 +1942,13 @@ static inline Ast *parse_generics_statements(void) static inline Decl *parse_generics_declaration(Visibility visibility) { advance_and_verify(TOKEN_GENERIC); - Type *rtype = NULL; + TypeInfo *rtype = NULL; if (tok.type != TOKEN_IDENT) { rtype = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); } Path *path = parse_path(); - Decl *decl = decl_new_user_defined_type(tok, DECL_GENERIC, visibility); + Decl *decl = decl_new_with_type(tok, DECL_GENERIC, visibility); decl->generic_decl.path = path; if (!consume_ident("generic function name")) return &poisoned_decl; decl->generic_decl.rtype = rtype; @@ -1968,10 +1973,10 @@ static inline Decl *parse_generics_declaration(Visibility visibility) { Ast *generic_case = AST_NEW(AST_GENERIC_CASE_STMT, tok); advance_and_verify(TOKEN_CASE); - Type **types = NULL; + TypeInfo **types = NULL; while (!try_consume(TOKEN_COLON)) { - Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); + TypeInfo *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); types = VECADD(types, type); if (!try_consume(TOKEN_COMMA) && tok.type != TOKEN_COLON) { @@ -2011,7 +2016,7 @@ static inline Decl *parse_generics_declaration(Visibility visibility) */ static inline bool parse_param_decl(Visibility parent_visibility, Decl*** parameters, bool type_only) { - Type *type = TRY_TYPE_OR(parse_type_expression(), false); + TypeInfo *type = TRY_TYPE_OR(parse_type_expression(), false); Decl *param = decl_new_var(tok, type, VARDECL_PARAM, parent_visibility); if (!try_consume(TOKEN_IDENT)) @@ -2217,8 +2222,8 @@ static inline bool parse_func_typedef(Decl *decl, Visibility visibility) { decl->typedef_decl.is_func = true; advance_and_verify(TOKEN_FUNC); - Type *type = TRY_TYPE_OR(parse_type_expression(), false); - decl->typedef_decl.function_signature.rtype = type; + TypeInfo *type_info = TRY_TYPE_OR(parse_type_expression(), false); + decl->typedef_decl.function_signature.rtype = type_info; if (!parse_opt_parameter_type_list(visibility, &(decl->typedef_decl.function_signature), true)) { return false; @@ -2229,19 +2234,20 @@ static inline bool parse_func_typedef(Decl *decl, Visibility visibility) static inline Decl *parse_typedef_declaration(Visibility visibility) { - Decl *decl = decl_new_user_defined_type(tok, DECL_TYPEDEF, visibility); advance_and_verify(TOKEN_TYPEDEF); + Decl *decl = decl_new_with_type(tok, DECL_TYPEDEF, visibility); if (tok.type == TOKEN_FUNC) { if (!parse_func_typedef(decl, visibility)) return &poisoned_decl; } else { - decl->typedef_decl.type = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); + decl->typedef_decl.type_info = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); decl->typedef_decl.is_func = false; } CONSUME_OR(TOKEN_AS, &poisoned_decl); decl->name = tok; + decl->type->name = tok.string; if (!consume_type_name("typedef")) return &poisoned_decl; CONSUME_OR(TOKEN_EOS, &poisoned_decl); return decl; @@ -2251,7 +2257,7 @@ static inline Decl *parse_macro_declaration(Visibility visibility) { advance_and_verify(TOKEN_MACRO); - Type *rtype = NULL; + TypeInfo *rtype = NULL; if (tok.type != TOKEN_AT_IDENT) { rtype = TRY_TYPE_OR(parse_type_expression(), &poisoned_decl); @@ -2265,7 +2271,7 @@ static inline Decl *parse_macro_declaration(Visibility visibility) Decl **params = NULL; while (!try_consume(TOKEN_RPAREN)) { - Type *parm_type = NULL; + TypeInfo *parm_type = NULL; TEST_TYPE: switch (tok.type) { @@ -2320,9 +2326,9 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa { advance_and_verify(TOKEN_FUNC); - Type *return_type = TRY_TYPE_OR(parse_type_expression(), false); + TypeInfo *return_type = TRY_TYPE_OR(parse_type_expression(), false); - Decl *func = decl_new_user_defined_type(tok, DECL_FUNC, visibility); + Decl *func = decl_new(DECL_FUNC, tok, visibility); func->func.function_signature.rtype = return_type; Path *path = parse_path(); @@ -2330,9 +2336,9 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa { // Special case, actually an extension TRY_EXPECT_OR(TOKEN_TYPE_IDENT, "A type was expected after '::'.", &poisoned_decl); - Type *type = type_new(TYPE_USER_DEFINED); + TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER); type->unresolved.path = path; - type->name_loc = tok; + type->unresolved.name_loc = tok; func->func.type_parent = type; advance_and_verify(TOKEN_TYPE_IDENT); @@ -2346,6 +2352,10 @@ static inline Decl *parse_func_definition(Visibility visibility, bool is_interfa if (!parse_opt_parameter_type_list(visibility, &(func->func.function_signature), is_interface)) return &poisoned_decl; if (!parse_opt_throw_declaration(&(func->func.function_signature))) return &poisoned_decl; + + // TODO remove + is_interface = tok.type == TOKEN_EOS; + if (is_interface) { if (tok.type == TOKEN_LBRACE) @@ -2375,7 +2385,7 @@ static inline Decl *parse_error_declaration(Visibility visibility) { advance_and_verify(TOKEN_ERROR_TYPE); - Decl *error_decl = decl_new_user_defined_type(tok, DECL_ERROR, visibility); + Decl *error_decl = decl_new_with_type(tok, DECL_ERROR, visibility); if (!consume_type_name("error type")) return &poisoned_decl; @@ -2424,11 +2434,11 @@ static inline Decl *parse_enum_declaration(Visibility visibility) { advance_and_verify(TOKEN_ENUM); - Decl *decl = decl_new_user_defined_type(tok, DECL_ENUM, visibility); + Decl *decl = decl_new_with_type(tok, DECL_ENUM, visibility); - if (!consume_type_name("enum")) return &poisoned_decl; + if (!consume_type_name("enum")) return &poisoned_decl; - Type *type = NULL; + TypeInfo *type = NULL; if (try_consume(TOKEN_COLON)) { type = TRY_TYPE_OR(parse_base_type(), &poisoned_decl); @@ -2436,7 +2446,7 @@ static inline Decl *parse_enum_declaration(Visibility visibility) CONSUME_OR(TOKEN_LBRACE, false); - decl->enums.type = type ? type : type_int; + decl->enums.type_info = type ? type : type_info_new_base(type_int); while (!try_consume(TOKEN_RBRACE)) { Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, tok, decl->visibility); @@ -2794,6 +2804,97 @@ static Expr *parse_access_expr(Expr *left) return access_expr; } +static int append_esc_string_token(char *restrict dest, const char *restrict src, size_t *pos) +{ + int scanned = 0; + uint64_t unicode_char = 0; + switch (src[0]) + { + case 'a': + dest[(*pos)++] = '\a'; + return 1; + case 'b': + dest[(*pos)++] = '\b'; + return 1; + case 'e': + dest[(*pos)++] = 0x1b; + return 1; + case 'f': + dest[(*pos)++] = '\f'; + return 1; + case 'n': + dest[(*pos)++] = '\n'; + return 1; + case 'r': + dest[(*pos)++] = '\r'; + return 1; + case 't': + dest[(*pos)++] = '\t'; + return 1; + case 'x': + { + int h = char_to_nibble(src[1]); + int l = char_to_nibble(src[2]); + if (h < 0 || l < 0) return -1; + unicode_char = ((unsigned) h << 4U) + l; + scanned = 3; + break; + } + case 'u': + { + int x1 = char_to_nibble(src[1]); + int x2 = char_to_nibble(src[2]); + int x3 = char_to_nibble(src[3]); + int x4 = char_to_nibble(src[4]); + if (x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0) return -1; + unicode_char = ((unsigned) x1 << 12U) + ((unsigned) x2 << 8U) + ((unsigned) x3 << 4U) + x4; + scanned = 5; + break; + } + case 'U': + { + int x1 = char_to_nibble(src[1]); + int x2 = char_to_nibble(src[2]); + int x3 = char_to_nibble(src[3]); + int x4 = char_to_nibble(src[4]); + int x5 = char_to_nibble(src[5]); + int x6 = char_to_nibble(src[6]); + int x7 = char_to_nibble(src[7]); + int x8 = char_to_nibble(src[8]); + if (x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || x5 < 0 || x6 < 0 || x7 < 0 || x8 < 0) return -1; + unicode_char = ((unsigned) x1 << 28U) + ((unsigned) x2 << 24U) + ((unsigned) x3 << 20U) + ((unsigned) x4 << 16U) + + ((unsigned) x5 << 12U) + ((unsigned) x6 << 8U) + ((unsigned) x7 << 4U) + x8; + scanned = 9; + break; + } + default: + dest[(*pos)++] = src[0]; + return 1; + } + if (unicode_char < 0x80U) + { + dest[(*pos)++] = (char)unicode_char; + } + else if (unicode_char < 0x800U) + { + dest[(*pos)++] = (char)(0xC0U | (unicode_char >> 6U)); + dest[(*pos)++] = (char)(0x80U | (unicode_char & 0x3FU)); + } + else if (unicode_char < 0x10000U) + { + dest[(*pos)++] = (char)(0xE0U | (unicode_char >> 12U)); + dest[(*pos)++] = (char)(0x80U | ((unicode_char >> 6U) & 0x3FU)); + dest[(*pos)++] = (char)(0x80U | (unicode_char & 0x3FU)); + } + else + { + dest[(*pos)++] = (char)(0xF0U | (unicode_char >> 18U)); + dest[(*pos)++] = (char)(0x80U | ((unicode_char >> 12U) & 0x3FU)); + dest[(*pos)++] = (char)(0x80U | ((unicode_char >> 6U) & 0x3FU)); + dest[(*pos)++] = (char)(0x80U | (unicode_char & 0x3FU)); + } + return scanned; +} static Expr *parse_string_literal(Expr *left) { @@ -2802,24 +2903,28 @@ static Expr *parse_string_literal(Expr *left) expr_string->resolve_status = RESOLVE_DONE; expr_string->type = type_string; - char *str = malloc_arena(tok.span.length + 1); - size_t len = tok.span.length; - - memcpy(str, tok.start, tok.span.length); - - // Just keep chaining if there are multiple parts. - - advance_and_verify(TOKEN_STRING); + char *str = NULL; + size_t len = 0; while (tok.type == TOKEN_STRING) { - char *new_string = malloc_arena(len + tok.span.length + 1); - memcpy(new_string, str, len); - memcpy(new_string + len, tok.start, tok.span.length); + char *new_string = malloc_arena(len + tok.span.length); + if (str) memcpy(new_string, str, len); str = new_string; - len += tok.span.length; - advance(); + for (unsigned i = 1; i < tok.span.length - 1; i++) + { + if (tok.string[i] == '\\') + { + i++; + i += append_esc_string_token(str, tok.string + i, &len) - 1; + continue; + } + str[len++] = tok.string[i]; + } + advance_and_verify(TOKEN_STRING); } + + assert(str); str[len] = '\0'; expr_string->const_expr.string.chars = str; expr_string->const_expr.string.len = len; @@ -2857,7 +2962,7 @@ static Expr *parse_integer(Expr *left) int hex = 0; for (int j = 0; j < 2; j++) { - hex <<= 4; + hex <<= 4U; char c = *(++string); if (c < 'A') { @@ -2933,7 +3038,7 @@ static Expr *parse_integer(Expr *left) { char c = *(string++); if (c == '_') continue; - if (i > (UINT64_MAX >> 3u)) + if (i > (UINT64_MAX >> 3U)) { SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number."); return &poisoned_expr; @@ -2948,7 +3053,7 @@ static Expr *parse_integer(Expr *left) { char c = *(string++); if (c == '_') continue; - if (i > (UINT64_MAX >> 1u)) + if (i > (UINT64_MAX >> 1U)) { SEMA_ERROR(tok, "Number is larger than an unsigned 64 bit number."); return &poisoned_expr; @@ -3078,7 +3183,7 @@ static Expr *parse_initializer(void) * @param type * @return Expr */ -static Expr *parse_type_access(Type *type) +static Expr *parse_type_access(TypeInfo *type) { Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPE_ACCESS, tok); expr->type_access.type = type; @@ -3119,8 +3224,9 @@ static Expr *parse_identifier(Expr *left) */ static Expr *parse_type_identifier_with_path(Path *path) { - Type *type = TYPE_UNRESOLVED(tok); + TypeInfo *type = type_info_new(TYPE_INFO_IDENTIFIER); type->unresolved.path = path; + type->unresolved.name_loc = tok; advance_and_verify(TOKEN_TYPE_IDENT); if (tok.type == TOKEN_LBRACE) { @@ -3169,7 +3275,7 @@ static Expr *parse_type_expr(Expr *left) Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPE, tok); advance_and_verify(TOKEN_TYPE); CONSUME_OR(TOKEN_LPAREN, &poisoned_expr); - Type *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_expr); + TypeInfo *type = TRY_TYPE_OR(parse_type_expression(), &poisoned_expr); CONSUME_OR(TOKEN_RPAREN, &poisoned_expr); expr->type_expr.type = type; return expr; @@ -3181,7 +3287,7 @@ static Expr *parse_cast_expr(Expr *left) 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); + expr->expr_cast.type_info = 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); diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 14aeed93e..dc4239be8 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -74,15 +74,14 @@ static inline void context_pop_scope(Context *context) -static bool sema_resolve_ptr_type(Context *context, Type *type) +static bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info) { - if (!sema_resolve_type_shallow(context, type->base)) + if (!sema_resolve_type_shallow(context, type_info->pointer)) { - type_poison(type); - return false; + return type_info_poison(type_info); } - type->canonical = type_get_canonical_ptr(type); - type->resolve_status = RESOLVE_DONE; + type_info->type = type_get_ptr(type_info->pointer->type); + type_info->resolve_status = RESOLVE_DONE; return true; } @@ -107,14 +106,20 @@ static void sema_release_defer_chain(Context *context, Ast ***statement_list) vec_resize(context->defers, start); } -static bool sema_resolve_array_type(Context *context, Type *type) +static bool sema_resolve_array_type(Context *context, TypeInfo *type) { - if (!sema_resolve_type(context, type->base)) + if (!sema_resolve_type_info(context, type->array.base)) { - type_poison(type); - return false; + return type_info_poison(type); } - type->canonical = type_get_canonical_array(type); + if (type->array.len) + { + if (!sema_analyse_expr(context, type->array.len)) return type_info_poison(type); + // Sema error on non const non positive integer. + TODO + } + assert(!type->array.len || type->array.len->expr_kind == EXPR_CONST); + type->type = type_get_array(type->array.base->type, type->array.len ? type->array.len->const_expr.i : 0); type->resolve_status = RESOLVE_DONE; return true; } @@ -147,12 +152,13 @@ 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->var.type)) + if (!sema_resolve_type_info(context, decl->var.type_info)) { decl_poison(decl); return false; } - assert(decl->var.type->canonical); + decl->type = decl->var.type_info->type; + assert(decl->var.type_info->type); return true; } @@ -189,10 +195,11 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo { assert(param->decl_kind == DECL_VAR); assert(param->var.kind == VARDECL_PARAM); - if (!sema_resolve_type(context, param->var.type)) + if (!sema_resolve_type_info(context, param->var.type_info)) { return false; } + param->type = param->var.type_info->type; if (param->var.init_expr && !is_function) { SEMA_ERROR(param->var.init_expr->loc, "Function types may not have default arguments."); @@ -207,7 +214,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo SEMA_ERROR(expr->loc, "Only constant expressions may be used as default values."); return false; } - if (!cast(expr, param->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + if (!cast(expr, param->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; } return true; } @@ -217,10 +224,10 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi char buffer[2048]; size_t buffer_write_offset = 0; bool all_ok = true; - all_ok = sema_resolve_type(context, signature->rtype) && all_ok; + all_ok = sema_resolve_type_info(context, signature->rtype) && all_ok; if (all_ok) { - type_append_signature_name(signature->rtype, buffer, &buffer_write_offset); + type_append_signature_name(signature->rtype->type, buffer, &buffer_write_offset); buffer[buffer_write_offset++] = '('; } // TODO check parameter name appearing more than once. @@ -240,7 +247,7 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi { buffer[buffer_write_offset++] = ','; } - type_append_signature_name(param->var.type, buffer, &buffer_write_offset); + type_append_signature_name(param->var.type_info->type, buffer, &buffer_write_offset); } // TODO variadic buffer[buffer_write_offset++] = ')'; @@ -263,9 +270,7 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi Type *func_type = stable_get(&context->local_symbols, signature->mangled_signature); if (!func_type) { - func_type = type_new(TYPE_FUNC); - func_type->name_loc = (Token) { .string = signature->mangled_signature, .span.length = buffer_write_offset }; - func_type->resolve_status = RESOLVE_DONE; + func_type = type_new(TYPE_FUNC, signature->mangled_signature); func_type->canonical = func_type; func_type->func.signature = signature; stable_set(&context->local_symbols, signature->mangled_signature, func_type); @@ -319,7 +324,7 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement) { assert(context->evaluating_macro); context->rtype = type_void; - context->active_function_for_analysis->func.function_signature.rtype = statement->return_stmt.expr->type; + context->active_function_for_analysis->func.function_signature.rtype->type->canonical = statement->return_stmt.expr->type->canonical; return true; } if (context->evaluating_macro && expected_rtype->canonical != return_expr->type->canonical) @@ -334,12 +339,13 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement) static inline bool sema_analyse_var_decl(Context *context, Decl *decl) { assert(decl->decl_kind == DECL_VAR); - if (!sema_resolve_type(context, decl->var.type)) return false; + if (!sema_resolve_type_info(context, decl->var.type_info)) return false; + decl->type = decl->var.type_info->type; if (decl->var.init_expr) { Type *prev_type = context->left_type_in_assignment; - context->left_type_in_assignment = decl->var.type; - bool success = sema_analyse_expr(context, decl->var.init_expr) && cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN); + context->left_type_in_assignment = decl->var.type_info->type; + bool success = sema_analyse_expr(context, decl->var.init_expr) && cast(decl->var.init_expr, decl->var.type_info->type, CAST_TYPE_IMPLICIT_ASSIGN); context->left_type_in_assignment = prev_type; if (!success) { @@ -373,7 +379,8 @@ static inline Expr *convert_decl_to_expr(Context *context, Decl *decl) assign_expr->binary_expr.left = identifier; assign_expr->binary_expr.right = decl->var.init_expr; assign_expr->binary_expr.operator = TOKEN_EQ; - identifier->type = decl->var.type; + // Possibly not right v TODO + identifier->type = decl->var.type_info->type; assign_expr->type = decl->var.init_expr->type; return assign_expr; } @@ -460,7 +467,7 @@ static inline bool decl_or_expr_to_expr_stmt(Context *context, Ast *stmt) Expr *identifier = expr_new(EXPR_IDENTIFIER, var->name); identifier->resolve_status = RESOLVE_DONE; identifier->identifier_expr.decl = var; - identifier->type = var->var.type; + identifier->type = var->var.type_info->type; assign_expr->binary_expr.left = identifier; assign_expr->binary_expr.right = var->var.init_expr; exprs = VECADD(exprs, assign_expr); @@ -873,7 +880,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement) context_push_scope_with_flags(context, SCOPE_BREAK | SCOPE_NEXT); // NOLINT(hicpp-signed-bitwise) Ast *body = statement->switch_stmt.body; assert(body->ast_kind == AST_COMPOUND_STMT); - Type *switch_type = cond->cond_stmt.expr->type; + Type *switch_type = cond->cond_stmt.expr->type->canonical; if (!type_is_integer(switch_type)) { SEMA_ERROR(cond->token, "Expected an integer or enum type, was '%s'.", type_to_error_string(switch_type)); @@ -959,13 +966,12 @@ bool sema_analyse_statement(Context *context, Ast *statement) static inline bool sema_analyse_function_body(Context *context, Decl *func) { context->active_function_for_analysis = func; - context->rtype = func->func.function_signature.rtype; + context->rtype = func->func.function_signature.rtype->type; context->current_scope = &context->scopes[0]; context->current_scope->local_decl_start = 0; context->labels = NULL; context->gotos = NULL; context->last_local = &context->locals[0]; - context->unique_index = 0; context->in_volatile_section = 0; func->func.annotations = CALLOCS(*func->func.annotations); context_push_scope(context); @@ -977,7 +983,7 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func) if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false; if (context->current_scope->exit != EXIT_RETURN) { - if (func->func.function_signature.rtype->canonical != type_void) + if (func->func.function_signature.rtype->type->canonical != type_void) { SEMA_ERROR(func->name, "Missing return statement at the end of the function."); return false; @@ -992,14 +998,14 @@ static inline bool sema_analyse_function_body(Context *context, Decl *func) static inline bool sema_analyse_method_function(Context *context, Decl *decl) { - Type *parent_type = decl->func.type_parent; - if (!sema_resolve_type(context, parent_type)) return false; - if (!type_may_have_method_functions(parent_type)) + TypeInfo *parent_type = decl->func.type_parent; + if (!sema_resolve_type_info(context, parent_type)) return false; + if (!type_may_have_method_functions(parent_type->type)) { - SEMA_ERROR(decl->name, "Method functions can not be associated with '%s'", type_to_error_string(decl->func.type_parent)); + SEMA_ERROR(decl->name, "Method functions can not be associated with '%s'", type_to_error_string(decl->func.type_parent->type)); return false; } - Decl *parent = parent_type->decl; + Decl *parent = parent_type->type->decl; VECEACH(parent->method_functions, i) { Decl *function = parent->method_functions[i]; @@ -1019,38 +1025,38 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) { DEBUG_LOG("Analysing function %s", decl->name.string); Type *func_type = sema_analyse_function_signature(context, &decl->func.function_signature, true); - decl->self_type = func_type; + decl->type = func_type; if (!func_type) return decl_poison(decl); if (decl->func.type_parent) { if (!sema_analyse_method_function(context, decl)) return decl_poison(decl); } - if (!sema_analyse_function_body(context, decl)) return decl_poison(decl); + if (decl->func.body && !sema_analyse_function_body(context, decl)) return decl_poison(decl); DEBUG_LOG("Function analysis done.") return true; } static inline bool sema_analyse_macro(Context *context, Decl *decl) { - Type *rtype = decl->macro_decl.rtype; - if (decl->macro_decl.rtype && !sema_resolve_type(context, rtype)) return false; + TypeInfo *rtype = decl->macro_decl.rtype; + if (decl->macro_decl.rtype && !sema_resolve_type_info(context, rtype)) return false; VECEACH(decl->macro_decl.parameters, i) { Decl *param = decl->macro_decl.parameters[i]; assert(param->decl_kind == DECL_VAR); assert(param->var.kind == VARDECL_PARAM); - if (param->var.type && !sema_resolve_type(context, param->var.type)) return false; + if (param->var.type_info && !sema_resolve_type_info(context, param->var.type_info)) return false; } return true; } static inline bool sema_analyse_global(Context *context, Decl *decl) { - if (!sema_resolve_type(context, decl->var.type)) return false; + if (!sema_resolve_type_info(context, decl->var.type_info)) return false; if (decl->var.init_expr) { if (!sema_analyse_expr(context, decl->var.init_expr)) return false; - if (!cast(decl->var.init_expr, decl->var.type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; + if (!cast(decl->var.init_expr, decl->var.type_info->type, CAST_TYPE_IMPLICIT_ASSIGN)) return false; if (decl->var.init_expr->expr_kind != EXPR_CONST) { SEMA_ERROR(decl->var.init_expr->loc, "The expression must be a constant value."); @@ -1076,11 +1082,11 @@ static inline bool sema_analyse_typedef(Context *context, Decl *decl) { Type *func_type = sema_analyse_function_signature(context, &decl->typedef_decl.function_signature, false); if (!func_type) return false; - decl->self_type->canonical = func_type; + decl->type->canonical = func_type; return true; } - if (!sema_resolve_type(context, decl->typedef_decl.type)) return false; - decl->self_type->canonical = decl->typedef_decl.type; + if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) return false; + decl->type->canonical = decl->typedef_decl.type_info->type; // Do we need anything else? return true; } @@ -1093,7 +1099,7 @@ static inline bool sema_analyse_generic(Context *context, Decl *decl) static inline bool sema_analyse_enum(Context *context, Decl *decl) { - if (!sema_resolve_type(context, decl->typedef_decl.type)) return false; + if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) return false; // TODO assign numbers to constants return true; } @@ -1104,7 +1110,7 @@ static inline bool sema_analyse_error(Context *context, Decl *decl) return true; } -static inline bool sema_analyse_decl(Context *context, Decl *decl) +bool sema_analyse_decl(Context *context, Decl *decl) { if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl); @@ -1249,47 +1255,20 @@ void sema_analysis_pass_decls(Context *context) } - -bool sema_resolve_type_shallow(Context *context, Type *type) +static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) { + assert(!type_info->unresolved.path && "TODO"); - 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.string); - type_poison(type); - return false; - } - - type->resolve_status = RESOLVE_RUNNING; - - switch (type->type_kind) - { - case TYPE_POISONED: - 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: - TODO - } - - Decl *decl = stable_get(&context->local_symbols, type->name_loc.string); + Decl *decl = stable_get(&context->local_symbols, type_info->unresolved.name_loc.string); if (!decl) { - decl = module_find_symbol(context->module, type->name_loc.string); + decl = module_find_symbol(context->module, type_info->unresolved.name_loc.string); } if (!decl) { - SEMA_ERROR(type->name_loc, "Unknown type '%s'.", type->name_loc.string); - type_poison(type); - return false; + SEMA_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", type_info->unresolved.name_loc.string); + return type_info_poison(type_info); } switch (decl->decl_kind) @@ -1298,27 +1277,23 @@ bool sema_resolve_type_shallow(Context *context, Type *type) 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); + type_info->type = decl->type; + type_info->resolve_status = RESOLVE_DONE; + DEBUG_LOG("Resolved %s.", type_info->unresolved.name_loc.string); return true; case DECL_TYPEDEF: // TODO func - if (!sema_resolve_type(context, decl->typedef_decl.type)) + if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) { decl_poison(decl); - type_poison(type); - return false; + return type_info_poison(type_info); } - type->decl = decl; - type->canonical = decl->typedef_decl.type->canonical; - type->resolve_status = RESOLVE_DONE; - DEBUG_LOG("Resolved %s.", type->name_loc.string); + DEBUG_LOG("Resolved %s.", type_info->unresolved.name_loc.string); + type_info->type = decl->type; + type_info->resolve_status = RESOLVE_DONE; return true; case DECL_POISONED: - type_poison(type); - return false; + return type_info_poison(type_info); case DECL_FUNC: case DECL_VAR: case DECL_ENUM_CONSTANT: @@ -1327,9 +1302,8 @@ bool sema_resolve_type_shallow(Context *context, Type *type) case DECL_IMPORT: case DECL_MACRO: case DECL_GENERIC: - SEMA_ERROR(type->name_loc, "This is not a type."); - type_poison(type); - return false; + SEMA_ERROR(type_info->unresolved.name_loc, "This is not a type."); + return type_info_poison(type_info); case DECL_MULTI_DECL: case DECL_CT_ELSE: case DECL_CT_IF: @@ -1338,14 +1312,44 @@ bool sema_resolve_type_shallow(Context *context, Type *type) UNREACHABLE } UNREACHABLE + +} +bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info) +{ + if (type_info->resolve_status == RESOLVE_DONE) return type_info_ok(type_info); + + if (type_info->resolve_status == RESOLVE_RUNNING) + { + // TODO this is incorrect for unresolved expressions + SEMA_ERROR(type_info->unresolved.name_loc, "Circular dependency resolving type '%s'.", type_info->unresolved.name_loc.string); + return type_info_poison(type_info); + } + + type_info->resolve_status = RESOLVE_RUNNING; + + switch (type_info->kind) + { + case TYPE_INFO_POISON: + case TYPE_INFO_INC_ARRAY: + UNREACHABLE + case TYPE_INFO_IDENTIFIER: + return sema_resolve_type_identifier(context, type_info); + case TYPE_INFO_EXPRESSION: + if (!sema_analyse_expr(context, type_info->unresolved_type_expr)) + { + return type_info_poison(type_info); + } + TODO + case TYPE_INFO_ARRAY: + return sema_resolve_array_type(context, type_info); + case TYPE_INFO_POINTER: + return sema_resolve_ptr_type(context, type_info); + } + } -bool sema_resolve_type(Context *context, Type *type) +bool sema_resolve_type_info(Context *context, TypeInfo *type_info) { - if (!sema_resolve_type_shallow(context, type)) return false; - if (type->type_kind == TYPE_USER_DEFINED) - { - if (!sema_analyse_decl(context, type->decl)) return false; - } + if (!sema_resolve_type_shallow(context, type_info)) return false; return true; } diff --git a/src/compiler/target.c b/src/compiler/target.c index e98e277c2..ae0ad82fe 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -94,6 +94,10 @@ void target_destroy() LLVMDisposeTargetMachine(target.machine); } +void *target_machine() +{ + return target.machine; +} void *target_data_layout() { return target.data_layout; diff --git a/src/compiler/types.c b/src/compiler/types.c index 75aad68f8..fdb5e0ed7 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -51,8 +51,9 @@ const char *type_to_error_string(Type *type) { case TYPE_POISONED: return "poisoned"; - case TYPE_USER_DEFINED: - return type->name_loc.string; + case TYPE_ENUM: + case TYPE_TYPEDEF: + case TYPE_STRUCT: case TYPE_VOID: case TYPE_BOOL: case TYPE_I8: @@ -69,30 +70,24 @@ const char *type_to_error_string(Type *type) case TYPE_F64: case TYPE_FXX: case TYPE_FUNC: - return type->name_loc.string; + case TYPE_UNION: + case TYPE_ERROR: + return type->name; case TYPE_POINTER: - asprintf(&buffer, "%s*", type_to_error_string(type->base)); + asprintf(&buffer, "%s*", type_to_error_string(type->pointer)); return buffer; case TYPE_STRING: return "string"; case TYPE_ARRAY: - if (type->resolve_status == RESOLVE_DONE) - { - asprintf(&buffer, "%s[%zu]", type_to_error_string(type->base), type->len); - } - else - { - asprintf(&buffer, "%s[]", type_to_error_string(type->base)); - } + asprintf(&buffer, "%s[%zu]", type_to_error_string(type->array.base), type->array.len); return buffer; case TYPE_VARARRAY: - asprintf(&buffer, "%s[]", type_to_error_string(type->base)); + asprintf(&buffer, "%s[]", type_to_error_string(type->array.base)); return buffer; - case TYPE_INC_ARRAY: - asprintf(&buffer, "%s[+]", type_to_error_string(type->base)); + case TYPE_SUBARRAY: + asprintf(&buffer, "%s[:]", type_to_error_string(type->array.base)); return buffer; - case TYPE_EXPRESSION: - return "type(...)"; + } } @@ -135,70 +130,11 @@ static void type_append_signature_name_user_defined(Decl *decl, char *dst, size_ void type_append_signature_name(Type *type, char *dst, size_t *offset) { assert(*offset < 2000); - assert(type->resolve_status == RESOLVE_DONE && type->canonical && type_ok(type)); - Type *canonical_type = type->canonical; - switch (type->type_kind) - { - case TYPE_POISONED: - UNREACHABLE - case TYPE_USER_DEFINED: - type_append_signature_name_user_defined(canonical_type->decl, dst, offset); - return; - 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: - case TYPE_FUNC: - memcpy(dst + *offset, type->name_loc.string, type->name_loc.span.length); - *offset += type->name_loc.span.length; - return; - case TYPE_POINTER: - type_append_signature_name(type->base, dst, offset); - return; - case TYPE_STRING: - TODO - return; - case TYPE_ARRAY: - type_append_signature_name(type->base, dst, offset); - { - int len = sprintf(dst + *offset, "[%zu]", type->len); - *offset += len; - } - return; - case TYPE_VARARRAY: - type_append_signature_name(type->base, dst, offset); - dst[*offset++] = '['; - dst[*offset] = ']'; - *offset += 1; - return; - case TYPE_INC_ARRAY: - TODO - return; - case TYPE_EXPRESSION: - UNREACHABLE - } + memcpy(dst + *offset, type->name, strlen(type->name)); + *offset += strlen(type->name); } -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) { @@ -206,10 +142,12 @@ size_t type_size(Type *canonical) switch (canonical->type_kind) { case TYPE_POISONED: - case TYPE_INC_ARRAY: - case TYPE_EXPRESSION: UNREACHABLE; - case TYPE_USER_DEFINED: + case TYPE_ENUM: + case TYPE_TYPEDEF: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_ERROR: TODO case TYPE_VOID: return 1; @@ -235,99 +173,132 @@ size_t type_size(Type *canonical) case TYPE_STRING: return t_usz.canonical->builtin.bytesize; case TYPE_ARRAY: - return type_size(canonical->base) * canonical->len; + return type_size(canonical->array.base) * canonical->array.len; + case TYPE_SUBARRAY: + TODO } TODO } -static inline void create_ptr_live_canonical(Type *canonical_type) +static inline void create_ptr_cache(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_cache = VECADD(canonical_type->ptr_cache, NULL); + canonical_type->ptr_cache = VECADD(canonical_type->ptr_cache, NULL); } -Type *type_get_canonical_ptr(Type *ptr_type) +static Type *type_generate_ptr(Type *ptr_type, bool canonical) { - Type *canonical_base = ptr_type->base->canonical; - - assert(canonical_base); - - if (!canonical_base->ptr_like_canonical) + if (canonical) ptr_type = ptr_type->canonical; + if (!ptr_type->ptr_cache) { - create_ptr_live_canonical(canonical_base); + create_ptr_cache(ptr_type); } - Type *canonical_ptr = canonical_base->ptr_like_canonical[0]; - if (canonical_ptr == NULL) + Type *ptr = ptr_type->ptr_cache[0]; + if (ptr == NULL) { - canonical_ptr = malloc_arena(sizeof(Type)); - *canonical_ptr = *ptr_type; - canonical_ptr->base = canonical_base; - canonical_ptr->canonical = canonical_ptr; - canonical_ptr->resolve_status = RESOLVE_DONE; - canonical_base->ptr_like_canonical[0] = canonical_ptr; - canonical_base->resolve_status = RESOLVE_DONE; + ptr = type_new(TYPE_POINTER, strformat("%s*", ptr_type->name)); + ptr->pointer = ptr_type; + ptr_type->ptr_cache[0] = ptr; + if (ptr_type == ptr_type->canonical) + { + ptr->canonical = ptr; + } + else + { + ptr->canonical = type_generate_ptr(ptr_type->canonical, true); + } } - - return canonical_ptr; + return ptr; } -Type *type_get_canonical_array(Type *arr_type) +Type *type_get_ptr(Type *ptr_type) { - Type *canonical_base = arr_type->base->canonical; - if (!arr_type->ptr_like_canonical) + return type_generate_ptr(ptr_type, false); +} + + +Type *type_create_array(Type *arr_type, uint64_t len, bool canonical) +{ + if (canonical) arr_type = arr_type->canonical; + if (!arr_type->ptr_cache) { - create_ptr_live_canonical(canonical_base); + create_ptr_cache(arr_type); } // Dynamic array - if (arr_type->len == 0) + if (len == 0) { - Type *canonical = canonical_base->ptr_like_canonical[1]; - if (canonical == NULL) + Type *array = arr_type->ptr_cache[1]; + if (array == NULL) { - canonical = malloc_arena(sizeof(Type)); - *canonical = *arr_type; - canonical->canonical = canonical_base; - canonical_base->ptr_like_canonical[1] = canonical; - canonical->resolve_status = RESOLVE_DONE; + array = type_new(TYPE_VARARRAY, strformat("%s[]", arr_type->name)); + array->array.base = arr_type; + array->array.len = 0; + if (arr_type->canonical == arr_type) + { + array->canonical = array; + } + else + { + array->canonical = type_create_array(arr_type, len, true); + } + arr_type->ptr_cache[1] = array; } - return canonical; + return array; } - int entries = (int)vec_size(canonical_base->ptr_like_canonical); + int entries = (int)vec_size(arr_type->ptr_cache); for (int i = 1; i < entries; i++) { - Type *ptr = canonical_base->ptr_like_canonical[i]; - if (ptr->len == arr_type->len) + Type *ptr = arr_type->ptr_cache[i]; + if (ptr->array.len == arr_type->array.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; + Type *array = type_new(TYPE_ARRAY, strformat("%s[%llu]", arr_type->name, len)); + array->array.base = arr_type; + array->array.len = 0; + if (arr_type->canonical == arr_type) + { + array->canonical = array; + } + else + { + array->canonical = type_create_array(arr_type, len, true); + } + VECADD(arr_type->ptr_cache, array); + return array; +} + +Type *type_get_array(Type *arr_type, uint64_t len) +{ + return type_create_array(arr_type, len, false); } static void type_create(const char *name, Type *location, Type **ptr, 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 = (Type) { + .type_kind = kind, + .builtin.bytesize = bytesize, + .builtin.bitsize = bitsize, + .name = name, + .canonical = location + }; + location->name = name; location->canonical = location; *ptr = location; } static void type_create_alias(const char *name, Type *location, Type **ptr, 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; + *location = (Type) { + .type_kind = TYPE_TYPEDEF, + .name = name, + .canonical = canonical + }; *ptr = location; } @@ -336,10 +307,10 @@ void builtin_setup() { type_create("void", &t_u0, &type_void, TYPE_VOID, 1, 8); type_create("string", &t_str, &type_string, TYPE_STRING, build_options.pointer_size, build_options.pointer_size * 8); - create_ptr_live_canonical(type_void); - type_void->ptr_like_canonical[0] = &t_voidstar; + create_ptr_cache(type_void); + type_void->ptr_cache[0] = &t_voidstar; type_create("void*", &t_voidstar, &type_voidptr, TYPE_POINTER, 0, 0); - t_voidstar.base = type_void; + t_voidstar.pointer = type_void; /*TODO * decl_string = (Decl) { .decl_kind = DECL_BUILTIN, .name.string = "string" }; @@ -380,7 +351,6 @@ type_create(#_name, &_shortname, &type_ ## _name, _type, (_bits + 7) / 8, _bits) type_create_alias("c_long", &t_cl, &type_c_long, type_signed_int_by_size(build_options.clong_size)); type_create_alias("c_longlong", &t_cll, &type_c_longlong, type_signed_int_by_size(build_options.clonglong_size)); - #undef DEF_TYPE } @@ -397,7 +367,7 @@ bool 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 (type->decl->decl_kind != DECL_STRUCT) return false; if (!possible_subtype->decl->strukt.members) return false; @@ -405,21 +375,18 @@ bool type_is_subtype(Type *type, Type *possible_subtype) if (first_element->decl_kind != DECL_VAR) return false; - return type_is_subtype(type, first_element->var.type->canonical); + return type_is_subtype(type, first_element->type->canonical); } bool type_may_have_method_functions(Type *type) { // An alias is not ok. - if (type->type_kind != TYPE_USER_DEFINED) return false; - Decl *decl = type->decl; - switch (decl->decl_kind) + switch (type->type_kind) { - case DECL_UNION: - case DECL_STRUCT: - case DECL_ERROR: - case DECL_ENUM: + case TYPE_UNION: + case TYPE_STRUCT: + case TYPE_ENUM: return true; default: return false; diff --git a/src/utils/errors.h b/src/utils/errors.h index c01da83fe..e6c56845c 100644 --- a/src/utils/errors.h +++ b/src/utils/errors.h @@ -11,7 +11,7 @@ void evprintf(const char *format, va_list list); void eprintf(const char *format, ...); void error_exit(const char *format, ...) __attribute__((noreturn)); -#define FATAL_ERROR(_string, ...) do { error_exit("FATAL ERROR at %s:%d: " _string, __func__, __LINE__, ##__VA_ARGS__); } while(0) +#define FATAL_ERROR(_string, ...) do { error_exit("FATAL ERROR at %s:%d in %s: " _string, __func__, __LINE__, __FILE__, ##__VA_ARGS__); } while(0) #define ASSERT(_condition, _string, ...) while (!(_condition)) { FATAL_ERROR(_string, ##__VA_ARGS__); } diff --git a/src/utils/lib.h b/src/utils/lib.h index f83c88ec2..d11b48c3a 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -100,6 +100,19 @@ static inline bool is_digit(char c) return c >= '0' && c <= '9'; } +/** + * Convert hex character to nibble + * @param c + * @return value or -1 if invalid. + */ +static inline int char_to_nibble(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c <= 'F') return c - 'A'; + if (c <= 'f') return c - 'f'; + return -1; +} + static inline bool is_hex_or_(char c) { switch (c)