mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
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:
@@ -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 }
|
||||
|
||||
17
resources/lib/std/array.c3
Normal file
17
resources/lib/std/array.c3
Normal 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)];
|
||||
}
|
||||
@@ -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
24
resources/lib/std/mem.c3
Normal 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);
|
||||
}
|
||||
36
resources/rosettacode/antiprime.c3
Normal file
36
resources/rosettacode/antiprime.c3
Normal 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;
|
||||
}
|
||||
7
resources/rosettacode/helloworld.c3
Normal file
7
resources/rosettacode/helloworld.c3
Normal file
@@ -0,0 +1,7 @@
|
||||
import std::io;
|
||||
|
||||
func int main()
|
||||
{
|
||||
io::println("Hello world");
|
||||
return 0;
|
||||
}
|
||||
18
resources/testfragments/test.c3
Normal file
18
resources/testfragments/test.c3
Normal 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);
|
||||
}
|
||||
89
resources/testfragments/toposort.c3
Normal file
89
resources/testfragments/toposort.c3
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -417,7 +417,7 @@ typedef enum
|
||||
TOKEN_LOCAL,
|
||||
TOKEN_MACRO,
|
||||
TOKEN_MODULE,
|
||||
TOKEN_NEXT,
|
||||
TOKEN_NEXTCASE,
|
||||
TOKEN_NULL,
|
||||
TOKEN_PUBLIC,
|
||||
TOKEN_RETURN,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -636,6 +636,6 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl)
|
||||
case DECL_ENUM:
|
||||
TODO
|
||||
case NON_TYPE_DECLS:
|
||||
UNREACHABLE
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(¤t_type, ¤t_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, ¤t_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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)); \
|
||||
|
||||
@@ -12,7 +12,7 @@ func void test(int i)
|
||||
{
|
||||
case 1:
|
||||
defer test2();
|
||||
if (b) next;
|
||||
if (b) nextcase;
|
||||
test1();
|
||||
case 2:
|
||||
test1();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user