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:
Christoffer Lerno
2019-11-21 11:15:03 +01:00
parent 990918b609
commit aee3f99ea7
25 changed files with 1595 additions and 1851 deletions

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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);
break;
case TYPE_USER_DEFINED:
if (type->resolve_status == RESOLVE_DONE)
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)
{
if (type->decl != type->canonical->decl)
{
fprintf(file, "(user-defined %s::%s\n", type->decl->module->name, type->decl->name.string);
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;
}
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;
}
break;
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;
}
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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
};
} 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;
TypeUnresolved unresolved;
Expr *unresolved_type_expr;
struct {
Type *base;
TypeArray array;
TypeFunc func;
Type *pointer;
};
};
struct _TypeInfo
{
ResolveStatus resolve_status : 2;
Type *type;
TypeInfoKind kind;
union
{
Expr *unresolved_len;
size_t len;
};
};
TypeFunc func;
TypeUnresolved unresolved;
Expr *unresolved_type_expr;
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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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,
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
}

View File

@@ -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,
{
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,
false);
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:

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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);
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;
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);

View File

@@ -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);
}
bool sema_resolve_type(Context *context, Type *type)
type_info->resolve_status = RESOLVE_RUNNING;
switch (type_info->kind)
{
if (!sema_resolve_type_shallow(context, type)) return false;
if (type->type_kind == TYPE_USER_DEFINED)
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))
{
if (!sema_analyse_decl(context, type->decl)) return false;
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_info(Context *context, TypeInfo *type_info)
{
if (!sema_resolve_type_shallow(context, type_info)) return false;
return true;
}

View File

@@ -94,6 +94,10 @@ void target_destroy()
LLVMDisposeTargetMachine(target.machine);
}
void *target_machine()
{
return target.machine;
}
void *target_data_layout()
{
return target.data_layout;

View File

@@ -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 ptr;
}
return canonical_ptr;
Type *type_get_ptr(Type *ptr_type)
{
return type_generate_ptr(ptr_type, false);
}
Type *type_get_canonical_array(Type *arr_type)
Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
{
Type *canonical_base = arr_type->base->canonical;
if (!arr_type->ptr_like_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;
}
return canonical;
else
{
array->canonical = type_create_array(arr_type, len, true);
}
arr_type->ptr_cache[1] = array;
}
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;

View File

@@ -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__); }

View File

@@ -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)