aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-07-17 19:23:16 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commit84e65c63e7482590d535e86f7660a00ae8a0cecb (patch)
treec79de87b7136e96b977003db85d43e5e676bbfc1 /src
parent85c654a102701958d3748e82ecac9c1bc4dbbcba (diff)
Start on amal program
Fix mutex issue in lhs expr which can cause a deadlock when a file has an error and throws and doesn't close the mutex and another thread waits for that mutex. The mutex can instead be removed and ignore race conditions which are uncommon. This should improve memory usage and performance.
Diffstat (limited to 'src')
-rw-r--r--src/ast.c27
-rw-r--r--src/bytecode/bytecode.c51
-rw-r--r--src/compiler.c81
-rw-r--r--src/parser.c12
-rw-r--r--src/program.c41
-rw-r--r--src/ssa/ssa.c4
-rw-r--r--src/std/buffer.c8
-rw-r--r--src/std/hash_map.c2
-rw-r--r--src/std/scoped_allocator.c30
-rw-r--r--src/tokenizer.c6
10 files changed, 153 insertions, 109 deletions
diff --git a/src/ast.c b/src/ast.c
index 4194737..69243f8 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -19,6 +19,7 @@ static void ast_resolve(Ast *self, AstCompilerContext *context);
static void resolve_data_init(AstResolveData *self) {
self->status = AST_NOT_RESOLVED;
+ self->parser = NULL;
self->type = NULL;
}
@@ -94,7 +95,7 @@ void structfield_init(StructField *self, BufferView name, BufferView type_name)
variable_init(&self->type, type_name);
}
-int lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator) {
+void lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, BufferView var_name) {
self->is_extern = is_extern;
self->is_pub = is_pub;
self->is_const = is_const;
@@ -102,8 +103,6 @@ int lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, Buff
self->type.value.variable = NULL;
self->var_name = var_name;
self->rhs_expr = NULL;
- return_if_error(scoped_allocator_create_mutex(allocator, &self->mutex));
- return 0;
}
void assignmentexpr_init(AssignmentExpr *self, Ast *lhs_expr, Ast *rhs_expr) {
@@ -159,7 +158,7 @@ int while_statement_init(WhileStatement *self, Scope *parent, ScopedAllocator *a
int scope_init(Scope *self, Scope *parent, ScopedAllocator *allocator) {
return_if_error(buffer_init(&self->ast_objects, allocator));
- return_if_error(hash_map_init(&self->named_objects, allocator, sizeof(Ast*), hash_compare_string, amal_hash_string));
+ return_if_error(hash_map_init(&self->named_objects, allocator, sizeof(Ast*), hash_map_compare_string, amal_hash_string));
self->parent = parent;
self->parser = NULL;
return 0;
@@ -627,6 +626,7 @@ static void while_statement_resolve(WhileStatement *while_stmt, AstCompilerConte
void ast_resolve(Ast *self, AstCompilerContext *context) {
assert(self);
+ assert(context->parser);
/*
TODO: Move these to the types that need checks for recursive dependency (function declaration, struct declaration)
For function declaration, it should be marked as resolved when the signature has been resolved
@@ -640,28 +640,15 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
*/
if(self->resolve_data.status == AST_RESOLVED) {
return;
- } else if(self->resolve_data.status == AST_RESOLVING) {
+ } else if(self->resolve_data.status == AST_RESOLVING && self->resolve_data.parser == context->parser) {
Parser *parser;
parser = scope_get_parser(context->scope);
parser_print_error(parser, ast_get_code_reference(self).data, "Found recursive dependency");
throw(AST_ERR);
}
- if(self->type == AST_LHS) {
- throw_if_error(amal_mutex_lock(self->value.lhs_expr->mutex, "ast_resolve"));
- if(self->resolve_data.status == AST_RESOLVED) {
- amal_mutex_tryunlock(self->value.lhs_expr->mutex);
- return;
- } else if(self->resolve_data.status == AST_RESOLVING) {
- Parser *parser;
- parser = scope_get_parser(context->scope);
- amal_mutex_tryunlock(self->value.lhs_expr->mutex);
- parser_print_error(parser, ast_get_code_reference(self).data, "Found recursive dependency");
- throw(AST_ERR);
- }
- }
-
self->resolve_data.status = AST_RESOLVING;
+ self->resolve_data.parser = context->parser;
switch(self->type) {
case AST_NUMBER: {
Number *number;
@@ -714,6 +701,4 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
}
/* TODO: See comment at the top of this function */
self->resolve_data.status = AST_RESOLVED;
- if(self->type == AST_LHS)
- amal_mutex_tryunlock(self->value.lhs_expr->mutex);
}
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 29d99c0..7c4fe08 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -19,7 +19,7 @@
} while(0)
int bytecode_init(Bytecode *self, ScopedAllocator *allocator) {
- return buffer_init(&self->instructions, allocator);
+ return buffer_init(&self->data, allocator);
}
static CHECK_RESULT usize ssa_extract_form1(u8 *instruction_data, SsaInsForm1 *result) {
@@ -59,7 +59,7 @@ static CHECK_RESULT usize ssa_extract_jump(u8 *instruction_data, SsaInsJump *res
}
static void add_header(BytecodeCompilerContext *self) {
- /*doc(BytecodeHeader)
+ /*doc(Bytecode header)
# Header layout
|Size|Name |Description |
|----|-------------|----------------------------------------------------------------------------|
@@ -76,7 +76,7 @@ static void add_header(BytecodeCompilerContext *self) {
const u8 patch_version = 0;
Buffer *instructions;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
throw_if_error(buffer_append(instructions, &magic_number, 4));
throw_if_error(buffer_append(instructions, &major_version, 1));
throw_if_error(buffer_append(instructions, &minor_version, 1));
@@ -90,7 +90,7 @@ static void add_intermediates(BytecodeCompilerContext *self) {
SsaNumber *intermediates_end;
ssa = self->parser->ssa;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
intermediate = buffer_begin(&ssa->intermediates);
intermediates_end = buffer_end(&ssa->intermediates);
@@ -108,20 +108,21 @@ void add_strings(BytecodeCompilerContext *self) {
Buffer *instructions;
BufferView *string;
BufferView *strings_end;
+ u32 strings_size;
ssa = self->parser->ssa;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
string = buffer_begin(&ssa->strings);
strings_end = buffer_end(&ssa->strings);
+ strings_size = 0;
- /*
- The 8 here is a arbitrary chosen number since we don't know the actual
- size of all strings without counting. The logic is that the average
- size of all strings length would be 8.
- */
- throw_if_error(buffer_expand(instructions,
- sizeof(u16) + (sizeof(u16) + 8) * ssa->strings.size));
- throw_if_error(buffer_append(instructions, &ssa->strings.size, sizeof(u16)));
+ for(; string != strings_end; ++string) {
+ strings_size += sizeof(u16) + string->size;
+ }
+ string = buffer_begin(&ssa->strings);
+
+ throw_if_error(buffer_expand(instructions, sizeof(u32) + strings_size));
+ throw_if_error(buffer_append(instructions, &strings_size, sizeof(u32)));
for(; string != strings_end; ++string) {
throw_if_error(buffer_append(instructions, &string->size, sizeof(u16)));
throw_if_error(buffer_append(instructions, &string->data, string->size));
@@ -129,7 +130,7 @@ void add_strings(BytecodeCompilerContext *self) {
}
static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const char *fmt) {
- throw_if_error(buffer_append(&self->bytecode->instructions, &opcode, sizeof(AmalOpcodeType)));
+ throw_if_error(buffer_append(&self->bytecode.data, &opcode, sizeof(AmalOpcodeType)));
fprintf(stderr, fmt);
fputc('\n', stderr);
}
@@ -138,7 +139,7 @@ static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const cha
static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, u8 reg, const char *fmt) {
Buffer *instructions;
size_t index;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(reg)));
@@ -151,7 +152,7 @@ static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, u8 reg, c
static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u8 src_reg, const char *fmt) {
Buffer *instructions;
size_t index;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(src_reg)));
@@ -165,7 +166,7 @@ static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_re
static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data, const char *fmt) {
Buffer *instructions;
size_t index;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(data)));
@@ -178,7 +179,7 @@ static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data,
static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u8 reg1, u8 reg2, const char *fmt) {
Buffer *instructions;
size_t index;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(reg1) + sizeof(reg2)));
@@ -193,7 +194,7 @@ static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_re
static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, u8 dst_reg, u16 data, const char *fmt) {
Buffer *instructions;
size_t index;
- instructions = &self->bytecode->instructions;
+ instructions = &self->bytecode.data;
index = instructions->size;
throw_if_error(buffer_append_empty(instructions, sizeof(AmalOpcodeType) + sizeof(dst_reg) + sizeof(data)));
@@ -237,6 +238,10 @@ static void add_instructions(BytecodeCompilerContext *self) {
FILE *file;
char *filename;
+
+ u32 num_instructions_index;
+ num_instructions_index = self->bytecode.data.size;
+ throw_if_error(buffer_append_empty(&self->bytecode.data, sizeof(num_instructions_index)));
#ifdef COMPILE_TO_C
LhsExpr *reg_types[NUM_MAX_REGS]; /* TODO: Remove this. Encode this data in the register itself */
SsaRegister func_arg_stack[NUM_MAX_FUNC_ARGS]; /* TODO: Remove this? */
@@ -470,6 +475,14 @@ static void add_instructions(BytecodeCompilerContext *self) {
assert(bool_false && "Instruction not yet implemented");
}
}
+
+ /* Prepend instructions with its size */
+ {
+ u32 instructions_size;
+ instructions_size = self->bytecode.data.size - num_instructions_index;
+ am_memcpy(&self->bytecode.data.data[num_instructions_index], &instructions_size, sizeof(instructions_size));
+ }
+
#endif /* COMPILE_TO_C */
fclose(file);
}
diff --git a/src/compiler.c b/src/compiler.c
index e7b242b..1af9537 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -12,6 +12,8 @@
#include <limits.h>
#include <assert.h>
+static void amal_compiler_deinit(amal_compiler *self);
+
static usize strnlen(const char *str, usize max_length) {
usize len;
len = 0;
@@ -31,9 +33,7 @@ static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char
return_if_error(structdecl_init(struct_decl, &compiler->root_scope, &compiler->allocator));
return_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(LhsExpr), (void**)lhs_expr));
- return_if_error(lhsexpr_init(*lhs_expr, bool_true, bool_true, bool_true,
- create_buffer_view(name, strnlen(name, PATH_MAX)),
- &compiler->allocator));
+ lhsexpr_init(*lhs_expr, bool_true, bool_true, bool_true, create_buffer_view(name, strnlen(name, PATH_MAX)));
return_if_error(ast_create(&compiler->allocator, struct_decl, AST_STRUCT_DECL, &(*lhs_expr)->rhs_expr));
return_if_error(ast_create(&compiler->allocator, *lhs_expr, AST_LHS, &expr));
expr->resolve_data.type = *lhs_expr;
@@ -64,7 +64,7 @@ void amal_compiler_options_init(amal_compiler_options *self) {
self->num_threads = 0;
}
-int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options) {
+static CHECK_RESULT int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options, amal_program *program) {
int i;
self->usable_thread_count = options ? options->num_threads : 0;
@@ -72,19 +72,20 @@ int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options
self->usable_thread_count = amal_get_usable_thread_count();
if(self->usable_thread_count == 0) {
amal_log_warning("Unable to get the number of threads available on the system, using 1 thread.");
- amal_log_warning("You can override the number of threads using by setting compiler option for number of thread to use.");
+ amal_log_warning("You can override the number of threads used by setting compiler option for number of thread to use.");
self->usable_thread_count = 1;
}
}
+ amal_log_info("Using %d threads", self->usable_thread_count);
am_memset(&self->allocator, 0, sizeof(self->allocator));
am_memset(&self->root_scope, 0, sizeof(self->root_scope));
if(options)
- am_memcpy(&self->options, options, sizeof(self->options));
+ self->options = *options;
else
- am_memset(&self->options, 0, sizeof(self->options));
+ amal_compiler_options_init(&self->options);
+ self->program = program;
self->started = bool_false;
- self->used = bool_false;
self->generic_work_object_index = 0;
amal_mutex_init(&self->mutex);
@@ -92,7 +93,7 @@ int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options
cleanup_if_error(scope_init(&self->root_scope, NULL, &self->allocator));
cleanup_if_error(buffer_init(&self->parsers, &self->allocator));
cleanup_if_error(buffer_init(&self->queued_files, &self->allocator));
- cleanup_if_error(hash_map_init(&self->file_scopes, &self->allocator, sizeof(FileScopeReference*), hash_compare_string, amal_hash_string));
+ cleanup_if_error(hash_map_init(&self->file_scopes, &self->allocator, sizeof(FileScopeReference*), hash_map_compare_string, amal_hash_string));
cleanup_if_error(scoped_allocator_alloc(&self->allocator,
self->usable_thread_count * sizeof(ParserThreadData),
(void**)&self->threads));
@@ -102,25 +103,18 @@ int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options
return AMAL_COMPILER_OK;
cleanup:
- ignore_result_int(amal_compiler_deinit(self));
+ amal_compiler_deinit(self);
return AMAL_COMPILER_ERR;
}
-int amal_compiler_deinit(amal_compiler *self) {
+void amal_compiler_deinit(amal_compiler *self) {
int i;
- int result;
- result = AMAL_COMPILER_OK;
-
for(i = 0; i < self->usable_thread_count; ++i) {
- int r;
- r = parser_thread_data_deinit(&self->threads[i]);
- if(r != 0)
- result = r;
+ parser_thread_data_deinit(&self->threads[i]);
}
amal_mutex_deinit(&self->mutex);
scoped_allocator_deinit(&self->allocator);
- return result;
}
typedef enum {
@@ -199,13 +193,19 @@ static void* thread_callback_parse_file(void *userdata) {
cleanup:
/*
- To stop all other parsers from working cleanly, we simply clear the file queue,
- and the other threads will stop when they are done with the file they are currently parsing.
+ To stop all other parsers from working cleanly, we simply clear the file queue,
+ and the other threads will stop when they are done with the file they are currently parsing.
*/
if(result != NULL) {
ignore_result_int(amal_mutex_lock(&compiler_parser_userdata.compiler->mutex, "thread_callback_parse_file"));
buffer_clear(&compiler_parser_userdata.compiler->queued_files);
}
+ /*
+ There can be a data race between writing to this and when this is read in @amal_compiler_load_file_join_threads.
+ This is intentional and it's ok, because the join_threads function checks against this status is guaranteed at this point
+ to not be a certain value that it checks for. Writing to an int is atomic.
+ TODO: Verify this is ok on all platforms.
+ */
compiler_parser_userdata.parser_thread_data->status = PARSER_THREAD_STATUS_IDLE;
amal_mutex_tryunlock(&compiler_parser_userdata.compiler->mutex);
return result;
@@ -215,6 +215,7 @@ static CHECK_RESULT int thread_resolve_ast(amal_compiler *compiler, Parser *pars
AstCompilerContext compiler_context;
int result;
compiler_context.compiler = compiler;
+ compiler_context.parser = parser;
compiler_context.scope = NULL;
result = setjmp(compiler_context.env);
if(result == 0) {
@@ -245,14 +246,15 @@ static CHECK_RESULT int thread_generate_bytecode(Parser *parser) {
BytecodeCompilerContext compiler_context;
int result;
- return_if_error(scoped_allocator_alloc(parser->allocator, sizeof(Bytecode), (void**)&compiler_context.bytecode));
- return_if_error(bytecode_init(compiler_context.bytecode, parser->allocator));
+ return_if_error(bytecode_init(&compiler_context.bytecode, parser->allocator));
compiler_context.parser = parser;
amal_log_debug("Generating bytecode for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data);
result = setjmp(compiler_context.env);
- if(result == 0)
+ if(result == 0) {
generate_bytecode_from_ssa(&compiler_context);
+ parser->bytecode = compiler_context.bytecode;
+ }
return result;
}
@@ -443,6 +445,17 @@ static CHECK_RESULT int amal_compiler_dispatch_generic(amal_compiler *self, Thre
return amal_compiler_load_file_join_threads(self);
}
+static CHECK_RESULT int amal_compiler_generate_program(amal_compiler *self) {
+ Parser **parser;
+ Parser **parser_end;
+ parser = buffer_begin(&self->parsers);
+ parser_end = buffer_end(&self->parsers);
+ for(; parser != parser_end; ++parser) {
+ return_if_error(amal_program_append_bytecode(self->program, &(*parser)->bytecode));
+ }
+ return 0;
+}
+
static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const char *filepath, FileScopeReference **file_scope, bool *new_entry) {
int ret;
char *result_path;
@@ -472,12 +485,16 @@ static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const cha
return ret;
}
-int amal_compiler_load_file(amal_compiler *self, const char *filepath) {
+int amal_compiler_load_file(amal_compiler_options *options, amal_program *program, const char *filepath) {
+ assert(program);
+ assert(filepath);
+ amal_compiler compiler;
FileScopeReference *file_scope;
- if(self->used)
- return AMAL_COMPILER_ERR;
- self->used = bool_true;
- return amal_compiler_internal_load_file(self, filepath, &file_scope);
+ int result;
+ return_if_error(amal_compiler_init(&compiler, options, program));
+ result = amal_compiler_internal_load_file(&compiler, filepath, &file_scope);
+ amal_compiler_deinit(&compiler);
+ return result;
}
int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) {
@@ -510,8 +527,7 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath,
return_if_error(amal_compiler_select_thread_for_work(self, thread_work_data, &parser_thread_data));
if(main_job) {
- /*doc(CompilerFlow)
- # Compiler flow
+ /*doc(Compiler flow)
(Tokenize&parse -> Resolve AST -> Generate SSA -> Generate bytecode) -> Generate program\
Each step except the last is done using multiple threads in parallel and the output of each step is used
in the next step. The last step is not done in parallel because the last step is combining all bytecode
@@ -535,6 +551,9 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath,
assert(amal_compiler_check_all_threads_done(self));
amal_log_info("Finished generating bytecode");
+ return_if_error(amal_compiler_generate_program(self));
+ amal_log_info("Finished generating program");
+
return AMAL_COMPILER_OK;
}
diff --git a/src/parser.c b/src/parser.c
index 68d0648..b61a968 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -33,10 +33,9 @@ int parser_thread_data_init(ParserThreadData *self) {
return scoped_allocator_init(&self->allocator);
}
-int parser_thread_data_deinit(ParserThreadData *self) {
+void parser_thread_data_deinit(ParserThreadData *self) {
ignore_result_int(amal_thread_deinit(&self->thread));
scoped_allocator_deinit(&self->allocator);
- return 0;
}
int parser_thread_data_start(ParserThreadData *self, AmalThreadCallbackFunc callback_func, void *userdata) {
@@ -62,10 +61,11 @@ int parser_init(Parser *self, amal_compiler *compiler, ScopedAllocator *allocato
self->error_context = ERROR_CONTEXT_NONE;
return_if_error(structdecl_init(&self->struct_decl, &compiler->root_scope, allocator));
self->struct_decl.body.parser = self;
- return_if_error(lhsexpr_init(&self->file_decl, bool_true, bool_true, bool_true, create_buffer_view_null(), self->allocator));
+ lhsexpr_init(&self->file_decl, bool_true, bool_true, bool_true, create_buffer_view_null());
return_if_error(ast_create(self->allocator, &self->struct_decl, AST_STRUCT_DECL, &self->file_decl.rhs_expr));
self->current_scope = &self->struct_decl.body;
self->has_func_parent = bool_false;
+ am_memset(&self->bytecode, 0, sizeof(self->bytecode));
return PARSER_OK;
}
@@ -202,7 +202,7 @@ static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) {
if(is_extern && self->has_func_parent) {
self->error = tokenizer_create_error(&self->tokenizer,
tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data),
- "Only declarations in structs can be extern");
+ "Only declarations in global structs can be extern");
throw(PARSER_UNEXPECTED_TOKEN);
}
@@ -210,7 +210,7 @@ static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) {
if(is_pub && self->has_func_parent) {
self->error = tokenizer_create_error(&self->tokenizer,
tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data),
- "Only declarations in structs can be public");
+ "Only declarations in global structs can be public");
throw(PARSER_UNEXPECTED_TOKEN);
}
@@ -233,7 +233,7 @@ static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) {
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER));
var_name = self->tokenizer.value.identifier;
throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&result));
- throw_if_error(lhsexpr_init(result, is_extern, is_pub, is_const, var_name, self->allocator));
+ lhsexpr_init(result, is_extern, is_pub, is_const, var_name);
ignore_result_int(parser_parse_var_type_def(self, &result->type));
return result;
diff --git a/src/program.c b/src/program.c
new file mode 100644
index 0000000..aa39a4c
--- /dev/null
+++ b/src/program.c
@@ -0,0 +1,41 @@
+#include "../include/program.h"
+#include <stdio.h>
+#include <errno.h>
+
+void amal_program_init(amal_program *self) {
+ ignore_result_int(buffer_init(&self->data, NULL));
+}
+
+void amal_program_deinit(amal_program *self) {
+ buffer_deinit(&self->data);
+}
+
+int amal_program_append_bytecode(amal_program *self, Bytecode *bytecode) {
+ return buffer_append(&self->data, bytecode->data.data, bytecode->data.size);
+}
+
+int amal_program_run(amal_program *self) {
+ /* TODO: Implement */
+ (void)self;
+ return 0;
+}
+
+int amal_program_save(amal_program *self, const char *filepath) {
+ FILE *file;
+ file = fopen(filepath, "wb");
+ if(!file) {
+ int err;
+ err = errno;
+ perror(filepath);
+ return -err;
+ }
+ if(fwrite(self->data.data, 1, self->data.size, file) != self->data.size) {
+ int err;
+ err = errno;
+ perror(filepath);
+ return -err;
+ }
+ fclose(file);
+ return 0;
+}
+
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index 34e3e3e..6e61bf1 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -17,7 +17,7 @@ do { \
} while(0)
/* Max length of a string that fits in u16 */
-#define MAX_STRING_LENGTH ((2 << 16) - 1)
+#define MAX_STRING_LENGTH UINT16_MAX
static int compare_number(const void *a, const void *b) {
const SsaNumber *lhs;
@@ -54,7 +54,7 @@ int ssa_init(Ssa *self, ScopedAllocator *allocator) {
return_if_error(buffer_init(&self->instructions, allocator));
return_if_error(hash_map_init(&self->intermediates_map, allocator, sizeof(SsaIntermediateIndex), compare_number, hash_number));
return_if_error(buffer_init(&self->intermediates, allocator));
- return_if_error(hash_map_init(&self->strings_map, allocator, sizeof(SsaStringIndex), hash_compare_string, amal_hash_string));
+ return_if_error(hash_map_init(&self->strings_map, allocator, sizeof(SsaStringIndex), hash_map_compare_string, amal_hash_string));
return_if_error(buffer_init(&self->strings, allocator));
self->intermediate_counter = 0;
self->string_counter = 0;
diff --git a/src/std/buffer.c b/src/std/buffer.c
index 3676cee..f4e93e5 100644
--- a/src/std/buffer.c
+++ b/src/std/buffer.c
@@ -17,6 +17,14 @@ int buffer_init(Buffer *self, struct ScopedAllocator *allocator) {
}
}
+void buffer_deinit(Buffer *self) {
+ assert(!self->allocator && "Can't deinit buffer if it has an allocator");
+ am_free(self->data);
+ self->data = NULL;
+ self->size = 0;
+ self->capacity = 0;
+}
+
static CHECK_RESULT int buffer_ensure_capacity(Buffer *self, usize new_capacity) {
usize capacity;
void *new_mem;
diff --git a/src/std/hash_map.c b/src/std/hash_map.c
index d13bf3d..1ad0dea 100644
--- a/src/std/hash_map.c
+++ b/src/std/hash_map.c
@@ -202,7 +202,7 @@ bool hash_map_get(HashMap *self, BufferView key, void *value) {
#define MIN(a, b) ((a) < (b) ? (a) : (b))
-int hash_compare_string(const void *a, const void *b) {
+int hash_map_compare_string(const void *a, const void *b) {
const BufferView *lhs;
const BufferView *rhs;
int mem_diff;
diff --git a/src/std/scoped_allocator.c b/src/std/scoped_allocator.c
index 84ec920..d8acbf6 100644
--- a/src/std/scoped_allocator.c
+++ b/src/std/scoped_allocator.c
@@ -27,15 +27,7 @@ void scoped_allocator_node_deinit(ScopedAllocatorNode *self) {
int scoped_allocator_init(ScopedAllocator *self) {
return_if_error(scoped_allocator_node_init(&self->head));
self->current = &self->head;
- return_if_error(buffer_init(&self->mems, NULL));
- return buffer_init(&self->mutexes, NULL);
-}
-
-static void buffer_deinit(Buffer *self) {
- am_free(self->data);
- self->data = NULL;
- self->size = 0;
- self->capacity = 0;
+ return buffer_init(&self->mems, NULL);
}
static void scoped_allocator_deinit_buffers(ScopedAllocator *self) {
@@ -50,22 +42,9 @@ static void scoped_allocator_deinit_buffers(ScopedAllocator *self) {
buffer_deinit(&self->mems);
}
-static void scoped_allocator_deinit_mutexes(ScopedAllocator *self) {
- amal_mutex **mutex;
- amal_mutex **mutexes_end;
- mutex = buffer_begin(&self->mutexes);
- mutexes_end = buffer_end(&self->mutexes);
- while(mutex != mutexes_end) {
- amal_mutex_deinit(*mutex);
- ++mutex;
- }
- buffer_deinit(&self->mutexes);
-}
-
void scoped_allocator_deinit(ScopedAllocator *self) {
self->current = NULL;
scoped_allocator_deinit_buffers(self);
- scoped_allocator_deinit_mutexes(self);
scoped_allocator_node_deinit(&self->head);
}
@@ -129,10 +108,3 @@ int scoped_allocator_add_mem(ScopedAllocator *self, usize *result_index) {
*result_index = buffer_get_size(&self->mems, sizeof(void*));
return buffer_append(&self->mems, &null_data, sizeof(void*));
}
-
-int scoped_allocator_create_mutex(ScopedAllocator *self, amal_mutex **mutex) {
- *mutex = NULL;
- return_if_error(scoped_allocator_alloc(self, sizeof(amal_mutex), (void**)mutex));
- amal_mutex_init(*mutex);
- return buffer_append(&self->mutexes, mutex, sizeof(amal_mutex*));
-}
diff --git a/src/tokenizer.c b/src/tokenizer.c
index bd57af7..bce386d 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -28,6 +28,11 @@ static int tokenizer_get_end_of_multiline_comment(Tokenizer *self, int index);
int tokenizer_init(Tokenizer *self, ScopedAllocator *allocator, BufferView code, BufferView code_name, const amal_compiler_options *compiler_options) {
assert(code.size <= INT_MAX);
assert(compiler_options);
+ /* Skip UTF-8 BOM */
+ if(code.size >= 3 && (u8)code.data[0] == 0xEF && (u8)code.data[1] == 0xBB && (u8)code.data[2] == 0xBF) {
+ code.data += 3;
+ code.size -= 3;
+ }
self->code = code;
self->index = 0;
self->prev_index = 0;
@@ -86,6 +91,7 @@ static CHECK_RESULT int find_end_of_string(BufferView buf, int index) {
}
/* TODO: Optimize string to integer and string to float */
+
#define I64_OVERFLOW_ERROR -1
static CHECK_RESULT int string_to_integer_unchecked(BufferView str, i64 *result) {
int i;