mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Added some codegen & .o generation and (hopefully correct) optimization. Hacked strings in together with i++/i--. Fixed up parsing of strings supporting \u \U \x => UTF8
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,13 @@
|
||||
#include <llvm-c/Target.h>
|
||||
#include <llvm-c/Analysis.h>
|
||||
#include <llvm-c/BitWriter.h>
|
||||
#include <llvm-c/DebugInfo.h>
|
||||
#include <llvm-c/Transforms/PassManagerBuilder.h>
|
||||
#include <llvm-c/Transforms/InstCombine.h>
|
||||
#include <llvm-c/Transforms/Vectorize.h>
|
||||
#include <llvm-c/Transforms/Scalar.h>
|
||||
#include <llvm-c/Transforms/IPO.h>
|
||||
#include <llvm-c/Transforms/Utils.h>
|
||||
#include <llvm-c/DebugInfo.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,10 @@ void target_destroy()
|
||||
LLVMDisposeTargetMachine(target.machine);
|
||||
}
|
||||
|
||||
void *target_machine()
|
||||
{
|
||||
return target.machine;
|
||||
}
|
||||
void *target_data_layout()
|
||||
{
|
||||
return target.data_layout;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__); }
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user