Fixed bug that would intermittently arise from multiple contexts having the same pointer (should preferably be fixed in a different way later). Free all the arenas before codegen. Change "next" to "nextcase". Allow missing function parameters. Add "inline" structs.

This commit is contained in:
Christoffer Lerno
2021-01-03 00:15:51 +01:00
parent 781638d207
commit 564c93700e
28 changed files with 427 additions and 192 deletions

View File

@@ -25,6 +25,7 @@ Checks: >
WarningsAsErrors: "*"
CheckOptions:
- { key: readability-function-cognitive-complexity.Threshold, value: 40 }
- { key: readability-identifier-naming.StructCase, value: CamelCase }
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
- { key: readability-identifier-naming.VariableCase, value: lower_case }

View File

@@ -0,0 +1,17 @@
module std::array;
import std::mem;
public macro make($Type, usize elements)
{
assert(elements > 0);
$Type* ptr = mem::alloc($Type.sizeof, elements);
return ptr[0..(elements - 1)];
}
public macro make_zero($Type, usize elements)
{
assert(elements > 0);
$Type* ptr = mem::calloc($Type.sizeof, elements);
return ptr[0..(elements - 1)];
}

View File

@@ -18,11 +18,16 @@ extern func int fseek(void*, long, int);
extern func void* fopen(char *, char *);
*/
struct File
{
void *file;
}
extern func int _puts(char* message) @cname("puts");
extern func int printf(char* message, ...);
extern func int _putchar(char c) @cname("putchar");
extern File *__stdinp;
public func int putchar(char c) @inline
{
@@ -46,10 +51,6 @@ public func int println(char *message) @inline
}
/*
struct File
{
void *file;
}
enum Seek
{

24
resources/lib/std/mem.c3 Normal file
View File

@@ -0,0 +1,24 @@
module std::mem;
extern func void* _malloc(usize bytes) @cname("malloc");
extern func void* _calloc(usize bytes, usize elements) @cname("calloc");
extern func void _free(void* ptr) @cname("free");
public macro malloc($Type)
{
// TODO: return cast(_malloc($Type.sizeof) as $Type*);
return cast(mem::alloc($Type.sizeof) as $Type*);
}
public func void* alloc(usize size, usize elements = 1) @inline
{
return _malloc(size * elements);
}
public func void* calloc(usize size, usize elements = 1) @inline
{
return _calloc(size, elements);
}
public func void free(void* ptr) @inline
{
_free(ptr);
}

View File

@@ -0,0 +1,36 @@
module antiprime;
import std::io;
extern func int printf(char* message, ...);
func int countDivisors(int n)
{
if (n < 2) return 1;
int count = 2;
for (int i = 2; i <= n / 2; i++)
{
if (n % i == 0) count++;
}
return count;
}
func int main()
{
int maxDiv;
int count;
io::println("The first 20 anti-primes are:");
int n = 1;
while (count < 20)
{
int d = countDivisors(n);
if (d > maxDiv)
{
printf("%d ", n);
maxDiv = d;
count++;
}
n++;
}
io::println("");
return 0;
}

View File

@@ -0,0 +1,7 @@
import std::io;
func int main()
{
io::println("Hello world");
return 0;
}

View File

@@ -0,0 +1,18 @@
import std::io;
extern func int printf(char* message, ...);
macro void swap(&a, &b)
{
typeof(a) temp = a;
a = b;
b = temp;
}
func void main()
{
int x = 1;
int y = 2;
@swap(x, y);
printf("x: %d y: &d\n", x, y);
}

View File

@@ -0,0 +1,89 @@
module topologicalsort;
import std::mem;
import std::array;
extern func void printf(char* x, ...);
struct InputPair
{
int value;
int successor;
}
struct Entry
{
int value;
Entry* next;
}
struct TopoList
{
int count;
Entry* next;
}
public func void sort(InputPair[] pairs, uint elements)
{
printf(.x = "fe");
InputPair[] result = @array::make(InputPair, pairs.len());
TopoList* top = mem::calloc(TopoList.sizeof, elements);
for (int i = 0; i < pairs.len(); i++)
{
InputPair pair = pairs[i];
assert(pair.value >= 0 && pair.value < elements);
assert(pair.successor >= 0 && pair.successor < elements);
top[pair.successor].count++;
Entry* successor_entry = @mem::malloc(Entry);
*successor_entry = { pair.successor, null };
Entry** next_ref = &top[pair.value].next;
while (*next_ref)
{
next_ref = &(*next_ref).next;
}
*next_ref = successor_entry;
}
int[] intout = @array::make(int, elements);
int count = 0;
while LOOP: (1)
{
for (int i = 1; i < elements; i++)
{
if (top[i].count == 0)
{
intout[count++] = i;
Entry *next = top[i].next;
while (next)
{
top[next.value].count--;
next = next.next;
}
top[i].count = -1;
continue LOOP;
}
}
break;
}
printf("Got %d elements.\n", count);
for (int i = 0; i < count; i++)
{
printf("%d\n", intout[i]);
}
}
public func void main()
{
InputPair[10] pairs = {
{ 9, 2 },
{ 3, 7 },
{ 7, 5 },
{ 5, 8 },
{ 8, 6 },
{ 4, 6 },
{ 1, 3 },
{ 7, 4 },
{ 9, 5 },
{ 2, 8 },
};
sort(&pairs, 10);
}

View File

@@ -80,6 +80,8 @@ void compiler_compile(BuildTarget *target)
{
vec_add(target->sources, strformat("%s/std/builtin.c3", compiler.lib_dir));
vec_add(target->sources, strformat("%s/std/io.c3", compiler.lib_dir));
vec_add(target->sources, strformat("%s/std/mem.c3", compiler.lib_dir));
vec_add(target->sources, strformat("%s/std/array.c3", compiler.lib_dir));
}
VECEACH(target->sources, i)
{
@@ -90,38 +92,39 @@ void compiler_compile(BuildTarget *target)
vec_add(contexts, context);
parse_file(context);
}
unsigned source_count = vec_size(contexts);
assert(contexts);
VECEACH(contexts, i)
for (unsigned i = 0; i < source_count; i++)
{
sema_analysis_pass_process_imports(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
for (unsigned i = 0; i < source_count; i++)
{
sema_analysis_pass_register_globals(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
for (unsigned i = 0; i < source_count; i++)
{
sema_analysis_pass_conditional_compilation(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
for (unsigned i = 0; i < source_count; i++)
{
sema_analysis_pass_decls(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
for (unsigned i = 0; i < source_count; i++)
{
sema_analysis_pass_ct_assert(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
for (unsigned i = 0; i < source_count; i++)
{
sema_analysis_pass_functions(contexts[i]);
}
@@ -129,7 +132,7 @@ void compiler_compile(BuildTarget *target)
if (build_options.command == COMMAND_GENERATE_HEADERS)
{
VECEACH(contexts, i)
for (unsigned i = 0; i < source_count; i++)
{
Context *context = contexts[i];
header_gen(context);
@@ -137,11 +140,14 @@ void compiler_compile(BuildTarget *target)
return;
}
llvm_codegen_setup();
VECEACH(contexts, i)
void **gen_contexts = malloc(source_count * sizeof(void*));
for (unsigned i = 0; i < source_count; i++)
{
Context *context = contexts[i];
llvm_codegen(context);
gen_contexts[i] = llvm_gen(context);
}
printf("-- AST/EXPR INFO -- \n");
@@ -152,7 +158,23 @@ void compiler_compile(BuildTarget *target)
printf(" * Token memory use: %llukb\n", (unsigned long long)(toktype_arena.allocated) / 1024);
printf(" * Sourceloc memory use: %llukb\n", (unsigned long long)(sourceloc_arena.allocated) / 1024);
printf(" * Token data memory use: %llukb\n", (unsigned long long)(tokdata_arena.allocated) / 1024);
ast_arena_free();
decl_arena_free();
expr_arena_free();
type_info_arena_free();
sourceloc_arena_free();
tokdata_arena_free();
print_arena_status();
free_arena();
for (unsigned i = 0; i < source_count; i++)
{
llvm_codegen(gen_contexts[i]);
}
exit(EXIT_SUCCESS);
}

View File

@@ -437,6 +437,7 @@ typedef struct _Decl
bool is_packed : 1;
bool is_opaque : 1;
bool needs_additional_pad : 1;
bool is_substruct : 1;
void *backend_ref;
const char *cname;
AlignSize alignment;
@@ -1323,9 +1324,8 @@ extern const char *kw_kindof;
extern const char *kw_nameof;
extern const char *kw_qnameof;
extern const char *kw_len;
extern const char *kw_inline;
extern const char *kw_ordinal;
extern const char *kw___alloc;
extern const char *kw___free;
extern const char *kw___round;
extern const char *kw___ceil;
extern const char *kw___trunc;
@@ -1392,7 +1392,8 @@ CastKind cast_to_bool_kind(Type *type);
bool cast_implicitly_to_runtime(Context *context, Expr *expr);
void llvm_codegen(Context *context);
void llvm_codegen(void *module);
void *llvm_gen(Context *context);
void llvm_codegen_setup();
void header_gen(Context *context);
@@ -1699,6 +1700,12 @@ static inline uint64_t aligned_offset(uint64_t offset, uint64_t alignment)
return ((offset + alignment - 1) / alignment) * alignment;
}
static inline bool type_is_substruct(Type *type)
{
assert(type == type->canonical);
return type->type_kind == TYPE_STRUCT && type->decl->is_substruct;
}
static inline bool type_is_float(Type *type)
{
assert(type == type->canonical);

View File

@@ -417,7 +417,7 @@ typedef enum
TOKEN_LOCAL,
TOKEN_MACRO,
TOKEN_MODULE,
TOKEN_NEXT,
TOKEN_NEXTCASE,
TOKEN_NULL,
TOKEN_PUBLIC,
TOKEN_RETURN,

View File

@@ -47,7 +47,10 @@ static void gencontext_init(GenContext *context, Context *ast_context)
static void gencontext_destroy(GenContext *context)
{
free(context->ir_filename);
free(context->object_filename);
LLVMContextDispose(context->context);
free(context);
}
LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, unsigned int align, bool bitcast)
@@ -245,8 +248,7 @@ void gencontext_emit_object_file(GenContext *context)
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))
if (LLVMTargetMachineEmitToFile(target_machine(), context->module, context->object_filename, LLVMObjectFile, &err))
{
error_exit("Could not emit object file: %s", err);
}
@@ -255,8 +257,7 @@ void gencontext_emit_object_file(GenContext *context)
void gencontext_print_llvm_ir(GenContext *context)
{
char *err = NULL;
char *filename = strformat("%.*s.ll", (int)strlen(context->ast_context->file->name) - 3, context->ast_context->file->name);
if (LLVMPrintModuleToFile(context->module, filename, &err))
if (LLVMPrintModuleToFile(context->module, context->ir_filename, &err))
{
error_exit("Could not emit ir to file: %s", err);
}
@@ -671,53 +672,10 @@ static void gencontext_emit_decl(GenContext *context, Decl *decl)
}
}
void llvm_codegen(Context *context)
void llvm_codegen(void *context)
{
assert(intrinsics_setup);
GenContext gen_context;
gencontext_init(&gen_context, context);
gencontext_begin_module(&gen_context);
// EmitDeferred()
VECEACH(context->external_symbol_list, i)
{
llvm_emit_extern_decl(&gen_context, context->external_symbol_list[i]);
}
VECEACH(context->methods, i)
{
llvm_emit_function_decl(&gen_context, context->methods[i]);
}
VECEACH(context->functions, i)
{
llvm_emit_function_decl(&gen_context, context->functions[i]);
}
VECEACH(context->types, i)
{
gencontext_emit_decl(&gen_context, context->types[i]);
}
VECEACH(context->vars, i)
{
gencontext_emit_global_variable_definition(&gen_context, context->vars[i]);
}
VECEACH(context->functions, i)
{
Decl *decl = context->functions[i];
if (decl->func.body) llvm_emit_function_body(&gen_context, decl);
}
VECEACH(context->methods, i)
{
Decl *decl = context->methods[i];
if (decl->func.body) llvm_emit_function_body(&gen_context, decl);
}
if (llvm_use_debug(&gen_context)) LLVMDIBuilderFinalize(gen_context.debug.builder);
// If it's in test, then we want to serialize the IR before it is optimized.
if (build_options.test_mode)
{
gencontext_print_llvm_ir(&gen_context);
gencontext_verify_ir(&gen_context);
}
GenContext *gen_context = context;
LLVMModuleRef module = gen_context->module;
// Starting from here we could potentially thread this:
LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate();
LLVMPassManagerBuilderSetOptLevel(pass_manager_builder, build_options.optimization_level);
@@ -725,7 +683,7 @@ void llvm_codegen(Context *context)
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);
LLVMPassManagerRef function_pass_manager = LLVMCreateFunctionPassManagerForModule(module);
LLVMAddAnalysisPasses(target_machine(), function_pass_manager);
LLVMAddAnalysisPasses(target_machine(), pass_manager);
LLVMPassManagerBuilderPopulateModulePassManager(pass_manager_builder, pass_manager);
@@ -739,7 +697,7 @@ void llvm_codegen(Context *context)
// Run function passes
LLVMInitializeFunctionPassManager(function_pass_manager);
LLVMValueRef current_function = LLVMGetFirstFunction(gen_context.module);
LLVMValueRef current_function = LLVMGetFirstFunction(module);
while (current_function)
{
LLVMRunFunctionPassManager(function_pass_manager, current_function);
@@ -749,20 +707,70 @@ void llvm_codegen(Context *context)
LLVMDisposePassManager(function_pass_manager);
// Run module pass
LLVMRunPassManager(pass_manager, gen_context.module);
LLVMRunPassManager(pass_manager, module);
LLVMDisposePassManager(pass_manager);
// Serialize the LLVM IR, if requested, also verify the IR in this case
if (build_options.emit_llvm)
{
gencontext_print_llvm_ir(&gen_context);
gencontext_verify_ir(&gen_context);
gencontext_print_llvm_ir(gen_context);
gencontext_verify_ir(gen_context);
}
if (build_options.emit_bitcode) gencontext_emit_object_file(&gen_context);
if (build_options.emit_bitcode) gencontext_emit_object_file(gen_context);
gencontext_end_module(&gen_context);
gencontext_destroy(&gen_context);
gencontext_end_module(gen_context);
gencontext_destroy(gen_context);
}
void *llvm_gen(Context *context)
{
assert(intrinsics_setup);
GenContext *gen_context = calloc(sizeof(GenContext), 1);
gencontext_init(gen_context, context);
gencontext_begin_module(gen_context);
// EmitDeferred()
VECEACH(context->external_symbol_list, i)
{
llvm_emit_extern_decl(gen_context, context->external_symbol_list[i]);
}
VECEACH(context->methods, i)
{
llvm_emit_function_decl(gen_context, context->methods[i]);
}
VECEACH(context->functions, i)
{
llvm_emit_function_decl(gen_context, context->functions[i]);
}
VECEACH(context->types, i)
{
gencontext_emit_decl(gen_context, context->types[i]);
}
VECEACH(context->vars, i)
{
gencontext_emit_global_variable_definition(gen_context, context->vars[i]);
}
VECEACH(context->functions, i)
{
Decl *decl = context->functions[i];
if (decl->func.body) llvm_emit_function_body(gen_context, decl);
}
VECEACH(context->methods, i)
{
Decl *decl = context->methods[i];
if (decl->func.body) llvm_emit_function_body(gen_context, decl);
}
if (llvm_use_debug(gen_context)) LLVMDIBuilderFinalize(gen_context->debug.builder);
// If it's in test, then we want to serialize the IR before it is optimized.
if (build_options.test_mode)
{
gencontext_print_llvm_ir(gen_context);
gencontext_verify_ir(gen_context);
}
return gen_context;
}
void llvm_attribute_add_int(GenContext *context, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, uint64_t val, int index)

View File

@@ -1437,7 +1437,7 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr
// We will be replacing the slice assign with code that roughly looks like this:
// size_t end = slice_end;
// size_t slice_current = slice_start;
// while (slice_current < end) pointer[slice_current++] = value;
// while (slice_current <= end) pointer[slice_current++] = value;
// First, find the value assigned.
Expr *assigned_value = expr->slice_assign_expr.right;
@@ -1470,7 +1470,7 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr
LLVMValueRef offset = LLVMBuildPhi(c->builder, llvm_get_type(c, start_type), "");
// Check if we're not at the end.
LLVMValueRef not_at_end = llvm_emit_int_comparison(c, start_type, end_type, offset, end_index, BINARYOP_LT);
LLVMValueRef not_at_end = llvm_emit_int_comparison(c, start_type, end_type, offset, end_index, BINARYOP_LE);
// If jump to the assign block if we're not at the end index.
BEValue value;
@@ -2405,26 +2405,6 @@ void gencontext_emit_call_intrinsic_expr(GenContext *c, BEValue *be_value, Expr
llvm_emit_fp_intrinsic_expr(c, intrinsic_id_ceil, be_value, expr);
return;
}
if (function_decl->name == kw___alloc)
{
unsigned arguments = vec_size(expr->call_expr.arguments);
BEValue size_value;
llvm_emit_expr(c, &size_value, expr->call_expr.arguments[0]);
llvm_value_rvalue(c, &size_value);
LLVMValueRef result = LLVMBuildArrayMalloc(c->builder, llvm_get_type(c, type_byte), llvm_value_rvalue_store(c, &size_value), "");
result = LLVMBuildBitCast(c->builder, result, llvm_get_type(c, expr->type), "");
llvm_value_set(be_value, result, expr->type);
return;
}
if (function_decl->name == kw___free)
{
unsigned arguments = vec_size(expr->call_expr.arguments);
BEValue size_value;
llvm_emit_expr(c, &size_value, expr->call_expr.arguments[0]);
llvm_value_rvalue(c, &size_value);
LLVMBuildFree(c->builder, llvm_value_rvalue_store(c, &size_value));
return;
}
UNREACHABLE
}
@@ -2539,7 +2519,7 @@ void llvm_emit_parameter(GenContext *context, LLVMValueRef **args, ABIArgInfo *i
}
}
void gencontext_emit_call_expr(GenContext *context, BEValue *be_value, Expr *expr)
void llvm_emit_call_expr(GenContext *context, BEValue *be_value, Expr *expr)
{
printf("Optimize call return\n");
FunctionSignature *signature;
@@ -3041,7 +3021,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
gencontext_emit_access_addr(c, value, expr);
return;
case EXPR_CALL:
gencontext_emit_call_expr(c, value, expr);
llvm_emit_call_expr(c, value, expr);
return;
case EXPR_GROUP:
expr = expr->group_expr;

View File

@@ -636,6 +636,6 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl)
case DECL_ENUM:
TODO
case NON_TYPE_DECLS:
UNREACHABLE
return;
}
}

View File

@@ -72,6 +72,8 @@ typedef struct
LLVMBuilderRef builder;
LLVMBasicBlockRef current_block;
LLVMBasicBlockRef catch_block;
char *ir_filename;
char *object_filename;
// The recipient of the error value in a catch(err = ...) expression.
LLVMValueRef error_var;
LLVMTypeRef bool_type;

View File

@@ -8,6 +8,10 @@
void gencontext_begin_module(GenContext *context)
{
assert(!context->module && "Expected no module");
asprintf(&context->ir_filename, "%.*s.ll", (int)strlen(context->ast_context->file->name) - 3, context->ast_context->file->name);
asprintf(&context->object_filename, "%.*s.o", (int)strlen(context->ast_context->file->name) - 3, context->ast_context->file->name);
const char *full_path = context->ast_context->file->full_path;
char *mangled_module_name = strformat("%s-%s", context->ast_context->module->name->module, context->ast_context->file->name);
context->module = LLVMModuleCreateWithNameInContext(mangled_module_name, context->context);

View File

@@ -125,7 +125,10 @@ static inline LLVMTypeRef llvm_type_from_ptr(GenContext *context, Type *type)
{
return type->backend_type = llvm_get_type(context, type->canonical);
}
if (type == type_voidptr)
{
return type->backend_type = llvm_get_ptr_type(context, type_byte);
}
return type->backend_type = LLVMPointerType(llvm_get_type(context, type->pointer), /** TODO **/0);
}

View File

@@ -580,7 +580,7 @@ static Expr *parse_else_expr(Context *context, Expr *left)
case TOKEN_RETURN:
case TOKEN_BREAK:
case TOKEN_CONTINUE:
case TOKEN_NEXT:
case TOKEN_NEXTCASE:
{
Ast *ast = TRY_AST_OR(parse_jump_stmt_no_eos(context), poisoned_expr);
else_expr->else_expr.is_jump = true;

View File

@@ -1014,7 +1014,7 @@ static inline bool parse_attributes(Context *context, Decl *parent_decl)
* | type_expression IDENT '=' initializer
* ;
*/
static inline bool parse_param_decl(Context *context, Visibility parent_visibility, Decl*** parameters, bool type_only)
static inline bool parse_param_decl(Context *context, Visibility parent_visibility, Decl*** parameters, bool require_name)
{
TypeInfo *type = TRY_TYPE_OR(parse_type(context), false);
Decl *param = decl_new_var(context->tok.id, type, VARDECL_PARAM, parent_visibility);
@@ -1026,7 +1026,7 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili
const char *name = param->name;
if (!name && !type_only)
if (!name && require_name)
{
if (!TOKEN_IS(TOKEN_COMMA) && !TOKEN_IS(TOKEN_RPAREN))
{
@@ -1038,7 +1038,7 @@ static inline bool parse_param_decl(Context *context, Visibility parent_visibili
sema_error_at_prev_end(context->tok, "Unexpected end of the parameter list, did you forget an ')'?");
return false;
}
SEMA_ERROR(type, "The function parameter must be named.");
SEMA_ERROR(type, "The parameter must be named.");
return false;
}
if (name && try_consume(context, TOKEN_EQ))
@@ -1086,7 +1086,7 @@ static inline bool parse_opt_parameter_type_list(Context *context, Visibility pa
}
else
{
if (!parse_param_decl(context, parent_visibility, &(signature->params), is_interface)) return false;
if (!parse_param_decl(context, parent_visibility, &(signature->params), false)) return false;
}
if (!try_consume(context, TOKEN_COMMA))
{
@@ -1121,7 +1121,6 @@ static inline bool parse_opt_parameter_type_list(Context *context, Visibility pa
*/
bool parse_struct_body(Context *context, Decl *parent)
{
CONSUME_OR(TOKEN_LBRACE, false);
assert(decl_is_struct_type(parent));
@@ -1161,6 +1160,23 @@ bool parse_struct_body(Context *context, Decl *parent)
}
continue;
}
bool was_inline = false;
if (token_type == TOKEN_IDENT && TOKSTR(context->tok) == kw_inline)
{
if (parent->decl_kind != DECL_STRUCT)
{
SEMA_TOKEN_ERROR(context->tok, "Only structs may have 'inline' elements, did you make a mistake?");
return false;
}
if (index > 0)
{
SEMA_TOKID_ERROR(context->prev_tok, "Only the first element may be 'inline', did you order your fields wrong?");
return false;
}
parent->is_substruct = true;
was_inline = true;
advance(context);
}
TypeInfo *type = TRY_TYPE_OR(parse_type(context), false);
while (1)
{
@@ -1175,6 +1191,11 @@ bool parse_struct_body(Context *context, Decl *parent)
}
advance(context);
if (!try_consume(context, TOKEN_COMMA)) break;
if (was_inline)
{
SEMA_ERROR(member, "'Inline' can only be applied to a single member, so please define it on its own line.");
return false;
}
}
CONSUME_OR(TOKEN_EOS, false);
}
@@ -1575,7 +1596,7 @@ static inline bool parse_enum_spec(Context *context, TypeInfo **type_ref, Decl**
if (!try_consume(context, TOKEN_LPAREN)) return true;
while (!try_consume(context, TOKEN_RPAREN))
{
if (!parse_param_decl(context, parent_visibility, parameters_ref, false)) return false;
if (!parse_param_decl(context, parent_visibility, parameters_ref, true)) return false;
if (!try_consume(context, TOKEN_COMMA))
{
EXPECT_OR(TOKEN_RPAREN, false);
@@ -1698,7 +1719,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit
func->func.function_signature.rtype = return_type;
func->func.function_signature.failable = try_consume(context, TOKEN_BANG);
SourceSpan start = source_span_from_token_id(context->tok.id);
bool had_error;
bool had_error = false;
Path *path = parse_path_prefix(context, &had_error);
if (had_error) return poisoned_decl;
if (path || TOKEN_IS(TOKEN_TYPE_IDENT))

View File

@@ -499,7 +499,7 @@ static inline Ast* parse_continue(Context *context)
static inline Ast* parse_next(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_NEXT_STMT, context->tok);
advance_and_verify(context, TOKEN_NEXT);
advance_and_verify(context, TOKEN_NEXTCASE);
if (!TOKEN_IS(TOKEN_EOS))
{
if (TOKEN_IS(TOKEN_CONST_IDENT) && context->next_tok.type == TOKEN_COLON)
@@ -964,7 +964,7 @@ Ast *parse_stmt(Context *context)
Ast *ast = TRY_AST(parse_break(context));
RETURN_AFTER_EOS(ast);
}
case TOKEN_NEXT:
case TOKEN_NEXTCASE:
{
Ast *ast = TRY_AST(parse_next(context));
RETURN_AFTER_EOS(ast);
@@ -1121,7 +1121,7 @@ Ast *parse_jump_stmt_no_eos(Context *context)
{
switch (context->tok.type)
{
case TOKEN_NEXT:
case TOKEN_NEXTCASE:
return parse_next(context);
case TOKEN_RETURN:
return parse_return(context);

View File

@@ -26,6 +26,16 @@ static inline bool sema_cast_rvalue(Context *context, Type *to, Expr *expr);
#define MACRO_COPY_AST_LIST(x) x = ast_copy_list_from_macro(context, x)
#define MACRO_COPY_AST(x) x = ast_copy_from_macro(context, x)
static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl)
{
Expr *embedded_struct = expr_new(EXPR_ACCESS, parent->span);
embedded_struct->resolve_status = RESOLVE_DONE;
embedded_struct->access_expr.parent = parent;
embedded_struct->access_expr.ref = parent_decl->strukt.members[0];
embedded_struct->type = embedded_struct->access_expr.ref->type;
return embedded_struct;
}
static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *expr);
static inline bool sema_analyse_expr_value(Context *context, Type *to, Expr *expr);
static inline bool expr_const_int_valid(Expr *expr, Type *type)
@@ -696,7 +706,7 @@ static inline int find_index_of_named_parameter(Decl **func_params, Expr *expr)
{
if (func_params[i]->name == name) return (int)i;
}
SEMA_ERROR(expr, "There's no parameter with the name '%s', if you want an assignment expression, enclose it in ().", name);
SEMA_ERROR(expr, "There's no parameter with the name '%s'.", name);
return -1;
}
@@ -737,41 +747,6 @@ static inline bool sema_expr_analyse_intrinsic_invocation(Context *context, Expr
{
return sema_expr_analyse_intrinsic_fp_invocation(context, expr, decl, to);
}
if (decl->name == kw___alloc)
{
if (to && type_is_pointer(to))
{
expr->type = to;
}
else
{
expr->type = type_voidptr;
}
if (arguments != 1)
{
SEMA_ERROR(expr, "Expected 1 argument to intrinsic __alloc.");
return false;
}
if (!sema_analyse_expr_of_required_type(context, type_usize, expr->call_expr.arguments[0], false)) return false;
return true;
}
if (decl->name == kw___free)
{
expr->type = type_void;
if (arguments != 1)
{
SEMA_ERROR(expr, "Expected 1 argument to intrinsic __free.");
return false;
}
Expr *pointer_expr = expr->call_expr.arguments[0];
if (!sema_analyse_expr(context, NULL, pointer_expr)) return false;
if (pointer_expr->type->type_kind != TYPE_POINTER)
{
// TODO vararrays - handle them.
SEMA_ERROR(expr, "Expected expected to free a pointer type.");
}
return true;
}
UNREACHABLE
}
@@ -1351,19 +1326,38 @@ static bool expr_check_index_in_range(Context *context, Type *type, Expr *index_
return true;
}
static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *context, Type *parent, Expr *expr)
static Type *sema_expr_find_indexable_type_recursively(Type **type, Expr **parent)
{
while (1)
{
Type *inner_type = type_get_indexed_type(*type);
if (!inner_type && type_is_substruct(*type))
{
Expr *embedded_struct = expr_access_inline_member(*parent, (*type)->decl);
*type = embedded_struct->type->canonical;
*parent = embedded_struct;
continue;
}
return inner_type;
}
}
static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false;
expr->failable = expr->subscript_expr.expr->failable;
assert(expr->expr_kind == EXPR_SUBSCRIPT);
Expr *subscripted = expr->subscript_expr.expr;
Type *type = parent ? parent->canonical : subscripted->type->canonical;
Type *type = subscripted->type->canonical;
Expr *index = expr->subscript_expr.index;
Type *inner_type = type_get_indexed_type(type);
Type *current_type = type;
Expr *current_expr = subscripted;
Type *inner_type = sema_expr_find_indexable_type_recursively(&current_type, &current_expr);
if (!inner_type)
{
SEMA_ERROR((parent ? expr : subscripted), "Cannot index '%s'.", type_to_error_string(type));
SEMA_ERROR(subscripted, "Cannot index '%s'.", type_to_error_string(type));
return false;
}
if (!sema_analyse_expr(context, type_isize, index)) return false;
expr->constant = index->constant & subscripted->constant;
@@ -1373,35 +1367,35 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *
if (!expr_cast_to_index(context, index)) return false;
// Check range
if (!expr_check_index_in_range(context, type, index, false, expr->subscript_expr.from_back)) return false;
if (!expr_check_index_in_range(context, current_type, index, false, expr->subscript_expr.from_back)) return false;
expr->subscript_expr.expr = current_expr;
expr->failable |= index->failable;
expr->type = inner_type;
return true;
}
static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false;
expr->failable = expr->subscript_expr.expr->failable;
return sema_expr_analyse_subscript_after_parent_resolution(context, NULL, expr);
}
static inline bool sema_expr_analyse_slice_after_parent_resolution(Context *context, Type *parent, Expr *expr)
static inline bool sema_expr_analyse_slice(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->slice_expr.expr)) return false;
expr->failable = expr->slice_expr.expr->failable;
assert(expr->expr_kind == EXPR_SLICE);
Expr *subscripted = expr->slice_expr.expr;
expr->pure = subscripted->pure;
expr->constant = subscripted->constant;
Type *type = parent ? parent->canonical : subscripted->type->canonical;
Type *type = subscripted->type->canonical;
Expr *start = expr->slice_expr.start;
Expr *end = expr->slice_expr.end;
Type *inner_type = type_get_indexed_type(type);
Expr *current_expr = subscripted;
Type *inner_type = sema_expr_find_indexable_type_recursively(&type, &current_expr);
if (!inner_type)
{
SEMA_ERROR((parent ? expr : subscripted), "Cannot slice '%s'.", type_to_error_string(type));
SEMA_ERROR(subscripted, "Cannot index '%s'.", type_to_error_string(subscripted->type));
return false;
}
expr->slice_expr.expr = current_expr;
if (!sema_analyse_expr(context, type_isize, start)) return false;
expr->pure &= start->pure;
@@ -1479,13 +1473,6 @@ static inline bool sema_expr_analyse_slice_after_parent_resolution(Context *cont
return true;
}
static inline bool sema_expr_analyse_slice(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->slice_expr.expr)) return false;
expr->failable = expr->slice_expr.expr->failable;
return sema_expr_analyse_slice_after_parent_resolution(context, NULL, expr);
}
static inline void insert_access_deref(Expr *expr)
{
Expr *deref = expr_new(EXPR_UNARY, expr->span);
@@ -1855,6 +1842,7 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr)
return false;
}
static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
{
Expr *parent = expr->access_expr.parent;
@@ -1881,8 +1869,13 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
if (is_pointer)
{
type = type->pointer;
if (!sema_cast_rvalue(context, NULL, parent)) return false;
insert_access_deref(expr);
parent = expr->access_expr.parent;
}
const char *kw = TOKSTR(expr->access_expr.sub_element);
Expr *current_parent = parent;
CHECK_DEEPER:
switch (type->type_kind)
{
case TYPE_SUBARRAY:
@@ -1922,22 +1915,28 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
SEMA_ERROR(expr, "Cannot access '%s' on '%s'", TOKSTR(expr->access_expr.sub_element), type_to_error_string(parent_type));
return false;
}
Decl *decl = type->decl;
context_push_scope(context);
add_members_to_context(context, decl);
Decl *member = sema_resolve_symbol_in_current_dynamic_scope(context, kw);
context_pop_scope(context);
if (!member)
{
// We have a potential embedded struct check:
if (type_is_substruct(type))
{
Expr *embedded_struct = expr_access_inline_member(parent, type->decl);
current_parent = embedded_struct;
type = embedded_struct->type->canonical;
goto CHECK_DEEPER;
}
SEMA_ERROR(expr, "There is no field or method '%s.%s'.", decl->name, kw);
return false;
}
if (is_pointer)
{
if (!sema_cast_ident_rvalue(context, NULL, expr->access_expr.parent)) return false;
insert_access_deref(expr);
}
expr->access_expr.parent = current_parent;
expr->constant = expr->access_expr.parent->constant;
expr->pure = expr->access_expr.parent->pure;

View File

@@ -48,8 +48,6 @@ void sema_analysis_pass_process_imports(Context *context)
context_add_intrinsic(context, kw___round);
context_add_intrinsic(context, kw___trunc);
context_add_intrinsic(context, kw___ceil);
context_add_intrinsic(context, kw___alloc);
context_add_intrinsic(context, kw___free);
context_add_intrinsic(context, kw___sqrt);
DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors);
}

View File

@@ -45,9 +45,8 @@ const char *kw_nameof;
const char *kw_qnameof;
const char *kw_kindof;
const char *kw_len;
const char *kw_inline;
const char *kw_ordinal;
const char *kw___alloc;
const char *kw___free;
const char *kw___round;
const char *kw___ceil;
const char *kw___trunc;
@@ -85,6 +84,7 @@ void symtab_init(uint32_t capacity)
// Init some constant idents
TokenType type = TOKEN_IDENT;
#define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type)
kw_inline = KW_DEF("inline");
kw_main = KW_DEF("main");
kw_sizeof = KW_DEF("sizeof");
kw_alignof = KW_DEF("alignof");
@@ -95,14 +95,12 @@ void symtab_init(uint32_t capacity)
kw_len = KW_DEF("len");
kw_align = KW_DEF("align");
kw_ordinal = KW_DEF("ordinal");
kw___alloc = KW_DEF("__alloc");
kw___free = KW_DEF("__free");
kw___round = KW_DEF("__round");
kw___sqrt = KW_DEF("__sqrt");
kw___trunc = KW_DEF("__trunc");
kw___ceil = KW_DEF("__ceil");
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("inline");
attribute_list[ATTRIBUTE_INLINE] = kw_inline;
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline");
attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall");
attribute_list[ATTRIBUTE_NORETURN] = KW_DEF("noreturn");

View File

@@ -480,7 +480,6 @@ void target_setup(void)
break;
default:
FATAL_ERROR("Unsupported architecture.");
break;
}
build_target.int_128 = os_target_supports_int128(build_target.os, build_target.arch);

View File

@@ -240,8 +240,8 @@ const char *token_type_to_string(TokenType type)
return "macro";
case TOKEN_MODULE:
return "module";
case TOKEN_NEXT:
return "next";
case TOKEN_NEXTCASE:
return "nextcase";
case TOKEN_NULL:
return "null";
case TOKEN_PUBLIC:

View File

@@ -10,6 +10,7 @@
extern Vmem name##_arena; \
typedef unsigned type##Id; \
static inline type *name##_alloc(void) { return (type *)vmem_alloc(&name##_arena, sizeof(type)); } \
static inline void name##_arena_free(void) { vmem_free(&name##_arena); } \
static inline type *name##_calloc(void) { \
type *ptr = name##_alloc(); \
memset(ptr, 0, sizeof(type)); \

View File

@@ -12,7 +12,7 @@ func void test(int i)
{
case 1:
defer test2();
if (b) next;
if (b) nextcase;
test1();
case 2:
test1();

View File

@@ -1,5 +1,5 @@
enum EnumWithErrorWithMissingName : int (int) // #error: function parameter must be named
enum EnumWithErrorWithMissingName : int (int) // #error: The parameter must be named
{
TEST
}
@@ -9,7 +9,7 @@ enum EnumWithErrorData : int (int // #error: end of the parameter list
TEST
}
enum EnumWithErrorData2 : int (int, int bar) // #error: function parameter must be named
enum EnumWithErrorData2 : int (int, int bar) // #error: The parameter must be named
{
TEST
}