Started work on ranges. Added weak/noreturn/inline/cname/stdcall/section/alignment attributes. Some work on subarrays. Fixes to throws. Function pointers work.

This commit is contained in:
Christoffer Lerno
2020-05-20 14:22:22 +02:00
parent a160bfc352
commit b2bfd87a06
27 changed files with 1105 additions and 513 deletions

View File

@@ -70,7 +70,7 @@ add_executable(c3c
src/compiler/context.c
src/compiler/sema_expr.c
src/compiler/enums.h
src/compiler/casts.c
src/compiler/sema_casts.c
src/compiler/target.c
src/compiler/compiler.h
src/compiler/types.c

View File

@@ -18,24 +18,28 @@ C3 tries to be an alternative in the the C/C++ niche: fast and close to the meta
### Current status
Most work is still being done in the design draft here: https://c3lang.github.io/c3docs/. If you have suggestions, send a mail to [christoffer@aegik.com](mailto:christoffer@aegik.com), [file an issue](https://github.com/c3lang/c3c/issues) or discuss C3 on the r/ProgrammingLanguages Discord server: https://discord.gg/cfu4wdk
It's possible to try out the current C3 compiler in the browser: https://ide.judge0.com/?1EFo this is courtesy of the
developer of Judge0.
Design work is still being done in the design draft here: https://c3lang.github.io/c3docs/. If you have suggestions, send a mail to [christoffer@aegik.com](mailto:christoffer@aegik.com), [file an issue](https://github.com/c3lang/c3c/issues) or discuss C3 on the r/ProgrammingLanguages Discord server: https://discord.gg/cfu4wdk
There are some small work being done on the parser here, but most of the structure is still missing:
#### What's missing in the parser
- `asm` sections.
- bitstructs
- array range initializers e.g. `{ [1..2] = 2 }`
- assert/$assert as keywords
- Docs not linked to statements/functions/declarations.
#### What's missing in the semantic analyser
- Incomplete handling of imports.
- `next` not correct
- Function signatures incomplete.
- Function typedef not done.
- `asm` not done.
- `generic` not analysed.
- `attribute` not analysed.
- `$switch` and `$for` not handled.
- Enums not correctly handled.
- Type resolution not complete for all types.

View File

@@ -2,10 +2,10 @@ Things missing:
* Attributes
- All types: @noreflect, @deprecated
- Struct: @packed, @aligned, @opaque
- Struct: @packed, @opaque
- Enums: @distinct, @noreflect
- Unions: @packed, @aligned, @opaque
- Functions: @inline, @reflect, @noreturn, @section, @unused, @used, @interrupt, @naked, @convention()
- Unions: @packed, @opaque
- Functions: @reflect, @noreturn, @unused, @used, @interrupt, @naked, @convention()
- Calls: @noinline, @inline
- Variables, parameters: @unused
- Constants, globals: @unused, @used, @section
@@ -62,6 +62,7 @@ Things missing:
- C ABI
- Safe varargs
- Malloc/free
- Check that structs are transferred the right way.
* Pre-post conditions
- Breakdown here

View File

@@ -372,6 +372,7 @@ label_statement
labeled_statement
: label_statement
| CASE constant_expression ':'
| CASE constant_expression ELLIPSIS constant_expression ':'
| DEFAULT ':'
;

View File

@@ -659,11 +659,7 @@ func int testThrow(int x) throws Err
return x * x;
}
func int testThrowAny(int x) throws
{
if (x < 0) throw Err.TEST_ERR1;
return x * x;
}
func int oekt() throws
{
@@ -671,9 +667,46 @@ func int oekt() throws
printf("Skipped.\n");
NEXT:
int x = try testThrow(-3);
catch (error e)
{
printf("An error %p\n", cast(e, usize));
throw e;
}
return x;
}
errset Xan
{
EE,
FF,
DD,
}
func int testThrowAny(int x) throws
{
if (x < 0) throw Err.TEST_ERR1;
return x * x;
}
func void testErrorBug()
{
printf("Test error multi\n");
{
printf("Will call\n");
try oekt();
}
catch (Err e)
{
printf("Expected particular error.\n");
}
catch (error e)
{
error foo = Err.TEST_ERR1;
printf("Not expected %p != %p\n", cast(e, usize), cast(foo, usize));
printf("Unexpected any error error.\n");
}
printf("End\n");
}
func void testErrorMulti()
{
defer printf("End defer\n");
@@ -692,6 +725,8 @@ func void testErrorMulti()
catch (error e)
{
defer printf("Left any error\n");
error foo = Err.TEST_ERR1;
printf("Not expected %p != %p\n", cast(e, usize), cast(foo, usize));
printf("Unexpected any error error.\n");
}
printf("End\n");
@@ -771,15 +806,50 @@ func void testErrors()
printf("Throws: %d\n", throwsDone.times);
printf("End of errors\n");
}
macro void arrayCallMacro($x)
{
printf("Array call: %d, %d\n", $x[0], $x[1]);
}
typedef func int(int) as IntInt;
func int funcTest(int i)
{
return i * i;
}
func void testFuncPointer()
{
IntInt bobd = &funcTest;
int x = bobd(2);
printf("Func test: %d\n", x);
printf("Func test: %d\n", bobd(100));
}
func void arrayCall(int[2] x) @inline @weak @align(16) @cname("Foo")
{
printf("Array call: %d, %d\n", x[0], x[1]);
}
func void testArray()
{
int[4] zebra = { [2] = 1 };
int[4] deok = { 1, 2, 3, 4 };
int[4] deok = { 1, 5, 9, 16 };
int[] sa = &deok;
int* sp = sa;
WithArray boo;
boo.x[0] = 2;
printf("boo.x[0] = %d\n", boo.x[0]);
printf("boo.x[2] = %d\n", boo.x[2]);
printf("sa[2] = %d\n", sa[2]);
printf("sa[3] = %d\n", sa[3]);
deok[2] = 100;
sa[1] = 999;
printf("sa[2] = %d\n", sa[2]);
printf("sp[2] = %d\n", sp[2]);
printf("deok[1] = %d\n", deok[1]);
int[2] two = { 142, 2 };
arrayCall(two);
//@arrayCallMacro(two);
int[4] x;
x[1] = 1;
x[0] = 3;
@@ -838,10 +908,38 @@ func void testType()
typeid structSize = typeof(b);
}
struct Big
{
long x;
long y;
long z;
}
func Big testStructReturn()
{
return Big { 1, 2, 3};
}
func void testExprBlock()
{
printf("ExprBlock\n");
int x = ({
int y = 1;
for (int i = 0; i < 100; i++)
{
printf("%d\n", i);
if (y % 3 == 0 && y % 2 == 0) return y;
y++;
}
return 100;
});
printf("Was %d\n", x);
}
func int main(int x)
{
printf("Helo!\n");
testErrorBug();
testErrors();
testDefault(y = 99);
testPointers(2, 3);
@@ -851,6 +949,8 @@ func int main(int x)
testSimpleStruct(0);
testUnion();
testType();
testExprBlock();
testFuncPointer();
int efd = 9;
uint fefoek = 1;
printf("Helo: %d\n", efd + cast(fefoek, int));

View File

@@ -428,6 +428,16 @@ void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent)
}
DUMPF("(unresolved %s)", type_info->unresolved.name_loc.string);
break;
case TYPE_INFO_VARARRAY:
DUMP("(vararray");
DUMPTI(type_info->array.base);
DUMPE();
break;
case TYPE_INFO_SUBARRAY:
DUMP("(subarray");
DUMPTI(type_info->array.base);
DUMPE();
break;
case TYPE_INFO_ARRAY:
DUMP("(unresolved-array");
DUMPTI(type_info->array.base);
@@ -435,7 +445,7 @@ void fprint_type_info_recursive(FILE *file, TypeInfo *type_info, int indent)
DUMPE();
break;
case TYPE_INFO_POINTER:
DUMP("pointer");
DUMP("(pointer");
DUMPTI(type_info->pointer);
DUMPE();
break;
@@ -821,7 +831,6 @@ void fprint_decl_recursive(FILE *file, Decl *decl, int indent)
DUMPEND();
case DECL_IMPORT:
DUMPF("(import %s", decl->name);
// TODO
DUMPEND();
case DECL_ATTRIBUTE:

View File

@@ -19,9 +19,11 @@ typedef uint32_t SourceLoc;
#define MAX_SCOPE_DEPTH 0xFF
#define MAX_PATH 1024
#define MAX_DEFERS 0xFFFF
#define MAX_MACRO_NESTING 1024
#define MAX_FUNCTION_SIGNATURE_SIZE 2048
#define MAX_PARAMS 512
#define MAX_ERRORS 0xFFFF
#define MAX_ALIGNMENT (1U << 29U)
typedef struct _Ast Ast;
typedef struct _Decl Decl;
@@ -226,6 +228,7 @@ typedef struct
union
{
Expr *expr;
uint32_t alignment;
};
} Attr;
@@ -261,7 +264,6 @@ typedef struct _VarDecl
Expr *init_expr;
Decl *parent;
};
void *backend_ref;
void *backend_debug_ref;
} VarDecl;
@@ -301,6 +303,7 @@ typedef enum
ERROR_RETURN_MANY = 2,
ERROR_RETURN_ANY = 3,
} ErrorReturn;
typedef struct _FunctionSignature
{
CallConvention convention : 4;
@@ -322,18 +325,27 @@ typedef struct
typedef struct
{
struct
{
bool attr_weak : 1;
bool attr_noreturn : 1;
bool attr_inline : 1;
bool attr_noinline : 1;
bool attr_cname : 1;
bool attr_stdcall : 1;
};
TypeInfo *type_parent;
FunctionSignature function_signature;
Ast *body;
FuncAnnotations *annotations;
Decl **locals;
Ast **labels;
void *backend_value;
} FuncDecl;
typedef struct
{
AttributeDomains domains;
AttributeDomain domains;
FunctionSignature attr_signature;
} AttrDecl;
@@ -378,7 +390,11 @@ typedef struct _Decl
Visibility visibility : 2;
ResolveStatus resolve_status : 2;
bool is_packed : 1;
/* bool is_exported : 1;
void *ref;
const char *cname;
uint32_t alignment;
const char *section;
/* bool is_exported : 1;
bool is_used : 1;
bool is_used_public : 1;
bool has_cname : 1;
@@ -523,6 +539,7 @@ typedef struct
typedef struct
{
bool is_struct_function : 1;
bool is_pointer_call : 1;
Expr *function;
Expr **arguments;
ThrowInfo *throw_info;
@@ -963,6 +980,14 @@ typedef struct _Context
};
Type *rtype;
int in_volatile_section;
struct
{
bool in_macro_call : 1;
bool in_macro : 1;
int macro_counter;
int macro_nesting;
Expr *first_macro_call;
};
Decl *locals[MAX_LOCALS];
DynamicScope scopes[MAX_SCOPE_DEPTH];
char path_scratch[MAX_PATH];
@@ -1014,8 +1039,9 @@ extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
extern Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
extern Type *type_typeid, *type_error_union, *type_error_base;
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
extern const char *main_name;
extern const char *main_kw;
#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, _token.span)
#define AST_NEW(_kind, _loc) new_ast(_kind, _loc)
@@ -1257,6 +1283,8 @@ static inline Token wrap(const char *string)
}
Type *type_get_ptr(Type *ptr_type);
Type *type_get_subarray(Type *arr_type);
Type *type_get_vararray(Type *arr_type);
Type *type_get_meta(Type *meta_type);
Type *type_get_indexed_type(Type *type);
Type *type_get_array(Type *arr_type, uint64_t len);

View File

@@ -189,8 +189,7 @@ bool context_add_import(Context *context, Path *path, Token token, Token alias)
}
vec_add(context->imports, import);
printf("Added import %s\n", path->module);
DEBUG_LOG("Added import %s\n", path->module);
return true;
}

View File

@@ -138,6 +138,8 @@ typedef enum
CAST_UIUI,
CAST_UIFP,
CAST_ENUMSI,
CAST_APTSA,
CAST_SAPTR,
/*
CAST_NONE,
CAST_INLINE,
@@ -242,9 +244,10 @@ typedef enum
typedef enum
{
PREC_NONE,
PREC_ASSIGNMENT, // =, *=, /=, %=, ...
PREC_ASSIGNMENT, // =, *=, /=, %=, +=, etc
PREC_TRY, // try
PREC_TERNARY, // ?:
PREC_RANGE, // ...
PREC_LOGICAL, // && ||
PREC_RELATIONAL, // < > <= >= == !=
PREC_ADDITIVE, // + -
@@ -279,6 +282,8 @@ typedef enum
TYPE_INFO_EXPRESSION,
TYPE_INFO_ARRAY,
TYPE_INFO_INC_ARRAY,
TYPE_INFO_VARARRAY,
TYPE_INFO_SUBARRAY,
TYPE_INFO_POINTER,
} TypeInfoKind;
@@ -345,7 +350,7 @@ typedef enum
TOKEN_SHL, // <<
// Three or more
TOKEN_ELIPSIS, // ...
TOKEN_ELLIPSIS, // ...
TOKEN_MINUS_MOD_ASSIGN, // -%=
TOKEN_MULT_MOD_ASSIGN, // *%=
TOKEN_PLUS_MOD_ASSIGN, // +%=
@@ -561,7 +566,23 @@ typedef enum
ATTR_CONST = 1 << 5,
ATTR_ERROR = 1 << 6,
ATTR_TYPEDEF = 1 << 7
} AttributeDomains;
} AttributeDomain;
typedef enum
{
ATTRIBUTE_INLINE,
ATTRIBUTE_NOINLINE,
ATTRIBUTE_STDCALL,
ATTRIBUTE_OPAQUE,
ATTRIBUTE_NORETURN,
ATTRIBUTE_SECTION,
ATTRIBUTE_CNAME,
ATTRIBUTE_WEAK,
ATTRIBUTE_ALIGN,
ATTRIBUTE_PACKED,
NUMBER_OF_ATTRIBUTES = ATTRIBUTE_PACKED + 1,
ATTRIBUTE_NONE,
} AttributeType;
typedef enum
{

View File

@@ -333,7 +333,7 @@ static inline Token scan_hex(Lexer *lexer)
}
while (is_hex_or_(peek(lexer))) next(lexer);
bool is_float = false;
if (peek(lexer) == '.')
if (peek(lexer) == '.' && peek_next(lexer) != '.')
{
is_float = true;
next(lexer);
@@ -360,7 +360,7 @@ static inline Token scan_dec(Lexer *lexer)
{
while (is_digit_or_(peek(lexer))) next(lexer);
bool is_float = false;
if (peek(lexer) == '.')
if (peek(lexer) == '.' && peek_next(lexer) != '.')
{
is_float = true;
next(lexer);
@@ -495,7 +495,7 @@ Token lexer_scan_token(Lexer *lexer)
case '#':
return make_token(lexer, TOKEN_HASH, "#");
case '$':
return scan_ident(lexer, TOKEN_CT_TYPE_IDENT, TOKEN_CT_CONST_IDENT, TOKEN_CT_TYPE_IDENT, '$');
return scan_ident(lexer, TOKEN_CT_IDENT, TOKEN_CT_CONST_IDENT, TOKEN_CT_TYPE_IDENT, '$');
case ',':
return make_token(lexer, TOKEN_COMMA, ",");
case ';':
@@ -513,7 +513,7 @@ Token lexer_scan_token(Lexer *lexer)
case ']':
return make_token(lexer, TOKEN_RBRACKET, "]");
case '.':
if (match(lexer, '.')) return match(lexer, '.') ? make_token(lexer, TOKEN_ELIPSIS, "...") : make_token(lexer, TOKEN_DOTDOT, "..");
if (match(lexer, '.')) return match(lexer, '.') ? make_token(lexer, TOKEN_ELLIPSIS, "...") : make_token(lexer, TOKEN_DOTDOT, "..");
return make_token(lexer, TOKEN_DOT, ".");
case '~':
return make_token(lexer, TOKEN_BIT_NOT, "~");

View File

@@ -66,29 +66,29 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl
assert(decl->var.kind == VARDECL_GLOBAL);
// TODO fix name
decl->var.backend_ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->name);
decl->ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->name);
if (decl->var.init_expr)
{
LLVMSetInitializer(decl->var.backend_ref, gencontext_emit_expr(context, decl->var.init_expr));
LLVMSetInitializer(decl->ref, gencontext_emit_expr(context, decl->var.init_expr));
}
else
{
LLVMSetInitializer(decl->var.backend_ref, LLVMConstInt(llvm_type(type_bool), 0, false));
LLVMSetInitializer(decl->ref, LLVMConstInt(llvm_type(type_bool), 0, false));
}
// If read only: LLVMSetGlobalConstant(decl->var.backend_ref, 1);
switch (decl->visibility)
{
case VISIBLE_MODULE:
LLVMSetVisibility(decl->var.backend_ref, LLVMProtectedVisibility);
LLVMSetVisibility(decl->ref, LLVMProtectedVisibility);
break;
case VISIBLE_PUBLIC:
LLVMSetVisibility(decl->var.backend_ref, LLVMDefaultVisibility);
LLVMSetVisibility(decl->ref, LLVMDefaultVisibility);
break;
case VISIBLE_EXTERN:
case VISIBLE_LOCAL:
LLVMSetVisibility(decl->var.backend_ref, LLVMHiddenVisibility);
LLVMSetVisibility(decl->ref, LLVMHiddenVisibility);
break;
}
@@ -212,6 +212,8 @@ unsigned nounwind_attribute;
unsigned writeonly_attribute;
unsigned readonly_attribute;
unsigned optnone_attribute;
unsigned noalias_attribute;
unsigned sret_attribute;
void llvm_codegen_setup()
{
@@ -232,7 +234,8 @@ void llvm_codegen_setup()
writeonly_attribute = lookup_attribute("writeonly");
readonly_attribute = lookup_attribute("readonly");
optnone_attribute = lookup_attribute("optnone");
sret_attribute = lookup_attribute("sret");
noalias_attribute = lookup_attribute("noalias");
intrinsics_setup = true;
}
@@ -248,14 +251,14 @@ void gencontext_emit_struct_decl(GenContext *context, Decl *decl)
switch (decl->visibility)
{
case VISIBLE_MODULE:
LLVMSetVisibility(decl->var.backend_ref, LLVMProtectedVisibility);
LLVMSetVisibility(global_name, LLVMProtectedVisibility);
break;
case VISIBLE_PUBLIC:
LLVMSetVisibility(decl->var.backend_ref, LLVMDefaultVisibility);
LLVMSetVisibility(global_name, LLVMDefaultVisibility);
break;
case VISIBLE_EXTERN:
case VISIBLE_LOCAL:
LLVMSetVisibility(decl->var.backend_ref, LLVMHiddenVisibility);
LLVMSetVisibility(global_name, LLVMHiddenVisibility);
break;
}
}
@@ -278,13 +281,14 @@ void gencontext_emit_error_decl(GenContext *context, Decl *decl)
LLVMTypeRef reserved_type = LLVMArrayType(llvm_type(type_char), slots);
char *buffer = strcat_arena(decl->external_name, "_DOMAIN");
LLVMValueRef global_name = LLVMAddGlobal(context->module, reserved_type, buffer);
LLVMSetLinkage(global_name, LLVMInternalLinkage);
LLVMSetLinkage(global_name, LLVMExternalLinkage);
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, llvm_int(type_char, 1));
decl->error.start_value = global_name;
LLVMSetInitializer(global_name, LLVMConstAllOnes(reserved_type));
decl->error.start_value = LLVMBuildPtrToInt(context->builder, global_name, llvm_type(type_usize), "");
uint32_t min_align = upper_power_of_two(slots);
uint32_t pointer_align = type_abi_alignment(type_voidptr);
LLVMSetAlignment(global_name, pointer_align > min_align ? pointer_align : min_align);
LLVMSetVisibility(global_name, LLVMDefaultVisibility);
switch (decl->visibility)
{
case VISIBLE_MODULE:
@@ -422,8 +426,9 @@ void llvm_codegen(Context *context)
gencontext_destroy(&gen_context);
}
void gencontext_add_attribute(GenContext context, unsigned attribute_id, LLVMValueRef value_to_add_attribute_to)
void
gencontext_add_attribute(GenContext *context, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index)
{
LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(context.context, attribute_id, 0);
LLVMAddAttributeAtIndex(value_to_add_attribute_to, -1, llvm_attr);
LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(context->context, attribute_id, 0);
LLVMAddAttributeAtIndex(value_to_add_attribute_to, index, llvm_attr);
}

View File

@@ -76,6 +76,7 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
{
Expr *parent = expr->subscript_expr.expr;
Expr *index = expr->subscript_expr.index;
if (index->expr_kind == EXPR_RANGE) TODO;
LLVMValueRef index_value = gencontext_emit_expr(context, index);
LLVMValueRef parent_value;
Type *type = parent->type->canonical;
@@ -99,8 +100,19 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
llvm_type(type),
parent_value, indices, 2, "arridx");
}
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
{
// TODO insert trap on overflow.
LLVMTypeRef subarray_type = llvm_type(type);
parent_value = gencontext_emit_address(context, expr->subscript_expr.expr);
LLVMValueRef pointer_addr = LLVMBuildStructGEP2(context->builder, subarray_type, parent_value, 0, "");
LLVMTypeRef pointer_type = llvm_type(type_get_ptr(type->array.base));
LLVMValueRef pointer = LLVMBuildLoad2(context->builder, pointer_type, pointer_addr, "");
return LLVMBuildInBoundsGEP2(context->builder,
llvm_type(type->array.base),
pointer, &index_value, 1, "sarridx");
}
case TYPE_VARARRAY:
case TYPE_STRING:
TODO
default:
@@ -175,7 +187,7 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
UNREACHABLE
case EXPR_IDENTIFIER:
return expr->identifier_expr.decl->var.backend_ref;
return expr->identifier_expr.decl->ref;
case EXPR_UNARY:
assert(expr->unary_expr.operator == UNARYOP_DEREF);
return gencontext_emit_expr(context, expr->unary_expr.expr);
@@ -211,12 +223,26 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
static inline LLVMValueRef gencontext_emit_error_cast(GenContext *context, LLVMValueRef value, Type *type)
{
LLVMValueRef global = type->decl->error.start_value;
LLVMValueRef val = LLVMBuildBitCast(context->builder, global, llvm_type(type_usize), "");
LLVMValueRef extend = LLVMBuildZExtOrBitCast(context->builder, value, llvm_type(type_usize), "");
return LLVMBuildAdd(context->builder, val, extend, "");
return LLVMBuildAdd(context->builder, global, extend, "");
}
LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMValueRef value, Type *type, Type *target_type)
LLVMValueRef gencontext_emit_arr_to_subarray_cast(GenContext *context, LLVMValueRef value, Type *to_type, Type *from_type)
{
size_t size = from_type->pointer->array.len;
LLVMTypeRef subarray_type = llvm_type(to_type);
LLVMValueRef result = LLVMGetUndef(subarray_type);
value = gencontext_emit_bitcast(context, value, type_get_ptr(from_type->pointer->array.base));
result = LLVMBuildInsertValue(context->builder, result, value, 0, "");
return LLVMBuildInsertValue(context->builder, result, llvm_int(type_usize, size), 1, "");
}
LLVMValueRef gencontext_emit_subarray_to_ptr_cast(GenContext *context, LLVMValueRef value, Type *to_type, Type *from_type)
{
return LLVMBuildExtractValue(context->builder, value, 0, "");
}
LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMValueRef value, Type *to_type, Type *from_type)
{
switch (cast_kind)
{
@@ -226,9 +252,13 @@ LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMV
case CAST_ERROR:
UNREACHABLE
case CAST_PTRPTR:
return LLVMBuildPointerCast(context->builder, value, llvm_type(type), "ptrptr");
return LLVMBuildPointerCast(context->builder, value, llvm_type(to_type), "ptrptr");
case CAST_PTRXI:
return LLVMBuildPtrToInt(context->builder, value, llvm_type(type), "ptrxi");
return LLVMBuildPtrToInt(context->builder, value, llvm_type(to_type), "ptrxi");
case CAST_APTSA:
return gencontext_emit_arr_to_subarray_cast(context, value, to_type, from_type);
case CAST_SAPTR:
return gencontext_emit_subarray_to_ptr_cast(context, value, to_type, from_type);
case CAST_VARRPTR:
TODO
case CAST_ARRPTR:
@@ -236,51 +266,51 @@ LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMV
case CAST_STRPTR:
TODO
case CAST_ERREU:
return gencontext_emit_error_cast(context, value, target_type);
return gencontext_emit_error_cast(context, value, from_type);
case CAST_EUERR:
TODO
case CAST_EUBOOL:
return LLVMBuildICmp(context->builder, LLVMIntNE, value, llvm_int(type_usize, 0), "eubool");
case CAST_PTRBOOL:
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstPointerNull(llvm_type(type->canonical->pointer)), "ptrbool");
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstPointerNull(llvm_type(to_type->canonical->pointer)), "ptrbool");
case CAST_BOOLINT:
return LLVMBuildTrunc(context->builder, value, llvm_type(type), "boolsi");
return LLVMBuildTrunc(context->builder, value, llvm_type(to_type), "boolsi");
case CAST_FPBOOL:
return LLVMBuildFCmp(context->builder, LLVMRealUNE, value, LLVMConstNull(LLVMTypeOf(value)), "fpbool");
case CAST_BOOLFP:
return LLVMBuildSIToFP(context->builder, value, llvm_type(type), "boolfp");
return LLVMBuildSIToFP(context->builder, value, llvm_type(to_type), "boolfp");
case CAST_INTBOOL:
return LLVMBuildICmp(context->builder, LLVMIntNE, value, LLVMConstNull(LLVMTypeOf(value)), "intbool");
case CAST_FPFP:
return type_convert_will_trunc(type, target_type)
? LLVMBuildFPTrunc(context->builder, value, llvm_type(type), "fpfptrunc")
: LLVMBuildFPExt(context->builder, value, llvm_type(type), "fpfpext");
return type_convert_will_trunc(to_type, from_type)
? LLVMBuildFPTrunc(context->builder, value, llvm_type(to_type), "fpfptrunc")
: LLVMBuildFPExt(context->builder, value, llvm_type(to_type), "fpfpext");
case CAST_FPSI:
return LLVMBuildFPToSI(context->builder, value, llvm_type(type), "fpsi");
return LLVMBuildFPToSI(context->builder, value, llvm_type(to_type), "fpsi");
case CAST_FPUI:
return LLVMBuildFPToUI(context->builder, value, llvm_type(type), "fpui");
return LLVMBuildFPToUI(context->builder, value, llvm_type(to_type), "fpui");
case CAST_SISI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "sisitrunc")
: LLVMBuildSExt(context->builder, value, llvm_type(type), "sisiext");
return type_convert_will_trunc(to_type, from_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(to_type), "sisitrunc")
: LLVMBuildSExt(context->builder, value, llvm_type(to_type), "sisiext");
case CAST_SIUI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "siuitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(type), "siuiext");
return type_convert_will_trunc(to_type, from_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(to_type), "siuitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(to_type), "siuiext");
case CAST_SIFP:
return LLVMBuildSIToFP(context->builder, value, llvm_type(type), "sifp");
return LLVMBuildSIToFP(context->builder, value, llvm_type(to_type), "sifp");
case CAST_XIPTR:
return LLVMBuildIntToPtr(context->builder, value, llvm_type(type), "xiptr");
return LLVMBuildIntToPtr(context->builder, value, llvm_type(to_type), "xiptr");
case CAST_UISI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "uisitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(type), "uisiext");
return type_convert_will_trunc(to_type, from_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(to_type), "uisitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(to_type), "uisiext");
case CAST_UIUI:
return type_convert_will_trunc(type, target_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(type), "uiuitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(type), "uiuiext");
return type_convert_will_trunc(to_type, from_type)
? LLVMBuildTrunc(context->builder, value, llvm_type(to_type), "uiuitrunc")
: LLVMBuildZExt(context->builder, value, llvm_type(to_type), "uiuiext");
case CAST_UIFP:
return LLVMBuildUIToFP(context->builder, value, llvm_type(type), "uifp");
return LLVMBuildUIToFP(context->builder, value, llvm_type(to_type), "uifp");
case CAST_ENUMSI:
TODO
}
@@ -834,12 +864,14 @@ LLVMValueRef gencontext_emit_try_expr(GenContext *context, Expr *expr)
if (expr->try_expr.type == TRY_EXPR_ELSE_JUMP)
{
LLVMBasicBlockRef else_block = gencontext_get_try_target(context, expr);
LLVMValueRef val = gencontext_emit_expr(context, expr->try_expr.expr);
LLVMBasicBlockRef after_catch = gencontext_create_free_block(context, "aftercatch");
gencontext_emit_br(context, after_catch);
gencontext_emit_block(context, else_block);
gencontext_emit_stmt(context, expr->try_expr.else_stmt);
gencontext_emit_br(context, after_catch);
gencontext_emit_block(context, after_catch);
return val;
}
return gencontext_emit_expr(context, expr->try_expr.expr);
}
@@ -953,7 +985,7 @@ LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
return llvm_int(type, expr->const_expr.b ? 1 : 0);
case TYPE_STRING:
{
LLVMValueRef global_name = LLVMAddGlobal(context->module, llvm_type(type), "string");
LLVMValueRef global_name = LLVMAddGlobal(context->module, LLVMArrayType(llvm_type(type_char), expr->const_expr.string.len + 1), "");
LLVMSetLinkage(global_name, LLVMInternalLinkage);
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, LLVMConstStringInContext(context->context,
@@ -1024,113 +1056,6 @@ static inline void gencontext_emit_throw_union_branch(GenContext *context, Catch
*/
static inline bool gencontext_emit_throw_branch_for_single_throw_catch(GenContext *context, Decl *throw, LLVMValueRef value, Ast *catch, bool single_throw)
{
gencontext_generate_catch_block_if_needed(context, catch);
// Catch any is simple.
if (catch->catch_stmt.error_param->type == type_error_union)
{
// If this was a single throw, then we do a cast first.
if (single_throw)
{
value = gencontext_emit_cast(context, CAST_ERREU, value, type_error_union, throw->type);
}
// Store the value and jump to the catch.
LLVMBuildStore(context->builder, value, catch->catch_stmt.error_param->var.backend_ref);
gencontext_emit_br(context, catch->catch_stmt.block);
return true;
}
// If we catch a single, the single throw is easy, it *must* be the same type.
if (single_throw)
{
assert(catch->catch_stmt.error_param->type->decl == throw);
// Store and jump.
LLVMBuildStore(context->builder, value, catch->catch_stmt.error_param->var.backend_ref);
gencontext_emit_br(context, catch->catch_stmt.block);
return true;
}
// Here instead we more than one throw and we're catching a single error type
LLVMValueRef offset = LLVMBuildBitCast(context->builder, catch->catch_stmt.error_param->type->decl->error.start_value, llvm_type(type_error_union), "");
LLVMValueRef check = LLVMBuildAnd(context->builder, offset, value, "");
LLVMValueRef match = LLVMBuildICmp(context->builder, LLVMIntEQ, offset, check, "");
LLVMBasicBlockRef catch_block_set = gencontext_create_free_block(context, "setval");
LLVMBasicBlockRef continue_block = gencontext_create_free_block(context, "");
gencontext_emit_cond_br(context, match, catch_block_set, continue_block);
value = LLVMBuildAnd(context->builder, LLVMBuildNeg(context->builder, offset, ""), value, "");
LLVMBuildStore(context->builder, value, catch->catch_stmt.error_param->var.backend_ref);
gencontext_emit_br(context, catch->catch_stmt.block);
gencontext_emit_block(context, continue_block);
return false;
}
static inline bool gencontext_emit_throw_branch_for_single_throw(GenContext *context, Decl *throw, LLVMValueRef value, CatchInfo *catch_infos, bool single_throw, bool union_return)
{
TODO
/*
VECEACH(catch_infos, i)
{
CatchInfo *info = &catch_infos[i];
switch (info->kind)
{
case CATCH_REGULAR:
if (gencontext_emit_throw_branch_for_single_throw_catch(context, throw, value, info->catch, single_throw))
{
// Catching all should only happen on the last branch.
assert(i == vec_size(catch_infos));
return true;
}
break;;
case CATCH_TRY_ELSE:
// Try else should only happen on the last branch.
assert(i == vec_size(catch_infos));
gencontext_emit_br(context, info->try_else->try_expr.jump_target);
return true;
}
}*/
// If this is not a single throw, then we need to check first.
if (!single_throw)
{
LLVMValueRef offset = LLVMBuildBitCast(context->builder, throw->error.start_value, llvm_type(type_error_union), "");
LLVMValueRef check = LLVMBuildAnd(context->builder, offset, value, "");
LLVMValueRef match = LLVMBuildICmp(context->builder, LLVMIntEQ, offset, check, "");
LLVMBasicBlockRef catch_block_set = gencontext_create_free_block(context, "setval");
LLVMBasicBlockRef continue_block = gencontext_create_free_block(context, "");
gencontext_emit_cond_br(context, match, catch_block_set, continue_block);
value = LLVMBuildAnd(context->builder, LLVMBuildNeg(context->builder, offset, ""), value, "");
//LLVMBuildStore(context->builder, value, catch->catch_stmt.error_param->var.backend_ref);
//gencontext_emit_br(context, catch->catch_stmt.block);
gencontext_emit_block(context, continue_block);
}
// Case (1) the error return is a normal return, in that case we send the unadorned type.
/* if (union_return)
{
assert(error_type == type_error_base);
gencontext_emit_cond_br(context, comparison, return_block, after_block);
gencontext_emit_block(context, return_block);
gencontext_emit_return_value(context, value);
gencontext_emit_block(context, after_block);
return;
}
assert(context->cur_func_decl->func.function_signature.error_return == ERROR_RETURN_UNION);
if (error_type == type_error_base)
{
value = gencontext_emit_cast(context, CAST_EREU, value, cuf, error_type)
gencontext_emit_cast_expr
return false;
*/
return false;
}
static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRef value, TypeInfo** errors, ThrowInfo *throw_info, ErrorReturn error_return)
@@ -1231,7 +1156,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
value = gencontext_emit_cast(context, CAST_ERREU, value, type_error_union, errors[0]->type);
}
}
LLVMBuildStore(context->builder, value, error_param->var.backend_ref);
LLVMBuildStore(context->builder, value, error_param->ref);
gencontext_emit_defer(context, throw_info->defer, catch->defer);
gencontext_emit_br(context, catch->catch->catch_stmt.block);
gencontext_emit_block(context, after_block);
@@ -1263,8 +1188,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
{
// This is always the last catch, so we can assume that we have the correct error
// type already.
LLVMValueRef offset = LLVMBuildBitCast(context->builder, catch->error->error.start_value, llvm_type(type_error_union), "");
LLVMValueRef negated = LLVMBuildNeg(context->builder, offset, "");
LLVMValueRef negated = LLVMBuildNeg(context->builder, catch->error->error.start_value, "");
LLVMValueRef final_value = LLVMBuildAnd(context->builder, negated, value, "");
gencontext_emit_defer(context, throw_info->defer, NULL);
gencontext_emit_return_value(context, final_value);
@@ -1294,15 +1218,15 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
}
case CATCH_REGULAR:
{
Decl *param = catch->catch->catch_stmt.error_param;
gencontext_generate_catch_block_if_needed(context, catch->catch);
Decl *error_param = catch->catch->catch_stmt.error_param;
Type *error_type = error_param->type->canonical;
// The wildcard catch is always the last one.
if (param->type == type_error_union)
if (error_type == type_error_union)
{
// Store the value, then jump
LLVMBuildStore(context->builder, value, error_param->var.backend_ref);
LLVMBuildStore(context->builder, value, error_param->ref);
gencontext_emit_defer(context, throw_info->defer, catch->defer);
gencontext_emit_br(context, catch->catch->catch_stmt.block);
gencontext_emit_block(context, after_block);
@@ -1312,21 +1236,19 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
// Here we have a normal catch.
// Find the offset.
LLVMValueRef offset = LLVMBuildBitCast(context->builder, param->type->decl->error.start_value, llvm_type(type_error_union), "");
// wrapping(value - offset) < entries + 1 this handles both cases since wrapping will make
// values below the offset big.
LLVMValueRef comp_value = LLVMBuildSub(context->builder, value, offset, "");
LLVMValueRef entries_value = llvm_int(type_error_union, vec_size(param->type->decl->error.error_constants) + 1);
LLVMValueRef match = LLVMBuildICmp(context->builder, LLVMIntULT, comp_value, entries_value, "matcherr");
Decl *error_decl = error_type->decl;
LLVMValueRef comp_value = LLVMBuildSub(context->builder, value, error_decl->error.start_value, "");
LLVMValueRef entries_value = llvm_int(type_error_union, vec_size(error_decl->error.error_constants) + 1);
LLVMValueRef match = LLVMBuildICmp(context->builder, LLVMIntULT, comp_value, entries_value, "regmatch");
LLVMBasicBlockRef match_block = gencontext_create_free_block(context, "match");
gencontext_emit_cond_br(context, match, match_block, err_handling_block);
gencontext_emit_block(context, match_block);
gencontext_emit_defer(context, throw_info->defer, catch->defer);
LLVMBuildStore(context->builder, comp_value, error_param->var.backend_ref);
LLVMBuildStore(context->builder, comp_value, error_param->ref);
gencontext_emit_br(context, catch->catch->catch_stmt.block);
gencontext_emit_block(context, err_handling_block);
err_handling_block = NULL;
@@ -1341,8 +1263,25 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)
{
size_t args = vec_size(expr->call_expr.arguments);
Decl *function_decl = expr->call_expr.function->identifier_expr.decl;
FunctionSignature *signature = &function_decl->func.function_signature;
FunctionSignature *signature;
LLVMValueRef func;
LLVMTypeRef func_type;
if (expr->call_expr.is_pointer_call)
{
signature = expr->call_expr.function->type->canonical->pointer->func.signature;
func = gencontext_emit_expr(context, expr->call_expr.function);
func_type = llvm_type(expr->call_expr.function->type->canonical->pointer);
}
else
{
Decl *function_decl = expr->call_expr.function->identifier_expr.decl;
signature = &function_decl->func.function_signature;
func = function_decl->ref;
func_type = llvm_type(function_decl->type);
}
LLVMValueRef return_param = NULL;
if (signature->return_param)
{
@@ -1360,13 +1299,9 @@ LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)
values[param_index++] = gencontext_emit_expr(context, expr->call_expr.arguments[i]);
}
Decl *function = expr->call_expr.function->identifier_expr.decl;
LLVMValueRef func = function->func.backend_value;
LLVMTypeRef func_type = llvm_type(function->type);
LLVMValueRef call = LLVMBuildCall2(context->builder, func_type, func, values, args, "call");
gencontext_emit_throw_branch(context, call, function->func.function_signature.throws, expr->call_expr.throw_info, signature->error_return);
gencontext_emit_throw_branch(context, call, signature->throws, expr->call_expr.throw_info, signature->error_return);
// If we used a return param, then load that info here.
if (return_param)
@@ -1423,7 +1358,7 @@ static inline LLVMValueRef gencontext_emit_expr_block(GenContext *context, Expr
context->return_out = old_ret_out;
context->expr_block_exit = saved_expr_block;
return return_out;
return return_out ? gencontext_emit_load(context, expr->type, return_out) : NULL;
}
LLVMValueRef gencontext_emit_call_intrinsic(GenContext *context, unsigned intrinsic_id, LLVMTypeRef *types,
@@ -1457,7 +1392,6 @@ NESTED_RETRY:
switch (expr->expr_kind)
{
case EXPR_RANGE:
TODO
case EXPR_POISONED:
UNREACHABLE
case EXPR_DESIGNATED_INITIALIZER:

View File

@@ -4,10 +4,7 @@
#include "llvm_codegen_internal.h"
#include "bigint.h"
bool gencontext_check_block_branch_emit(GenContext *context)
{
@@ -78,8 +75,8 @@ static inline void gencontext_emit_parameter(GenContext *context, Decl *decl, un
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_PARAM);
// Allocate room on stack and copy.
decl->var.backend_ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
LLVMBuildStore(context->builder, LLVMGetParam(context->function, index), decl->var.backend_ref);
decl->ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
LLVMBuildStore(context->builder, LLVMGetParam(context->function, index), decl->ref);
}
void gencontext_emit_implicit_return(GenContext *context)
@@ -103,12 +100,12 @@ void gencontext_emit_implicit_return(GenContext *context)
void gencontext_emit_function_body(GenContext *context, Decl *decl)
{
DEBUG_LOG("Generating function %s.", decl->external_name);
assert(decl->func.backend_value);
assert(decl->ref);
LLVMValueRef prev_function = context->function;
LLVMBuilderRef prev_builder = context->builder;
context->function = decl->func.backend_value;
context->function = decl->ref;
context->cur_func_decl = decl;
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(context->context, context->function, "entry");
@@ -182,22 +179,61 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl)
{
assert(decl->decl_kind == DECL_FUNC);
// Resolve function backend type for function.
decl->func.backend_value = LLVMAddFunction(context->module, decl->external_name,
llvm_type(decl->type));
// Specify appropriate storage class, visibility and call convention
// extern functions (linkedited in separately):
/*
if (glofn->flags & FlagSystem) {
LLVMSetFunctionCallConv(glofn->llvmvar, LLVMX86StdcallCallConv);
LLVMSetDLLStorageClass(glofn->llvmvar, LLVMDLLImportStorageClass);
}*/
if (decl->visibility == VISIBLE_LOCAL)
LLVMValueRef function = LLVMAddFunction(context->module, decl->cname ?: decl->external_name, llvm_type(decl->type));
decl->ref = function;
if (decl->func.function_signature.return_param)
{
LLVMSetVisibility(decl->func.backend_value, LLVMHiddenVisibility);
if (decl->func.function_signature.error_return == ERROR_RETURN_NONE)
{
gencontext_add_attribute(context, function, sret_attribute, 1);
}
gencontext_add_attribute(context, function, noalias_attribute, 1);
}
if (decl->func.attr_inline)
{
gencontext_add_attribute(context, function, alwaysinline_attribute, -1);
}
if (decl->func.attr_noinline)
{
gencontext_add_attribute(context, function, noinline_attribute, -1);
}
if (decl->func.attr_noreturn)
{
gencontext_add_attribute(context, function, noreturn_attribute, -1);
}
if (decl->alignment)
{
LLVMSetAlignment(function, decl->alignment);
}
if (decl->section)
{
LLVMSetSection(function, decl->section);
}
gencontext_add_attribute(context, function, nounwind_attribute, -1);
// TODO only for windows.
if (decl->func.attr_stdcall)
{
LLVMSetFunctionCallConv(function, LLVMX86StdcallCallConv);
LLVMSetDLLStorageClass(function, LLVMDLLImportStorageClass);
}
switch (decl->visibility)
{
case VISIBLE_EXTERN:
LLVMSetLinkage(function, decl->func.attr_weak ? LLVMExternalWeakLinkage : LLVMExternalLinkage);
LLVMSetVisibility(function, LLVMDefaultVisibility);
break;
case VISIBLE_PUBLIC:
case VISIBLE_MODULE:
if (decl->func.attr_weak) LLVMSetLinkage(function, LLVMWeakAnyLinkage);
LLVMSetVisibility(function, LLVMDefaultVisibility);
break;
case VISIBLE_LOCAL:
LLVMSetLinkage(function, decl->func.attr_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage);
LLVMSetVisibility(function, LLVMDefaultVisibility);
break;;
}
if (context->debug.builder)
{
LLVMDIFlags flags = LLVMDIFlagZero;
@@ -241,13 +277,13 @@ void gencontext_emit_extern_decl(GenContext *context, Decl *decl)
case DECL_POISONED:
UNREACHABLE;
case DECL_FUNC:
decl->func.backend_value = LLVMAddFunction(context->module, decl->external_name,
decl->ref = LLVMAddFunction(context->module, decl->cname ?: decl->external_name,
llvm_type(decl->type));
LLVMSetVisibility(decl->func.backend_value, LLVMDefaultVisibility);
LLVMSetVisibility(decl->ref, LLVMDefaultVisibility);
break;
case DECL_VAR:
decl->var.backend_ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->external_name);
LLVMSetVisibility(decl->var.backend_ref, LLVMDefaultVisibility);
decl->ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->cname ?: decl->external_name);
LLVMSetVisibility(decl->ref, LLVMDefaultVisibility);
break;
case DECL_TYPEDEF:
UNREACHABLE

View File

@@ -100,13 +100,17 @@ extern unsigned writeonly_attribute;
extern unsigned readonly_attribute;
// Disable optimization.
extern unsigned optnone_attribute;
// Sret (pointer)
extern unsigned sret_attribute;
// Noalias (pointer)
extern unsigned noalias_attribute;
void gencontext_begin_module(GenContext *context);
void gencontext_end_module(GenContext *context);
void gencontext_add_attribute(GenContext context, unsigned attribute_id, LLVMValueRef value_to_add_attribute_to);
void
gencontext_add_attribute(GenContext *context, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index);
void gencontext_emit_stmt(GenContext *context, Ast *ast);
void gencontext_generate_catch_block_if_needed(GenContext *context, Ast *ast);
@@ -149,9 +153,13 @@ static inline void gencontext_emit_return_value(GenContext *context, LLVMValueRe
context->current_block = NULL;
context->current_block_is_target = false;
}
LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMValueRef value, Type *type, Type *target_type);
LLVMValueRef gencontext_emit_cast(GenContext *context, CastKind cast_kind, LLVMValueRef value, Type *to_type, Type *from_type);
static inline bool gencontext_func_pass_return_by_param(GenContext *context, Type *first_param_type) { return false; };
static inline bool gencontext_func_pass_param_by_reference(GenContext *context, Type *param_type) { return false; }
static inline LLVMValueRef gencontext_emit_bitcast(GenContext *context, LLVMValueRef value, Type *type)
{
return LLVMBuildBitCast(context->builder, value, gencontext_get_llvm_type(context, type), "");
}
static inline bool gencontext_use_debug(GenContext *context)
{

View File

@@ -23,7 +23,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
{
Decl *decl = ast->declare_stmt;
decl->var.backend_ref = gencontext_emit_alloca(context, llvm_type(type_reduced(decl->type)), decl->name);
decl->ref = gencontext_emit_alloca(context, llvm_type(type_reduced(decl->type)), decl->name);
// TODO NRVO
// TODO debug info
/*
@@ -42,10 +42,10 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
*/
if (decl->var.init_expr)
{
gencontext_emit_assign_expr(context, decl->var.backend_ref, decl->var.init_expr);
return decl->var.backend_ref;
gencontext_emit_assign_expr(context, decl->ref, decl->var.init_expr);
return decl->ref;
}
return decl->var.backend_ref;
return decl->ref;
}
void gencontext_emit_decl_expr_list_ignore_result(GenContext *context, Ast *ast)
@@ -602,7 +602,7 @@ void gencontext_generate_catch_block_if_needed(GenContext *context, Ast *ast)
{
type = llvm_type(type_error_base);
}
ast->catch_stmt.error_param->var.backend_ref = gencontext_emit_alloca(context, type, "");
ast->catch_stmt.error_param->ref = gencontext_emit_alloca(context, type, "");
}
void gencontext_emit_catch_stmt(GenContext *context, Ast *ast)

View File

@@ -152,8 +152,7 @@ LLVMTypeRef llvm_func_type(LLVMContextRef context, Type *type)
default:
UNREACHABLE
}
LLVMTypeRef functype = LLVMFunctionType(ret_type, params, parameters, signature->variadic);
return functype;
return LLVMFunctionType(ret_type, params, parameters, signature->variadic);
}
@@ -213,16 +212,15 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
return type->backend_type = llvm_type_from_array(context, type);
case TYPE_SUBARRAY:
{
LLVMTypeRef base_type = llvm_get_type(context, type->array.base);
LLVMTypeRef base_type = llvm_get_type(context, type_get_ptr(type->array.base));
LLVMTypeRef size_type = llvm_get_type(context, type_usize);
assert(type->array.base->canonical->type_kind == TYPE_POINTER);
LLVMTypeRef array_type = LLVMStructCreateNamed(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:
return type->backend_type = LLVMPointerType(llvm_get_type(context, type->array.base), 0);
return type->backend_type = llvm_get_type(context, type_get_ptr(type->array.base));
}
UNREACHABLE;
}

View File

@@ -198,6 +198,18 @@ static Expr *parse_post_unary(Context *context, Expr *left)
return unary;
}
static Expr *parse_range_expr(Context *context, Expr *left_side)
{
assert(expr_ok(left_side));
advance_and_verify(context, TOKEN_ELLIPSIS);
Expr *right = TRY_EXPR_OR(parse_precedence(context, PREC_RANGE + 1), poisoned_expr);
Expr *range = expr_new(EXPR_RANGE, left_side->span);
range->range_expr.left = left_side;
range->range_expr.right = right;
RANGE_EXTEND_PREV(range);
return range;
}
static Expr *parse_ternary_expr(Context *context, Expr *left_side)
{
assert(expr_ok(left_side));
@@ -819,6 +831,7 @@ static Expr* parse_expr_block(Context *context, Expr *left)
}
ParseRule rules[TOKEN_EOF + 1] = {
[TOKEN_ELLIPSIS] = { NULL, parse_range_expr, PREC_RANGE },
[TOKEN_QUESTION] = { NULL, parse_ternary_expr, PREC_TERNARY },
[TOKEN_ELVIS] = { NULL, parse_ternary_expr, PREC_TERNARY },
[TOKEN_PLUSPLUS] = { parse_unary_expr, parse_post_unary, PREC_CALL },

View File

@@ -180,6 +180,7 @@ static inline Ast *parse_case_stmts(Context *context)
/**
* case_stmt
* : CASE constant_expression ':' case_stmts
* | CASE constant_expression ELLIPSIS constant_expression ':' cast_stmts
*/
static inline Ast* parse_case_stmt(Context *context)
{
@@ -800,7 +801,7 @@ Ast *parse_stmt(Context *context)
case TOKEN_MULT_ASSIGN:
case TOKEN_NOT_EQUAL:
case TOKEN_PLUS_ASSIGN:
case TOKEN_ELIPSIS:
case TOKEN_ELLIPSIS:
case TOKEN_SCOPE:
case TOKEN_SHR:
case TOKEN_SHL:

View File

@@ -425,6 +425,7 @@ static inline TypeInfo *parse_base_type(Context *context)
* : '[' constant_expression ']'
* | '[' ']'
* | '[' '+' ']'
* | '[' '*' ']'
* ;
*
* @param type the type to wrap, may not be poisoned.
@@ -443,13 +444,22 @@ static inline TypeInfo *parse_array_type_index(Context *context, TypeInfo *type)
RANGE_EXTEND_PREV(incr_array);
return incr_array;
}
if (try_consume(context, TOKEN_STAR))
{
CONSUME_OR(TOKEN_RBRACKET, poisoned_type_info);
TypeInfo *vararray = type_info_new(TYPE_INFO_VARARRAY, type->span);
vararray->array.base = type;
vararray->array.len = NULL;
RANGE_EXTEND_PREV(vararray);
return vararray;
}
if (try_consume(context, TOKEN_RBRACKET))
{
TypeInfo *array = type_info_new(TYPE_INFO_ARRAY, type->span);
array->array.base = type;
array->array.len = NULL;
RANGE_EXTEND_PREV(array);
return array;
TypeInfo *subarray = type_info_new(TYPE_INFO_SUBARRAY, type->span);
subarray->array.base = type;
subarray->array.len = NULL;
RANGE_EXTEND_PREV(subarray);
return subarray;
}
TypeInfo *array = type_info_new(TYPE_INFO_ARRAY, type->span);
array->array.base = type;
@@ -927,7 +937,7 @@ static inline bool parse_opt_parameter_type_list(Context *context, Visibility pa
SEMA_TOKEN_ERROR(context->tok, "Variadic arguments should be the last in a parameter list.");
return false;
}
if (try_consume(context, TOKEN_ELIPSIS))
if (try_consume(context, TOKEN_ELLIPSIS))
{
signature->variadic = true;
}
@@ -1170,7 +1180,7 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi
static AttributeDomains TOKEN_TO_ATTR[TOKEN_EOF + 1] = {
static AttributeDomain TOKEN_TO_ATTR[TOKEN_EOF + 1] = {
[TOKEN_FUNC] = ATTR_FUNC,
[TOKEN_VAR] = ATTR_VAR,
[TOKEN_ENUM] = ATTR_ENUM,
@@ -1209,8 +1219,8 @@ static AttributeDomains TOKEN_TO_ATTR[TOKEN_EOF + 1] = {
static inline Decl *parse_attribute_declaration(Context *context, Visibility visibility)
{
advance_and_verify(context, TOKEN_ATTRIBUTE);
AttributeDomains domains = 0;
AttributeDomains last_domain;
AttributeDomain domains = 0;
AttributeDomain last_domain;
last_domain = TOKEN_TO_ATTR[context->tok.type];
while (last_domain)
{
@@ -1255,7 +1265,7 @@ static inline bool parse_func_typedef(Context *context, Decl *decl, Visibility v
{
return false;
}
return parse_opt_throw_declaration(context, VISIBLE_PUBLIC, &(decl->typedef_decl.function_signature));
return parse_opt_throw_declaration(context, visibility, &(decl->typedef_decl.function_signature));
}
@@ -1290,7 +1300,6 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil
{
rtype = TRY_TYPE_OR(parse_type(context), poisoned_decl);
}
Decl *decl = decl_new(DECL_MACRO, context->tok, visibility);
decl->macro_decl.rtype = rtype;
TRY_CONSUME_OR(TOKEN_IDENT, "Expected a macro name here", poisoned_decl);
@@ -1531,6 +1540,8 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit
if (!parse_opt_throw_declaration(context, visibility, &(func->func.function_signature))) return poisoned_decl;
if (!parse_attributes(context, func)) return poisoned_decl;
// TODO remove
is_interface = context->tok.type == TOKEN_EOS;

View File

@@ -617,7 +617,14 @@ bool vava(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
bool sapt(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
TODO
bool is_subtype = type_is_subtype(canonical->pointer, from->array.base);
if (!is_subtype)
{
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
return sema_type_mismatch(left, type, cast_type);
}
insert_cast(left, CAST_SAPTR, canonical);
return true;
}
bool vasa(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
@@ -625,10 +632,7 @@ bool vasa(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
TODO
}
bool usui(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
TODO
}
bool euxi(Expr *left, Type *canonical, Type *type, CastType cast_type)
{
@@ -686,6 +690,24 @@ bool ptva(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_typ
TODO
}
bool ptsa(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
if (from->pointer->type_kind != TYPE_ARRAY)
{
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT);
return false;
}
if (!type_is_subtype(canonical->array.base, from->pointer->array.base))
{
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
sema_type_mismatch(left, type, CAST_TYPE_EXPLICIT);
return false;
}
insert_cast(left, CAST_APTSA, canonical);
return true;
}
bool usbo(Expr* left, Type *from, Type *canonical, Type *type, CastType cast_type)
{
TODO
@@ -845,6 +867,7 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
if (canonical->type_kind == TYPE_POINTER) return ptpt(expr, from_type, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_FUNC) return ptfu(expr, from_type, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_VARARRAY) return ptva(expr, from_type, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_SUBARRAY) return ptsa(expr, from_type, canonical, to_type, cast_type);
break;
case TYPE_ENUM:
if (type_is_integer(canonical)) return enxi(expr, from_type, canonical, to_type, cast_type);
@@ -854,9 +877,8 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type)
if (canonical == type_error_union) return ereu(expr);
break;
case TYPE_FUNC:
if (type_is_integer(canonical)) return ptxi(expr, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_POINTER) return fupt(expr, from_type, canonical, to_type, cast_type);
break;
SEMA_ERROR(expr, "The function call is missing (...), if you want to take the address of a function it must be prefixed with '&'.");
return false;
case TYPE_STRUCT:
if (canonical->type_kind == TYPE_STRUCT) return stst(expr, from_type, canonical, to_type, cast_type);
if (canonical->type_kind == TYPE_UNION) return stun(expr, from_type, canonical, to_type, cast_type);

View File

@@ -318,7 +318,7 @@ 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->type->canonical = func_type;
decl->type->canonical = type_get_ptr(func_type);
return true;
}
if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) return false;
@@ -437,7 +437,123 @@ static inline bool sema_analyse_method_function(Context *context, Decl *decl)
return true;
}
static inline AttributeType attribute_by_name(Attr *attr)
{
const char *attribute = attr->name.string;
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
{
if (attribute_list[i] == attribute) return (AttributeType)i;
}
return ATTRIBUTE_NONE;
}
static const char *attribute_domain_to_string(AttributeDomain domain)
{
switch (domain)
{
case ATTR_FUNC:
return "function";
case ATTR_VAR:
return "variable";
case ATTR_ENUM:
return "enum";
case ATTR_STRUCT:
return "struct";
case ATTR_UNION:
return "union";
case ATTR_CONST:
return "constant";
case ATTR_ERROR:
return "error type";
case ATTR_TYPEDEF:
return "typedef";
}
UNREACHABLE
}
static AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDomain domain)
{
AttributeType type = attribute_by_name(attr);
if (type == ATTRIBUTE_NONE)
{
SEMA_TOKEN_ERROR(attr->name, "There is no attribute with the name '%s', did you mistype?", attr->name.string);
return ATTRIBUTE_NONE;
}
static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = {
[ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_VAR,
[ATTRIBUTE_CNAME] = 0xFF,
[ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_VAR,
[ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION,
[ATTRIBUTE_NORETURN] = ATTR_FUNC,
[ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_VAR | ATTR_STRUCT | ATTR_UNION,
[ATTRIBUTE_INLINE] = ATTR_FUNC,
[ATTRIBUTE_OPAQUE] = ATTR_STRUCT | ATTR_UNION
};
if ((attribute_domain[type] & domain) != domain)
{
SEMA_TOKEN_ERROR(attr->name, "'%s' is not a valid %s attribute.", attr->name.string, attribute_domain_to_string(domain));
return ATTRIBUTE_NONE;
}
switch (type)
{
case ATTRIBUTE_ALIGN:
if (!attr->expr)
{
SEMA_TOKEN_ERROR(attr->name, "'align' requires an power-of-2 argument, e.g. align(8).");
return ATTRIBUTE_NONE;
}
if (!sema_analyse_expr(context, type_usize, attr->expr)) return false;
if (attr->expr->expr_kind != EXPR_CONST || !type_is_any_integer(attr->expr->type->canonical))
{
SEMA_ERROR(attr->expr, "Expected a constant integer value as argument.");
return ATTRIBUTE_NONE;
}
{
BigInt comp;
bigint_init_unsigned(&comp, MAX_ALIGNMENT);
if (bigint_cmp(&attr->expr->const_expr.i, &comp) == CMP_GT)
{
SEMA_ERROR(attr->expr, "Alignment must be less or equal to %ull.", MAX_ALIGNMENT);
return ATTRIBUTE_NONE;
}
if (bigint_cmp_zero(&attr->expr->const_expr.i) != CMP_GT)
{
SEMA_ERROR(attr->expr, "Alignment must be greater than zero.");
return ATTRIBUTE_NONE;
}
uint64_t align = bigint_as_unsigned(&attr->expr->const_expr.i);
if (!is_power_of_two(align))
{
SEMA_ERROR(attr->expr, "Alignment must be a power of two.");
return ATTRIBUTE_NONE;
}
attr->alignment = align;
}
return type;
case ATTRIBUTE_SECTION:
case ATTRIBUTE_CNAME:
if (!attr->expr)
{
SEMA_TOKEN_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", attr->name.string, attr->name.string);
return ATTRIBUTE_NONE;
}
if (!sema_analyse_expr(context, NULL, attr->expr)) return false;
if (attr->expr->expr_kind != EXPR_CONST || attr->expr->type->canonical != type_string)
{
SEMA_ERROR(attr->expr, "Expected a constant string value as argument.");
return ATTRIBUTE_NONE;
}
return type;
default:
if (attr->expr)
{
SEMA_ERROR(attr->expr, "'%s' should not have any arguments.", attr->name.string);
return ATTRIBUTE_NONE;
}
return type;
}
}
static inline bool sema_analyse_func(Context *context, Decl *decl)
{
@@ -449,7 +565,50 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
{
if (!sema_analyse_method_function(context, decl)) return decl_poison(decl);
}
if (decl->name == main_name)
VECEACH(decl->attributes, i)
{
Attr *attr = decl->attributes[i];
AttributeType attribute = sema_analyse_attribute(context, attr, ATTR_FUNC);
if (attribute == ATTRIBUTE_NONE) return decl_poison(decl);
bool had = false;
#define SET_ATTR(_X) had = decl->func._X; decl->func._X = true; break
switch (attribute)
{
case ATTRIBUTE_CNAME:
had = decl->cname != NULL;
decl->cname = attr->expr->const_expr.string.chars;
break;
case ATTRIBUTE_SECTION:
had = decl->section != NULL;
decl->section = attr->expr->const_expr.string.chars;
break;
case ATTRIBUTE_ALIGN:
had = decl->alignment != 0;
decl->alignment = attr->alignment;
break;
case ATTRIBUTE_NOINLINE: SET_ATTR(attr_noinline);
case ATTRIBUTE_STDCALL: SET_ATTR(attr_stdcall);
case ATTRIBUTE_INLINE: SET_ATTR(attr_inline);
case ATTRIBUTE_NORETURN: SET_ATTR(attr_noreturn);
case ATTRIBUTE_WEAK: SET_ATTR(attr_weak);
default:
UNREACHABLE
}
#undef SET_ATTR
if (had)
{
SEMA_TOKEN_ERROR(attr->name, "Attribute occurred twice, please remove one.");
return decl_poison(decl);
}
if (decl->func.attr_inline && decl->func.attr_noinline)
{
SEMA_TOKEN_ERROR(attr->name, "A function cannot be 'inline' and 'noinline' at the same time.");
return decl_poison(decl);
}
}
if (decl->name == main_kw)
{
if (decl->visibility == VISIBLE_LOCAL)
{
@@ -492,6 +651,42 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
return false;
}
}
AttributeDomain domain = decl->var.kind == VARDECL_CONST ? ATTR_CONST : ATTR_FUNC;
VECEACH(decl->attributes, i)
{
Attr *attr = decl->attributes[i];
AttributeType attribute = sema_analyse_attribute(context, attr, domain);
if (attribute == ATTRIBUTE_NONE) return decl_poison(decl);
bool had = false;
#define SET_ATTR(_X) had = decl->func._X; decl->func._X = true; break
switch (attribute)
{
case ATTRIBUTE_CNAME:
had = decl->cname != NULL;
decl->cname = attr->expr->const_expr.string.chars;
break;
case ATTRIBUTE_SECTION:
had = decl->section != NULL;
decl->section = attr->expr->const_expr.string.chars;
break;
case ATTRIBUTE_ALIGN:
had = decl->alignment != 0;
decl->alignment = attr->alignment;
break;
case ATTRIBUTE_WEAK: SET_ATTR(attr_weak);
default:
UNREACHABLE
}
#undef SET_ATTR
if (had)
{
SEMA_TOKEN_ERROR(attr->name, "Attribute occurred twice, please remove one.");
return decl_poison(decl);
}
}
switch (decl->var.kind)
{
case VARDECL_CONST:

View File

@@ -23,6 +23,7 @@ static Ast **ast_copy_list_from_macro(Context *context, Expr *macro, Ast **to_co
#define MACRO_COPY_AST_LIST(x) x = ast_copy_list_from_macro(context, macro, x)
#define MACRO_COPY_AST(x) x = ast_copy_from_macro(context, macro, x)
bool sema_analyse_expr_may_be_function(Context *context, Expr *expr);
static inline bool is_const(Expr *expr)
{
@@ -39,6 +40,30 @@ static inline bool both_any_integer(Expr *left, Expr *right)
return type_is_any_integer(left->type->canonical) && type_is_any_integer(right->type->canonical);
}
static inline void context_pop_returns(Context *context, Ast **restore)
{
if (!context->returns_cache && context->returns)
{
context->returns_cache = context->returns;
}
context->returns = restore;
}
static inline Ast **context_push_returns(Context *context)
{
Ast** old_returns = context->returns;
if (context->returns_cache)
{
context->returns = context->returns_cache;
context->returns_cache = NULL;
vec_resize(context->returns, 0);
}
else
{
context->returns = NULL;
}
return old_returns;
}
int sema_check_comp_time_bool(Context *context, Expr *expr)
{
if (!sema_analyse_expr_of_required_type(context, type_bool, expr)) return -1;
@@ -55,9 +80,10 @@ static bool expr_is_ltype(Expr *expr)
switch (expr->expr_kind)
{
case EXPR_IDENTIFIER:
return expr->identifier_expr.decl->decl_kind == DECL_VAR && (expr->identifier_expr.decl->var.kind == VARDECL_LOCAL
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
|| expr->identifier_expr.decl->var.kind == VARDECL_PARAM);
|| expr->identifier_expr.decl->var.kind == VARDECL_PARAM));
case EXPR_UNARY:
return expr->unary_expr.operator == UNARYOP_DEREF;
case EXPR_ACCESS:
@@ -84,6 +110,15 @@ static inline bool sema_type_error_on_binop(Expr *expr)
return false;
}
static bool expr_cast_to_index(Expr *index)
{
if (index->type->canonical->type_kind == type_usize->canonical->type_kind) return true;
if (index->expr_kind != EXPR_RANGE) return cast_implicit(index, type_isize);
if (!cast_implicit(index->range_expr.left, type_isize)) return false;
if (!cast_implicit(index->range_expr.right, type_isize)) return false;
index->type = type_isize;
return true;
}
static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *expr)
{
@@ -219,8 +254,14 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
}
if (decl->decl_kind == DECL_MACRO)
{
SEMA_ERROR(expr, "Macro expansions must be prefixed with '@', try using '@%s(...)' instead.", decl->name);
return false;
if (!context->in_macro_call)
{
SEMA_ERROR(expr, "Macro expansions must be prefixed with '@', try using '@%s(...)' instead.", decl->name);
return false;
}
expr->identifier_expr.decl = decl;
expr->type = type_void;
return true;
}
assert(decl->type);
expr->identifier_expr.decl = decl;
@@ -233,10 +274,6 @@ static inline bool sema_expr_analyse_binary_sub_expr(Context *context, Type *to,
return sema_analyse_expr(context, to, left) & sema_analyse_expr(context, to, right);
}
static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr *expr) { TODO }
static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO };
static inline int find_index_of_named_parameter(Decl** func_params, Expr *expr)
{
if (expr->expr_kind != EXPR_IDENTIFIER || expr->identifier_expr.path)
@@ -253,14 +290,12 @@ static inline int find_index_of_named_parameter(Decl** func_params, Expr *expr)
return -1;
}
static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl)
static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionSignature *signature, Expr *expr, Decl *decl, Type *to)
{
Expr **args = expr->call_expr.arguments;
FunctionSignature *signature = &decl->func.function_signature;
Decl **func_params = signature->params;
expr->call_expr.throw_info = CALLOCS(ThrowInfo);
expr->call_expr.throw_info->defer = context->current_scope->defers.start;
Expr **args = expr->call_expr.arguments;
unsigned error_params = signature->throw_any || signature->throws;
if (error_params)
{
@@ -277,8 +312,8 @@ static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr
else
{
vec_add(context->error_calls, throw_new(expr->span,
vec_size(signature->throws) == 1 ? THROW_TYPE_CALL_THROW_ONE : THROW_TYPE_CALL_THROW_MANY,
expr->call_expr.throw_info, signature->throws));
vec_size(signature->throws) == 1 ? THROW_TYPE_CALL_THROW_ONE : THROW_TYPE_CALL_THROW_MANY,
expr->call_expr.throw_info, signature->throws));
}
}
unsigned func_param_count = vec_size(func_params);
@@ -341,17 +376,103 @@ static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr
SEMA_ERROR(expr, "Parameter '%s' was not set.", func_params[i]->name);
return false;
}
expr->type = decl->func.function_signature.rtype->type;
expr->type = signature->rtype->type;
expr->call_expr.arguments = actual_args;
return true;
}
static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr *expr, Decl *var_decl)
{
Type *func_ptr_type = var_decl->type->canonical;
if (func_ptr_type->type_kind != TYPE_POINTER || func_ptr_type->pointer->type_kind != TYPE_FUNC)
{
SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", type_to_error_string(var_decl->type));
return false;
}
expr->call_expr.is_pointer_call = true;
return sema_expr_analyse_func_invocation(context,
func_ptr_type->pointer->func.signature,
expr,
func_ptr_type->decl,
to);
}
static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO };
static inline Type *unify_returns(Context *context, Type *to)
{
bool all_returns_need_casts = false;
// Let's unify the return statements.
VECEACH(context->returns, i)
{
Ast *return_stmt = context->returns[i];
Expr *ret_expr = return_stmt->return_stmt.expr;
bool last_expr_was_void = to == type_void;
Type *right_canonical = ret_expr ? ret_expr->type->canonical : type_void;
bool current_expr_was_void = right_canonical == type_void;
if (i > 0 && last_expr_was_void != current_expr_was_void)
{
SEMA_ERROR(return_stmt, "You can't combine empty returns with value returns.");
SEMA_PREV(context->returns[i - 1], "Previous return was here.");
return NULL;
}
if (to)
{
if (current_expr_was_void)
{
SEMA_ERROR(return_stmt, "The return must be a value of type '%s'.", type_to_error_string(to));
return NULL;
}
if (!cast_implicit(ret_expr, to))
{
return NULL;
}
continue;
}
// The simple case.
if (to == right_canonical) continue;
// Try to find a common type:
Type *max = type_find_max_type(to, right_canonical);
if (!max)
{
SEMA_ERROR(return_stmt, "Cannot find a common parent type of '%s' and '%s'",
type_to_error_string(to), type_to_error_string(right_canonical));
SEMA_PREV(context->returns[i - 1], "The previous return was here.");
return false;
}
to = max;
all_returns_need_casts = true;
}
if (all_returns_need_casts)
{
VECEACH(context->returns, i)
{
Ast *return_stmt = context->returns[i];
Expr *ret_expr = return_stmt->return_stmt.expr;
if (!cast_implicit(ret_expr, to))
{
return NULL;
}
}
}
return to;
}
static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl)
{
expr->call_expr.is_pointer_call = false;
return sema_expr_analyse_func_invocation(context, &decl->func.function_signature, expr, decl, to);
}
static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr)
{
// TODO
Expr *func_expr = expr->call_expr.function;
// TODO check
if (!sema_analyse_expr(context, to, func_expr)) return false;
if (!sema_analyse_expr_may_be_function(context, func_expr)) return false;
Decl *decl;
switch (func_expr->expr_kind)
{
@@ -367,7 +488,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
switch (decl->decl_kind)
{
case DECL_VAR:
return sema_expr_analyse_var_call(context, to, expr);
return sema_expr_analyse_var_call(context, to, expr, decl);
case DECL_FUNC:
return sema_expr_analyse_func_call(context, to, expr, decl);
case DECL_MACRO:
@@ -383,6 +504,83 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
}
}
static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *expr)
{
Expr *left = expr->range_expr.left;
Expr *right = expr->range_expr.right;
bool success = sema_analyse_expr(context, to, left) & sema_analyse_expr(context, to, right);
if (!success) return expr_poison(expr);
Type *left_canonical = left->type->canonical;
Type *right_canonical = right->type->canonical;
if (!type_is_any_integer(left_canonical))
{
SEMA_ERROR(left, "Expected an integer value in the range expression.");
return false;
}
if (!type_is_any_integer(right_canonical))
{
SEMA_ERROR(right, "Expected an integer value in the range expression.");
return false;
}
if (left_canonical != right_canonical)
{
Type *type = type_find_max_type(left_canonical, right_canonical);
if (!cast_implicit(left, type) || !cast_implicit(right, type)) return expr_poison(expr);
}
if (left->expr_kind == EXPR_CONST && right->expr_kind == EXPR_CONST)
{
if (expr_const_compare(&left->const_expr, &right->const_expr, BINARYOP_GT))
{
SEMA_ERROR(expr, "Left side of the range is smaller than the right.");
return false;
}
}
expr->type = left->type;
return true;
}
static bool expr_check_index_in_range(Type *type, Expr *index)
{
if (index->expr_kind == EXPR_RANGE)
{
return expr_check_index_in_range(type, index->range_expr.left) & expr_check_index_in_range(type, index->range_expr.right);
}
assert(type == type->canonical);
if (index->expr_kind == EXPR_CONST)
{
switch (type->type_kind)
{
case TYPE_POINTER:
return true;
case TYPE_ARRAY:
{
BigInt size;
bigint_init_unsigned(&size, type->array.len);
if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.",
bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1);
return false;
}
FALLTHROUGH;
}
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
if (bigint_cmp_zero(&index->const_expr.i) == CMP_LT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s.", bigint_to_error_string(&index->const_expr.i, 10));
return false;
}
break;
case TYPE_STRING:
TODO
default:
UNREACHABLE
}
}
return true;
}
static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *context, Type *parent, Expr *expr)
{
assert(expr->expr_kind == EXPR_SUBSCRIPT);
@@ -396,41 +594,25 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *
return false;
}
if (!sema_analyse_expr(context, type_isize, index)) return false;
if (index->expr_kind == EXPR_RANGE)
{
if (!sema_expr_analyse_range(context, type_isize, index)) return false;
}
else
{
if (!sema_analyse_expr(context, type_isize, index)) return false;
}
// Unless we already have type_usize, cast to type_isize;
if (index->type->canonical->type_kind != type_usize->canonical->type_kind)
{
if (!cast_implicit(index, type_isize)) return false;
}
if (!expr_cast_to_index(index)) return false;
// Check range
if (index->expr_kind == EXPR_CONST)
if (!expr_check_index_in_range(type, index)) return false;
if (index->expr_kind == EXPR_RANGE)
{
switch (type->type_kind)
{
case TYPE_ARRAY:
{
BigInt size;
bigint_init_unsigned(&size, type->array.len);
if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.",
bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1);
return false;
}
FALLTHROUGH;
}
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
if (bigint_cmp_zero(&index->const_expr.i) == CMP_LT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s.", bigint_to_error_string(&index->const_expr.i, 10));
return false;
}
break;
default:
break;
}
expr->type = type_get_subarray(inner_type);
return true;
}
expr->type = inner_type;
return true;
@@ -653,55 +835,7 @@ static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath
return path;
}
static bool expr_cast_to_index(Expr *index)
{
if (index->expr_kind == EXPR_RANGE)
{
TODO
}
if (index->type->canonical->type_kind == type_usize->canonical->type_kind) return true;
return cast_implicit(index, type_isize);
}
static bool expr_check_index_in_range(Type *type, Expr *index)
{
if (index->expr_kind == EXPR_RANGE)
{
return expr_check_index_in_range(type, index->range_expr.left) & expr_check_index_in_range(type, index->range_expr.right);
}
assert(type == type->canonical);
if (index->expr_kind == EXPR_CONST)
{
switch (type->type_kind)
{
case TYPE_ARRAY:
{
BigInt size;
bigint_init_unsigned(&size, type->array.len);
if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.",
bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1);
return false;
}
FALLTHROUGH;
}
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
if (bigint_cmp_zero(&index->const_expr.i) == CMP_LT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s.", bigint_to_error_string(&index->const_expr.i, 10));
return false;
}
break;
case TYPE_STRING:
TODO
default:
UNREACHABLE
}
}
return true;
}
static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedPath *parent, Expr *expr, bool *has_found_match, bool *has_reported_error)
{
assert(expr->expr_kind == EXPR_SUBSCRIPT);
@@ -1932,6 +2066,11 @@ static bool sema_expr_analyse_deref(Context *context, Expr *expr, Expr *inner)
*/
static bool sema_expr_analyse_addr(Context *context, Expr *expr, Expr *inner)
{
if (inner->type->type_kind == TYPE_FUNC)
{
expr->type = type_get_ptr(inner->type);
return true;
}
// 1. Check that it is an lvalue.
if (!expr_is_ltype(inner))
{
@@ -2187,23 +2326,27 @@ static inline bool sema_expr_analyse_unary(Context *context, Type *to, Expr *exp
assert(expr->resolve_status == RESOLVE_RUNNING);
Expr *inner = expr->unary_expr.expr;
if (!sema_analyse_expr(context, NULL, inner)) return false;
switch (expr->unary_expr.operator)
{
case UNARYOP_DEREF:
if (!sema_analyse_expr(context, NULL, inner)) return false;
return sema_expr_analyse_deref(context, expr, inner);
case UNARYOP_ADDR:
if (!sema_analyse_expr_may_be_function(context, inner)) return false;
return sema_expr_analyse_addr(context, expr, inner);
case UNARYOP_NEG:
case UNARYOP_NEGMOD:
if (!sema_analyse_expr(context, NULL, inner)) return false;
return sema_expr_analyse_neg(context, to, expr, inner);
case UNARYOP_BITNEG:
if (!sema_analyse_expr(context, to, inner)) return false;
return sema_expr_analyse_bit_not(context, to, expr, inner);
case UNARYOP_NOT:
if (!sema_analyse_expr(context, NULL, inner)) return false;
return sema_expr_analyse_not(context, to, expr, inner);
case UNARYOP_DEC:
case UNARYOP_INC:
if (!sema_analyse_expr(context, NULL, inner)) return false;
return sema_expr_analyse_incdec(context, to, expr, inner);
case UNARYOP_ERROR:
return false;
@@ -2331,6 +2474,8 @@ static TypeInfo *type_info_copy_from_macro(Context *context, Expr *macro, TypeIn
copy->array.base = type_info_copy_from_macro(context, macro, source->array.base);
return copy;
case TYPE_INFO_INC_ARRAY:
case TYPE_INFO_VARARRAY:
case TYPE_INFO_SUBARRAY:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->array.base = type_info_copy_from_macro(context, macro, source->array.base);
return copy;
@@ -2599,22 +2744,31 @@ static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source)
}
UNREACHABLE;
}
static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *macro, Expr *inner)
{
Expr *func_expr = inner->call_expr.function;
if (context->macro_nesting > MAX_MACRO_NESTING)
{
SEMA_ERROR(context->first_macro_call, "Too deep nesting (more than %d levels) when evaluating this macro.", MAX_MACRO_NESTING);
return false;
}
if (!sema_analyse_expr(context, NULL, func_expr)) return false;
Expr *func_expr = inner->call_expr.function;
bool was_in_macro_call = context->in_macro_call;
context->in_macro_call = true;
bool ok = sema_analyse_expr(context, NULL, inner->call_expr.function);
context->in_macro_call = was_in_macro_call;
if (!ok) return ok;
Decl *decl;
switch (func_expr->expr_kind)
switch (inner->call_expr.function->expr_kind)
{
case EXPR_TYPE_ACCESS:
TODO
case EXPR_IDENTIFIER:
decl = func_expr->identifier_expr.decl;
break;
default:
TODO
SEMA_ERROR(inner, "Expected a macro identifier here");
return false;
}
if (decl->decl_kind != DECL_MACRO)
{
@@ -2623,18 +2777,56 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr
}
Expr **args =func_expr->call_expr.arguments;
Decl **func_params = decl->macro_decl.parameters;
// TODO handle bare macros.
// TODO handle $ args and # args
unsigned num_args = vec_size(args);
// unsigned num_params = vec_size(func_params);
for (unsigned i = 0; i < num_args; i++)
{
Expr *arg = args[i];
Decl *param = func_params[i];
if (!sema_analyse_expr(context, param->type, arg)) return false;
}
Ast *body = ast_copy_from_macro(context, inner, decl->macro_decl.body);
TODO
ok = true;
macro->type = type_void;
Ast **saved_returns = context_push_returns(context);
context->expected_block_type = to;
context_push_scope_with_flags(context, SCOPE_EXPR_BLOCK);
VECEACH(body->compound_stmt.stmts, i)
{
if (!sema_analyse_statement(context, body->compound_stmt.stmts[i]))
{
ok = false;
goto EXIT;
}
}
if (!vec_size(context->returns))
{
if (to)
{
SEMA_ERROR(decl, "Missing return in macro that evaluates to %s.", type_to_error_string(to));
ok = false;
}
goto EXIT;
}
Expr *first_return_expr = context->returns[0]->return_stmt.expr;
Type *left_canonical = first_return_expr ? first_return_expr->type->canonical : type_void;
// Let's unify the return statements.
left_canonical = unify_returns(context, left_canonical);
if (!left_canonical)
{
ok = false;
goto EXIT;
}
macro->type = left_canonical;
EXIT:
context_pop_scope(context);
context_pop_returns(context, saved_returns);
return ok;
}
static inline bool sema_expr_analyse_macro_call2(Context *context, Type *to, Expr *expr, Decl *macro)
@@ -2683,30 +2875,7 @@ static inline bool sema_expr_analyse_type(Context *context, Type *to, Expr *expr
static inline Ast **context_push_returns(Context *context)
{
Ast** old_returns = context->returns;
if (context->returns_cache)
{
context->returns = context->returns_cache;
context->returns_cache = NULL;
vec_resize(context->returns, 0);
}
else
{
context->returns = NULL;
}
return old_returns;
}
static inline void context_pop_returns(Context *context, Ast **restore)
{
if (!context->returns_cache && context->returns)
{
context->returns_cache = context->returns;
}
context->returns = restore;
}
static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr *expr)
@@ -2739,66 +2908,12 @@ static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr
Expr *first_return_expr = context->returns[0]->return_stmt.expr;
Type *left_canonical = first_return_expr ? first_return_expr->type->canonical : type_void;
bool all_returns_needs_casts = false;
// Let's unify the return statements.
VECEACH(context->returns, i)
left_canonical = unify_returns(context, left_canonical);
if (!left_canonical)
{
Ast *return_stmt = context->returns[i];
Expr *ret_expr = return_stmt->return_stmt.expr;
bool last_expr_was_void = left_canonical == type_void;
Type *right_canonical = ret_expr ? ret_expr->type->canonical : type_void;
bool current_expr_was_void = right_canonical == type_void;
if (i > 0 && last_expr_was_void != current_expr_was_void)
{
SEMA_ERROR(return_stmt, "You can't combine empty returns with value returns.");
SEMA_PREV(context->returns[i - 1], "Previous return was here.");
success = false;
goto EXIT;
}
if (to)
{
if (current_expr_was_void)
{
SEMA_ERROR(return_stmt, "The return must be a value of type '%s'.", type_to_error_string(to));
success = false;
goto EXIT;
}
if (!cast_implicit(ret_expr, to))
{
success = false;
goto EXIT;
}
continue;
}
// The simple case.
if (left_canonical == right_canonical) continue;
// Try to find a common type:
Type *max = type_find_max_type(left_canonical, right_canonical);
if (!max)
{
SEMA_ERROR(return_stmt, "Cannot find a common parent type of '%s' and '%s'",
type_to_error_string(left_canonical), type_to_error_string(right_canonical));
SEMA_PREV(context->returns[i - 1], "The previous return was here.");
success = false;
goto EXIT;
}
left_canonical = max;
all_returns_needs_casts = true;
}
if (all_returns_needs_casts)
{
VECEACH(context->returns, i)
{
Ast *return_stmt = context->returns[i];
Expr *ret_expr = return_stmt->return_stmt.expr;
if (!cast_implicit(ret_expr, left_canonical))
{
success = false;
goto EXIT;
}
}
success = false;
goto EXIT;
}
expr->type = left_canonical;
EXIT:
@@ -2808,10 +2923,7 @@ EXIT:
return success;
}
static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *expr)
{
TODO
}
static inline bool sema_expr_analyse_compound_literal(Context *context, Type *to, Expr *expr)
{
if (!sema_resolve_type_info(context, expr->expr_compound_literal.type_info)) return false;
@@ -2853,7 +2965,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
case EXPR_TRY:
return sema_expr_analyse_try(context, to, expr);
case EXPR_RANGE:
return sema_expr_analyse_range(context, to, expr);
SEMA_ERROR(expr, "Range expression was not expected here.");
return false;
case EXPR_CONST:
return true;
case EXPR_BINARY:
@@ -2910,5 +3023,36 @@ bool sema_analyse_expr(Context *context, Type *to, Expr *expr)
}
if (!sema_analyse_expr_dispatch(context, to, expr)) return expr_poison(expr);
expr->resolve_status = RESOLVE_DONE;
if (expr->expr_kind == EXPR_IDENTIFIER)
{
if (expr->identifier_expr.decl->decl_kind == DECL_FUNC)
{
SEMA_ERROR(expr, "Expected function followed by (...) or prefixed by &.");
return false;
}
if (expr->identifier_expr.decl->decl_kind == DECL_MACRO)
{
SEMA_ERROR(expr, "Expected macro followed by (...) or prefixed by &.");
return false;
}
}
return to ? cast(expr, to, CAST_TYPE_OPTIONAL_IMPLICIT) : true;
}
bool sema_analyse_expr_may_be_function(Context *context, Expr *expr)
{
switch (expr->resolve_status)
{
case RESOLVE_NOT_DONE:
expr->resolve_status = RESOLVE_RUNNING;
break;
case RESOLVE_RUNNING:
SEMA_ERROR(expr, "Recursive resolution of expression");
return expr_poison(expr);
case RESOLVE_DONE:
return expr_ok(expr);
}
if (!sema_analyse_expr_dispatch(context, NULL, expr)) return expr_poison(expr);
expr->resolve_status = RESOLVE_DONE;
return true;
}

View File

@@ -1062,6 +1062,9 @@ bool sema_analyse_function_body(Context *context, Decl *func)
context->expected_block_type = NULL;
context->last_local = &context->locals[0];
context->in_volatile_section = 0;
context->in_macro = 0;
context->macro_counter = 0;
context->macro_nesting = 0;
func->func.annotations = CALLOCS(*func->func.annotations);
context_push_scope(context);
Decl **params = signature->params;

View File

@@ -48,18 +48,28 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type)
return type_info_poison(type);
}
uint64_t len = 0;
if (type->array.len)
switch (type->kind)
{
if (!sema_analyse_expr_of_required_type(context, type_usize, type->array.len)) return type_info_poison(type);
if (type->array.len->expr_kind != EXPR_CONST)
{
SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
return type_info_poison(type);
}
len = bigint_as_unsigned(&type->array.len->const_expr.i);
case TYPE_INFO_VARARRAY:
type->type = type_get_vararray(type->array.base->type);
break;
case TYPE_INFO_SUBARRAY:
type->type = type_get_subarray(type->array.base->type);
break;;
case TYPE_INFO_ARRAY:
if (!sema_analyse_expr_of_required_type(context, type_usize, type->array.len)) return type_info_poison(type);
if (type->array.len->expr_kind != EXPR_CONST)
{
SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
return type_info_poison(type);
}
len = bigint_as_unsigned(&type->array.len->const_expr.i);
type->type = type_get_array(type->array.base->type, len);
break;
default:
UNREACHABLE
}
assert(!type->array.len || type->array.len->expr_kind == EXPR_CONST);
type->type = type_get_array(type->array.base->type, len);
type->resolve_status = RESOLVE_DONE;
return true;
}
@@ -101,21 +111,15 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_UNION:
case DECL_ERROR:
case DECL_ENUM:
case DECL_TYPEDEF:
if (decl->resolve_status == RESOLVE_NOT_DONE)
{
if (!sema_analyse_decl(context, decl)) return decl_poison(decl);
}
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_info(context, decl->typedef_decl.type_info))
{
decl_poison(decl);
return type_info_poison(type_info);
}
DEBUG_LOG("Resolved %s.", type_info->unresolved.name_loc.string);
type_info->type = decl->typedef_decl.type_info->type;
type_info->resolve_status = RESOLVE_DONE;
return true;
case DECL_POISONED:
return type_info_poison(type_info);
case DECL_FUNC:
@@ -166,6 +170,8 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info)
return type_info_poison(type_info);
}
TODO
case TYPE_INFO_SUBARRAY:
case TYPE_INFO_VARARRAY:
case TYPE_INFO_ARRAY:
return sema_resolve_array_type(context, type_info);
case TYPE_INFO_POINTER:

View File

@@ -34,7 +34,9 @@ typedef struct _Entry
static SymTab symtab;
const char *main_name;
const char *attribute_list[NUMBER_OF_ATTRIBUTES];
const char *main_kw;
void symtab_init(uint32_t capacity)
{
@@ -64,9 +66,21 @@ void symtab_init(uint32_t capacity)
assert(type == (TokenType)i);
assert(symtab_add(name, (uint32_t)strlen(name), fnv1a(name, len), &type) == interned);
}
// Init some constant idents
TokenType type = TOKEN_IDENT;
main_name = symtab_add("main", 4, fnv1a("main", 4), &type);
#define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type)
main_kw = KW_DEF("main");
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("inline");
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline");
attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall");
attribute_list[ATTRIBUTE_NORETURN] = KW_DEF("noreturn");
attribute_list[ATTRIBUTE_ALIGN] = KW_DEF("align");
attribute_list[ATTRIBUTE_PACKED] = KW_DEF("packed");
attribute_list[ATTRIBUTE_SECTION] = KW_DEF("section");
attribute_list[ATTRIBUTE_CNAME] = KW_DEF("cname");
attribute_list[ATTRIBUTE_WEAK] = KW_DEF("weak");
attribute_list[ATTRIBUTE_OPAQUE] = KW_DEF("opaque");
}
static inline SymEntry *entry_find(const char *key, uint32_t key_len, uint32_t hash)

View File

@@ -124,7 +124,7 @@ const char *token_type_to_string(TokenType type)
return "})";
// Three character tokens
case TOKEN_ELIPSIS:
case TOKEN_ELLIPSIS:
return "...";
case TOKEN_MULT_MOD_ASSIGN:
return "*%=";

View File

@@ -48,8 +48,9 @@ unsigned size_error_code;
unsigned alignment_error_code;
#define PTR_OFFSET 0
#define VAR_ARRAY_OFFSET 1
#define ARRAY_OFFSET 2
#define SUB_ARRAY_OFFSET 1
#define VAR_ARRAY_OFFSET 2
#define ARRAY_OFFSET 3
Type *type_signed_int_by_bitsize(unsigned bytesize)
{
@@ -113,10 +114,10 @@ const char *type_to_error_string(Type *type)
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->array.base));
asprintf(&buffer, "%s[*]", type_to_error_string(type->array.base));
return buffer;
case TYPE_SUBARRAY:
asprintf(&buffer, "%s[:]", type_to_error_string(type->array.base));
asprintf(&buffer, "%s[]", type_to_error_string(type->array.base));
return buffer;
case TYPE_ERROR_UNION:
return "error";
@@ -294,6 +295,57 @@ static Type *type_generate_ptr(Type *ptr_type, bool canonical)
return ptr;
}
static Type *type_generate_subarray(Type *arr_type, bool canonical)
{
if (canonical) arr_type = arr_type->canonical;
if (!arr_type->type_cache)
{
create_type_cache(arr_type);
}
Type *arr = arr_type->type_cache[SUB_ARRAY_OFFSET];
if (arr == NULL)
{
arr = type_new(TYPE_SUBARRAY, strformat("%s[]", arr_type->name));
arr->array.base = arr_type;
arr_type->type_cache[SUB_ARRAY_OFFSET] = arr;
if (arr_type == arr_type->canonical)
{
arr->canonical = arr;
}
else
{
arr->canonical = type_generate_subarray(arr_type->canonical, true);
}
}
return arr;
}
static Type *type_generate_vararray(Type *arr_type, bool canonical)
{
if (canonical) arr_type = arr_type->canonical;
if (!arr_type->type_cache)
{
create_type_cache(arr_type);
}
Type *arr = arr_type->type_cache[VAR_ARRAY_OFFSET];
if (arr == NULL)
{
arr = type_new(TYPE_VARARRAY, strformat("%s[*]", arr_type->name));
arr->array.base = arr_type;
arr_type->type_cache[VAR_ARRAY_OFFSET] = arr;
if (arr_type == arr_type->canonical)
{
arr->canonical = arr;
}
else
{
arr->canonical = type_generate_vararray(arr_type->canonical, true);
}
}
return arr;
}
Type *type_get_ptr(Type *ptr_type)
@@ -301,6 +353,16 @@ Type *type_get_ptr(Type *ptr_type)
return type_generate_ptr(ptr_type, false);
}
Type *type_get_subarray(Type *arr_type)
{
return type_generate_subarray(arr_type, false);
}
Type *type_get_vararray(Type *arr_type)
{
return type_generate_subarray(arr_type, false);
}
Type *type_get_indexed_type(Type *type)
{
switch (type->type_kind)
@@ -330,34 +392,11 @@ Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
{
create_type_cache(arr_type);
}
// Dynamic array
if (len == 0)
{
Type *array = arr_type->type_cache[VAR_ARRAY_OFFSET];
if (array == NULL)
{
array = type_new(TYPE_VARARRAY, strformat("%s[]", arr_type->name));
array->array.base = arr_type;
array->array.len = 0;
if (arr_type->canonical == arr_type)
{
array->canonical = array;
}
else
{
array->canonical = type_create_array(arr_type, len, true);
}
arr_type->type_cache[VAR_ARRAY_OFFSET] = array;
}
return array;
}
int entries = (int)vec_size(arr_type->type_cache);
for (int i = ARRAY_OFFSET; i < entries; i++)
{
Type *ptr = arr_type->type_cache[i];
if (ptr->array.len == arr_type->array.len)
if (ptr->array.len == len)
{
return ptr;
}