aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.sh6
-rw-r--r--include/ast.h1
-rw-r--r--include/bytecode/bytecode.h33
-rw-r--r--include/defs.h1
-rw-r--r--include/parser.h2
-rw-r--r--include/ssa/ssa.h36
-rw-r--r--include/std/buffer.h10
-rw-r--r--src/ast.c4
-rw-r--r--src/bytecode/bytecode.c126
-rw-r--r--src/compiler.c38
-rw-r--r--src/parser.c2
-rw-r--r--src/ssa/ssa.c83
-rw-r--r--src/std/buffer.c16
-rw-r--r--src/std/hash_map.c4
-rw-r--r--src/std/log.c2
-rw-r--r--src/std/scoped_allocator.c4
-rw-r--r--tests/main.c99
17 files changed, 365 insertions, 102 deletions
diff --git a/build.sh b/build.sh
index 240b2e9..87e18a6 100755
--- a/build.sh
+++ b/build.sh
@@ -28,13 +28,13 @@ LIBS+="-pthread"
BUILD_ARGS="$source_files $CFLAGS $LIBS -shared -fpic -o libamalgam.so"
set -x
-time "$CC" $BUILD_ARGS
+time $CC $BUILD_ARGS
if [ ! -z "$SCAN_BUILD" ]; then
- scan-build "$CC" $BUILD_ARGS
+ scan-build $CC $BUILD_ARGS
fi
set +x
if [ -z "$NO_TEST" ]; then
source_files_tests=$(readlink -f $(find "$this_script_dir/tests" -name "*.c"))
set -x
- time "$CC" $source_files_tests $CFLAGS $LIBS -o test "$this_script_dir/libamalgam.so"
+ time $CC $source_files_tests $CFLAGS $LIBS -o test "$this_script_dir/libamalgam.so"
fi
diff --git a/include/ast.h b/include/ast.h
index d37fcb3..c010538 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -17,7 +17,6 @@
#define AST_ERR -1
#define AST_ERR_DEF_DUP -20
-typedef struct FunctionDecl FunctionDecl;
typedef struct FunctionCall FunctionCall;
typedef struct StructDecl StructDecl;
typedef struct StructField StructField;
diff --git a/include/bytecode/bytecode.h b/include/bytecode/bytecode.h
new file mode 100644
index 0000000..3a141f0
--- /dev/null
+++ b/include/bytecode/bytecode.h
@@ -0,0 +1,33 @@
+#ifndef AMALGAM_BYTECODE_H
+#define AMALGAM_BYTECODE_H
+
+#include "../std/defs.h"
+#include "../std/misc.h"
+#include "../std/buffer.h"
+#include "../defs.h"
+
+#include <setjmp.h>
+
+typedef enum {
+ NOP, /* To allow hot-patching */
+
+} BytecodeInstruction;
+
+typedef u8 BytecodeInstructionType;
+
+typedef struct {
+ Buffer/*<instruction data>*/ instructions;
+} Bytecode;
+
+typedef struct {
+ jmp_buf env;
+ Bytecode *bytecode;
+ Parser *parser; /* borrowed */
+} BytecodeCompilerContext;
+
+CHECK_RESULT int bytecode_init(Bytecode *self, ScopedAllocator *allocator);
+
+/* longjump to self->env on failure */
+void generate_bytecode_from_ssa(BytecodeCompilerContext *self);
+
+#endif
diff --git a/include/defs.h b/include/defs.h
index 76e5e0d..d7f6692 100644
--- a/include/defs.h
+++ b/include/defs.h
@@ -6,5 +6,6 @@ typedef struct amal_compiler amal_compiler;
typedef struct Parser Parser;
typedef struct Scope Scope;
typedef struct FileScopeReference FileScopeReference;
+typedef struct FunctionDecl FunctionDecl;
#endif
diff --git a/include/parser.h b/include/parser.h
index 8a339ff..491815f 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -41,7 +41,7 @@ struct Parser {
bool has_func_parent;
ScopedAllocator *allocator; /* borrowed. Copied from @compiler for faster access to allocator */
amal_compiler *compiler;
- SsaCompilerContext *ssa_context;
+ Ssa *ssa;
bool started;
TokenizerError error;
ErrorContext error_context;
diff --git a/include/ssa/ssa.h b/include/ssa/ssa.h
index 16ceb25..32d1ba6 100644
--- a/include/ssa/ssa.h
+++ b/include/ssa/ssa.h
@@ -20,7 +20,7 @@ typedef enum {
SSA_FUNC_END,
SSA_PUSH,
SSA_CALL
-} SsaInstructionType;
+} SsaInstruction;
typedef enum {
SSA_NUMBER_TYPE_INTEGER,
@@ -42,7 +42,8 @@ typedef usize SsaFuncIndex;
typedef struct {
Buffer/*instruction data*/ instructions;
- HashMap/*<SsaNumberType, SsaIntermediateIndex>*/ intermediates;
+ HashMap/*<SsaNumber, SsaIntermediateIndex>*/ intermediates_map;
+ Buffer/*SsaNumber*/ intermediates;
HashMap/*<BufferView, SsaStringIndex>*/ strings;
SsaIntermediateIndex intermediate_counter;
SsaStringIndex string_counter;
@@ -50,28 +51,51 @@ typedef struct {
SsaFuncIndex func_counter;
} Ssa;
+typedef struct {
+ SsaRegister lhs;
+ u16 rhs;
+} SsaInsForm1;
+
+typedef struct {
+ SsaRegister result;
+ SsaRegister lhs;
+ SsaRegister rhs;
+} SsaInsForm2;
+
+typedef struct {
+ SsaFuncIndex func_index;
+ u8 num_args;
+} SsaInsFuncStart;
+
+typedef struct {
+ SsaRegister result;
+ FunctionDecl *func_decl;
+} SsaInsFuncCall;
+
/* None of these functions are thread-safe */
SsaNumber create_ssa_integer(i64 value);
SsaNumber create_ssa_float(f64 value);
+SsaNumber ssa_get_intermediate(Ssa *self, SsaIntermediateIndex index);
+
CHECK_RESULT int ssa_init(Ssa *self, ScopedAllocator *allocator);
CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result);
CHECK_RESULT int ssa_ins_assign_inter(Ssa *self, SsaRegister dest, SsaNumber number);
CHECK_RESULT int ssa_ins_assign_string(Ssa *self, SsaRegister dest, BufferView str);
CHECK_RESULT int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src);
-CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstructionType binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result);
+CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result);
CHECK_RESULT int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result);
CHECK_RESULT int ssa_ins_func_end(Ssa *self);
CHECK_RESULT int ssa_ins_push(Ssa *self, SsaRegister reg);
-CHECK_RESULT int ssa_ins_call(Ssa *self, void *func, SsaRegister *result);
+CHECK_RESULT int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result);
typedef struct {
jmp_buf env;
- Ssa ssa;
+ Ssa *ssa;
} SsaCompilerContext;
-/* longjump to compiler env on failure */
+/* longjump to context->env on failure */
void scope_generate_ssa(Scope *self, SsaCompilerContext *context);
#endif
diff --git a/include/std/buffer.h b/include/std/buffer.h
index 723ef6c..aa82bcc 100644
--- a/include/std/buffer.h
+++ b/include/std/buffer.h
@@ -16,13 +16,19 @@ typedef struct {
CHECK_RESULT int buffer_init(Buffer *self, struct ScopedAllocator *allocator);
-/* @data can be NULL */
+/*
+@data can't be null. Use @buffer_append_empty if you want to change the size
+of the buffer without adding data
+*/
CHECK_RESULT int buffer_append(Buffer *self, const void *data, usize size);
+CHECK_RESULT int buffer_append_empty(Buffer *self, usize size);
+/* Expand buffer capacity without changing size */
+CHECK_RESULT int buffer_expand(Buffer *self, usize size);
void* buffer_get(Buffer *self, usize index, usize type_size);
CHECK_RESULT int buffer_pop(Buffer *self, void *data, usize size);
/* Set buffer size to 0, doesn't reallocate */
void buffer_clear(Buffer *self);
-void* buffer_start(Buffer *self);
+void* buffer_begin(Buffer *self);
void* buffer_end(Buffer *self);
usize __buffer_get_size(Buffer *self, usize type_size);
#define buffer_get_size(self, type) __buffer_get_size((self), sizeof(type))
diff --git a/src/ast.c b/src/ast.c
index a9f9be2..680eb50 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -171,7 +171,7 @@ void scope_resolve(Scope *self, AstCompilerContext *context) {
Ast **ast;
Ast **ast_end;
- ast = buffer_start(&self->ast_objects);
+ ast = buffer_begin(&self->ast_objects);
ast_end = buffer_end(&self->ast_objects);
context->scope = self;
for(; ast != ast_end; ++ast) {
@@ -339,7 +339,7 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) {
throw(AST_ERR);
}
- ast = buffer_start(&func_call->args);
+ ast = buffer_begin(&func_call->args);
ast_end = buffer_end(&func_call->args);
for(; ast != ast_end; ++ast) {
ast_resolve(*ast, context);
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
new file mode 100644
index 0000000..7feb185
--- /dev/null
+++ b/src/bytecode/bytecode.c
@@ -0,0 +1,126 @@
+#include "../../include/bytecode/bytecode.h"
+#include "../../include/std/mem.h"
+#include "../../include/ssa/ssa.h"
+#include "../../include/parser.h"
+#include <assert.h>
+
+#define throw(result) do { throw_debug_msg; longjmp(self->env, (result)); } while(0)
+#define throw_if_error(result) \
+ do { \
+ int return_if_result; \
+ return_if_result = (result); \
+ if((return_if_result) != 0) \
+ throw(return_if_result); \
+ } while(0)
+
+int bytecode_init(Bytecode *self, ScopedAllocator *allocator) {
+ return buffer_init(&self->instructions, allocator);
+}
+
+static CHECK_RESULT usize ssa_extract_form1(u8 *instruction_data, SsaInsForm1 *result) {
+ am_memcpy(&result->lhs, instruction_data, sizeof(result->lhs));
+ am_memcpy(&result->rhs, instruction_data + sizeof(result->lhs), sizeof(result->rhs));
+ return sizeof(result->lhs) + sizeof(result->rhs);
+}
+
+static CHECK_RESULT usize ssa_extract_form2(u8 *instruction_data, SsaInsForm2 *result) {
+ am_memcpy(&result->result, instruction_data, sizeof(result->result));
+ am_memcpy(&result->lhs, instruction_data + sizeof(result->result), sizeof(result->lhs));
+ am_memcpy(&result->rhs, instruction_data + sizeof(result->result) + sizeof(result->lhs), sizeof(result->rhs));
+ return sizeof(result->result) + sizeof(result->lhs) + sizeof(result->rhs);
+}
+
+static CHECK_RESULT usize ssa_extract_func_start(u8 *instruction_data, SsaInsFuncStart *result) {
+ am_memcpy(&result->func_index, instruction_data, sizeof(result->func_index));
+ am_memcpy(&result->num_args, instruction_data + sizeof(result->func_index), sizeof(result->num_args));
+ return sizeof(result->func_index) + sizeof(result->num_args);
+}
+
+static CHECK_RESULT usize ssa_extract_func_call(u8 *instruction_data, SsaInsFuncCall *result) {
+ am_memcpy(&result->result, instruction_data, sizeof(result->result));
+ am_memcpy(&result->func_decl, instruction_data + sizeof(result->result), sizeof(result->func_decl));
+ return sizeof(result->result) + sizeof(result->func_decl);
+}
+
+static void add_intermediates(BytecodeCompilerContext *self) {
+ Ssa *ssa;
+ Buffer *instructions;
+ SsaNumber *intermediate;
+ SsaNumber *intermediates_end;
+
+ ssa = self->parser->ssa;
+ instructions = &self->bytecode->instructions;
+ intermediate = buffer_begin(&ssa->intermediates);
+ intermediates_end = buffer_end(&ssa->intermediates);
+
+ throw_if_error(buffer_expand(instructions,
+ sizeof(u16) + (sizeof(u8) + sizeof(u64)) * ssa->intermediates.size));
+ throw_if_error(buffer_append(instructions, &ssa->intermediates.size, sizeof(u16)));
+ for(; intermediate != intermediates_end; ++intermediate) {
+ throw_if_error(buffer_append(instructions, &intermediate->type, sizeof(u8)));
+ throw_if_error(buffer_append(instructions, &intermediate->value.integer, sizeof(u64)));
+ }
+}
+
+static void add_instructions(BytecodeCompilerContext *self) {
+ Ssa *ssa;
+ u8 *instruction;
+ u8 *instructions_end;
+ SsaInsForm1 ssa_ins_form1;
+ SsaInsForm2 ssa_ins_form2;
+ SsaInsFuncStart ssa_ins_func_start;
+ SsaInsFuncCall ssa_ins_func_call;
+
+ ssa = self->parser->ssa;
+ instruction = buffer_begin(&ssa->instructions);
+ instructions_end = buffer_end(&ssa->instructions);
+
+ while(instruction != instructions_end) {
+ switch(*instruction++) {
+ case SSA_ASSIGN_INTER: {
+ SsaNumber number;
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ number = ssa_get_intermediate(ssa, ssa_ins_form1.rhs);
+ (void)number;
+ break;
+ }
+ case SSA_ASSIGN_STRING:
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ break;
+ case SSA_ASSIGN_REG:
+ instruction += ssa_extract_form1(instruction, &ssa_ins_form1);
+ break;
+ case SSA_ADD:
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ break;
+ case SSA_SUB:
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ break;
+ case SSA_MUL:
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ break;
+ case SSA_DIV:
+ instruction += ssa_extract_form2(instruction, &ssa_ins_form2);
+ break;
+ case SSA_FUNC_START:
+ instruction += ssa_extract_func_start(instruction, &ssa_ins_func_start);
+ break;
+ case SSA_FUNC_END:
+ break;
+ case SSA_PUSH: {
+ SsaRegister reg;
+ am_memcpy(&reg, instruction, sizeof(SsaRegister));
+ instruction += sizeof(SsaRegister);
+ break;
+ }
+ case SSA_CALL:
+ instruction += ssa_extract_func_call(instruction, &ssa_ins_func_call);
+ break;
+ }
+ }
+}
+
+void generate_bytecode_from_ssa(BytecodeCompilerContext *self) {
+ add_intermediates(self);
+ add_instructions(self);
+}
diff --git a/src/compiler.c b/src/compiler.c
index d10d9fb..3a921c3 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -1,6 +1,7 @@
#include "../include/compiler.h"
#include "../include/parser.h"
#include "../include/ssa/ssa.h"
+#include "../include/bytecode/bytecode.h"
#include "../include/std/log.h"
#include "../include/std/mem.h"
#include "../include/std/hash.h"
@@ -236,28 +237,35 @@ static CHECK_RESULT int thread_resolve_ast(amal_compiler *compiler, Parser *pars
}
static CHECK_RESULT int thread_generate_ssa(Parser *parser) {
- SsaCompilerContext *compiler_context;
+ SsaCompilerContext compiler_context;
int result;
- return_if_error(scoped_allocator_alloc(parser->allocator, sizeof(SsaCompilerContext), (void**)&compiler_context));
- return_if_error(ssa_init(&compiler_context->ssa, parser->allocator));
- /* TODO: Maybe instead of creating a ssa context for every parser (every file), create one for every thread */
- parser->ssa_context = compiler_context;
+ return_if_error(scoped_allocator_alloc(parser->allocator, sizeof(Ssa), (void**)&compiler_context.ssa));
+ return_if_error(ssa_init(compiler_context.ssa, parser->allocator));
+ parser->ssa = compiler_context.ssa;
amal_log_debug("Generating SSA for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data);
- result = setjmp(compiler_context->env);
+ result = setjmp(compiler_context.env);
if(result == 0)
- scope_generate_ssa(&parser->struct_decl.body, compiler_context);
+ scope_generate_ssa(&parser->struct_decl.body, &compiler_context);
return result;
}
-static CHECK_RESULT int thread_generate_bytecode(amal_compiler *compiler, Parser *parser) {
- /* TODO: Implement */
- (void)compiler;
- (void)parser;
- /*assert(bool_false);*/
- return 0;
+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));
+ 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)
+ generate_bytecode_from_ssa(&compiler_context);
+
+ return result;
}
/* TODO: Handle errors (stop work in all other threads and report errors/warnings) */
@@ -285,7 +293,7 @@ static void* thread_callback_generic(void *userdata) {
cleanup_if_error(thread_generate_ssa(parser));
break;
case THREAD_WORK_GENERATE_BYTECODE:
- cleanup_if_error(thread_generate_bytecode(compiler_userdata.compiler, parser));
+ cleanup_if_error(thread_generate_bytecode(parser));
break;
}
cleanup_if_error(amal_mutex_lock(&compiler_userdata.compiler->mutex, "thread_callback_generic"));
@@ -430,7 +438,7 @@ static CHECK_RESULT int amal_compiler_load_file_join_threads(amal_compiler *self
static CHECK_RESULT int amal_compiler_dispatch_generic(amal_compiler *self, ThreadWorkType work_type) {
Parser **parser;
Parser **parser_end;
- parser = buffer_start(&self->parsers);
+ parser = buffer_begin(&self->parsers);
parser_end = buffer_end(&self->parsers);
self->generic_work_object_index = 0;
for(; parser != parser_end; ++parser) {
diff --git a/src/parser.c b/src/parser.c
index 9aa8924..8e122fd 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -54,7 +54,7 @@ int parser_thread_data_join(ParserThreadData *self, void **result) {
int parser_init(Parser *self, amal_compiler *compiler, ScopedAllocator *allocator) {
self->allocator = allocator;
self->compiler = compiler;
- self->ssa_context = NULL;
+ self->ssa = NULL;
self->started = bool_false;
self->error.index = 0;
self->error.str = NULL;
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index 2391778..3afe7ed 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -48,7 +48,8 @@ SsaNumber create_ssa_float(f64 value) {
int ssa_init(Ssa *self, ScopedAllocator *allocator) {
return_if_error(buffer_init(&self->instructions, allocator));
- return_if_error(hash_map_init(&self->intermediates, allocator, sizeof(SsaIntermediateIndex), compare_number, hash_number));
+ 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, allocator, sizeof(SsaStringIndex), hash_compare_string, amal_hash_string));
self->intermediate_counter = 0;
self->string_counter = 0;
@@ -65,6 +66,13 @@ int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
return 0;
}
+SsaNumber ssa_get_intermediate(Ssa *self, SsaIntermediateIndex index) {
+ SsaNumber result;
+ assert(index < buffer_get_size(&self->intermediates, SsaNumber));
+ am_memcpy(&result, buffer_get(&self->intermediates, index, sizeof(SsaNumber)), sizeof(result));
+ return result;
+}
+
static CHECK_RESULT int ssa_try_add_intermediate(Ssa *self, SsaNumber number, SsaIntermediateIndex *result_index) {
bool exists;
BufferView key;
@@ -72,7 +80,7 @@ static CHECK_RESULT int ssa_try_add_intermediate(Ssa *self, SsaNumber number, Ss
assert(result_index);
key = create_buffer_view((const char*)&number, sizeof(number));
- exists = hash_map_get(&self->intermediates, key, result_index);
+ exists = hash_map_get(&self->intermediates_map, key, result_index);
if(exists)
return 0;
@@ -92,7 +100,9 @@ static CHECK_RESULT int ssa_try_add_intermediate(Ssa *self, SsaNumber number, Ss
break;
}
}
- return hash_map_insert(&self->intermediates, key, result_index);
+
+ return_if_error(buffer_append(&self->intermediates, &number, sizeof(number)));
+ return hash_map_insert(&self->intermediates_map, key, result_index);
}
static CHECK_RESULT int ssa_try_add_string(Ssa *self, BufferView str, SsaStringIndex *result_index) {
@@ -113,18 +123,18 @@ static CHECK_RESULT int ssa_try_add_string(Ssa *self, BufferView str, SsaStringI
return hash_map_insert(&self->strings, str, result_index);
}
-static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstructionType ins_type, SsaRegister lhs, u16 rhs) {
+static CHECK_RESULT int ssa_add_ins_form1(Ssa *self, SsaInstruction ins_type, SsaRegister lhs, u16 rhs) {
usize index;
index = self->instructions.size;
- return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister) + sizeof(u16)));
+ return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(u16)));
self->instructions.data[index + 0] = ins_type;
am_memcpy(self->instructions.data + index + 1, &lhs, sizeof(lhs));
am_memcpy(self->instructions.data + index + 3, &rhs, sizeof(rhs));
return 0;
}
-static const char* binop_type_to_string(SsaInstructionType binop_type) {
+static const char* binop_type_to_string(SsaInstruction binop_type) {
assert(binop_type >= SSA_ADD && binop_type <= SSA_DIV);
switch(binop_type) {
case SSA_ADD: return "+";
@@ -135,7 +145,7 @@ static const char* binop_type_to_string(SsaInstructionType binop_type) {
}
}
-static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstructionType ins_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
+static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstruction ins_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
usize index;
index = self->instructions.size;
@@ -144,7 +154,7 @@ static CHECK_RESULT int ssa_add_ins_form2(Ssa *self, SsaInstructionType ins_type
return -1;
assert(result);
- return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister) + sizeof(SsaRegister) + sizeof(SsaRegister)));
+ return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister) + sizeof(SsaRegister) + sizeof(SsaRegister)));
*result = self->reg_counter++;
self->instructions.data[index + 0] = ins_type;
am_memcpy(self->instructions.data + index + 1, &result, sizeof(*result));
@@ -173,7 +183,7 @@ int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegister src) {
return ssa_add_ins_form1(self, SSA_ASSIGN_REG, dest, src);
}
-int ssa_ins_binop(Ssa *self, SsaInstructionType binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
+int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
assert(binop_type >= SSA_ADD && binop_type <= SSA_DIV);
return ssa_add_ins_form2(self, binop_type, lhs, rhs, result);
}
@@ -186,11 +196,11 @@ int ssa_ins_func_start(Ssa *self, u8 num_args, SsaFuncIndex *result) {
if(self->func_counter + 1 < self->func_counter)
return -1;
- return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(u8)));
+ return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(u8)));
*result = self->func_counter++;
self->instructions.data[index + 0] = SSA_FUNC_START;
am_memcpy(self->instructions.data + index + 1, result, sizeof(*result));
- self->instructions.data[index + 3] = num_args;
+ self->instructions.data[index + 1 + sizeof(SsaFuncIndex)] = num_args;
amal_log_debug("FUNC_START f%u(%u)", *result, num_args);
return 0;
}
@@ -206,14 +216,14 @@ int ssa_ins_push(Ssa *self, SsaRegister reg) {
usize index;
index = self->instructions.size;
- return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaRegister)));
+ return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(SsaRegister)));
self->instructions.data[index + 0] = SSA_PUSH;
am_memcpy(self->instructions.data + index + 1, &reg, sizeof(reg));
amal_log_debug("PUSH r%u", reg);
return 0;
}
-int ssa_ins_call(Ssa *self, void *func, SsaRegister *result) {
+int ssa_ins_call(Ssa *self, FunctionDecl *func_decl, SsaRegister *result) {
usize index;
index = self->instructions.size;
@@ -221,12 +231,12 @@ int ssa_ins_call(Ssa *self, void *func, SsaRegister *result) {
if(self->reg_counter + 1 < self->reg_counter)
return -1;
- return_if_error(buffer_append(&self->instructions, NULL, sizeof(u8) + sizeof(SsaFuncIndex) + sizeof(SsaRegister)));
+ return_if_error(buffer_append_empty(&self->instructions, sizeof(u8) + sizeof(func_decl) + sizeof(SsaRegister)));
*result = self->reg_counter++;
self->instructions.data[index + 0] = SSA_CALL;
- am_memcpy(self->instructions.data + index + 1, &func, sizeof(func));
- am_memcpy(self->instructions.data + index + 3, result, sizeof(*result));
- amal_log_debug("r%u = CALL %p", *result, func);
+ am_memcpy(self->instructions.data + index + 1, result, sizeof(*result));
+ am_memcpy(self->instructions.data + index + 1 + sizeof(func_decl), &func_decl, sizeof(func_decl));
+ amal_log_debug("r%u = CALL %p", *result, func_decl);
return 0;
}
@@ -237,12 +247,12 @@ static CHECK_RESULT SsaRegister number_generate_ssa(Number *self, SsaCompilerCon
SsaNumber number;
if(self->is_integer) {
number = create_ssa_integer(self->value.integer);
- throw_if_error(ssa_get_unique_reg(&context->ssa, &reg));
- throw_if_error(ssa_ins_assign_inter(&context->ssa, reg, number));
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
} else {
number = create_ssa_float(self->value.floating);
- throw_if_error(ssa_get_unique_reg(&context->ssa, &reg));
- throw_if_error(ssa_ins_assign_inter(&context->ssa, reg, number));
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ throw_if_error(ssa_ins_assign_inter(context->ssa, reg, number));
}
return reg;
}
@@ -266,14 +276,15 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
*/
if(self->resolve_data.type == lhs_expr || lhs_expr->rhs_expr->type == AST_IMPORT)
return 0;
- throw_if_error(ssa_get_unique_reg(&context->ssa, &reg));
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
if(reg == rhs_reg) {
amal_log_error("rhs_expr is same as reg.. rhs type: %d", lhs_expr->rhs_expr->type);
}
assert(reg != rhs_reg);
- throw_if_error(ssa_ins_assign_reg(&context->ssa, reg, rhs_reg));
+ throw_if_error(ssa_ins_assign_reg(context->ssa, reg, rhs_reg));
} else {
/* TODO: assign default value to reg depending on LhsExpr type */
+ reg = 0;
}
return reg;
}
@@ -284,10 +295,16 @@ in any order.
*/
static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCompilerContext *context) {
/* TODO: Implement */
+ SsaRegister prev_reg_counter;
+ prev_reg_counter = context->ssa->reg_counter;
+ context->ssa->reg_counter = 0;
+
amal_log_debug("SSA funcdecl %p", self);
- throw_if_error(ssa_ins_func_start(&context->ssa, 0, &self->ssa_func_index));
+ throw_if_error(ssa_ins_func_start(context->ssa, 0, &self->ssa_func_index));
scope_generate_ssa(&self->body, context);
- throw_if_error(ssa_ins_func_end(&context->ssa));
+ throw_if_error(ssa_ins_func_end(context->ssa));
+
+ context->ssa->reg_counter = prev_reg_counter;
return 0;
}
@@ -301,12 +318,12 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont
assert(self->type == AST_FUNCTION_CALL);
func_call = self->value.func_call;
- ast = buffer_start(&func_call->args);
+ ast = buffer_begin(&func_call->args);
ast_end = buffer_end(&func_call->args);
for(; ast != ast_end; ++ast) {
SsaRegister arg_reg;
arg_reg = ast_generate_ssa(*ast, context);
- throw_if_error(ssa_ins_push(&context->ssa, arg_reg));
+ throw_if_error(ssa_ins_push(context->ssa, arg_reg));
}
assert(self->resolve_data.type->rhs_expr->type == AST_FUNCTION_DECL);
@@ -316,7 +333,7 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont
then there is no need for mutex locks.
*/
amal_log_debug("SSA funccall %.*s, func index ptr: %p", func_call->func.name.size, func_call->func.name.data, func_to_call);
- throw_if_error(ssa_ins_call(&context->ssa, func_to_call, &reg));
+ throw_if_error(ssa_ins_call(context->ssa, func_to_call, &reg));
return reg;
}
@@ -335,8 +352,8 @@ static CHECK_RESULT SsaRegister structfield_generate_ssa(StructField *self, SsaC
static CHECK_RESULT SsaRegister string_generate_ssa(String *self, SsaCompilerContext *context) {
SsaRegister reg;
- throw_if_error(ssa_get_unique_reg(&context->ssa, &reg));
- throw_if_error(ssa_ins_assign_string(&context->ssa, reg, self->str));
+ throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
+ throw_if_error(ssa_ins_assign_string(context->ssa, reg, self->str));
return reg;
}
@@ -347,7 +364,7 @@ static CHECK_RESULT SsaRegister variable_generate_ssa(Variable *self, SsaCompile
return 0;
}
-static SsaInstructionType binop_type_to_ssa_type(BinopType binop_type) {
+static SsaInstruction binop_type_to_ssa_type(BinopType binop_type) {
switch(binop_type) {
case BINOP_ADD:
return SSA_ADD;
@@ -374,7 +391,7 @@ static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerConte
} else {
lhs_reg = ast_generate_ssa(self->lhs, context);
rhs_reg = ast_generate_ssa(self->rhs, context);
- throw_if_error(ssa_ins_binop(&context->ssa, binop_type_to_ssa_type(self->type), lhs_reg, rhs_reg, &reg));
+ throw_if_error(ssa_ins_binop(context->ssa, binop_type_to_ssa_type(self->type), lhs_reg, rhs_reg, &reg));
}
return reg;
}
@@ -416,7 +433,7 @@ CHECK_RESULT SsaRegister ast_generate_ssa(Ast *self, SsaCompilerContext *context
void scope_generate_ssa(Scope *self, SsaCompilerContext *context) {
Ast **ast;
Ast **ast_end;
- ast = buffer_start(&self->ast_objects);
+ ast = buffer_begin(&self->ast_objects);
ast_end = buffer_end(&self->ast_objects);
for(; ast != ast_end; ++ast) {
ignore_result_int(ast_generate_ssa(*ast, context));
diff --git a/src/std/buffer.c b/src/std/buffer.c
index 8e23a30..5fb4b05 100644
--- a/src/std/buffer.c
+++ b/src/std/buffer.c
@@ -40,13 +40,23 @@ static CHECK_RESULT int buffer_ensure_capacity(Buffer *self, usize new_capacity)
}
int buffer_append(Buffer *self, const void *data, usize size) {
+ assert(data);
return_if_error(buffer_ensure_capacity(self, self->size + size));
- if(data)
- am_memcpy(self->data + self->size, data, size);
+ am_memcpy(self->data + self->size, data, size);
self->size += size;
return BUFFER_OK;
}
+int buffer_append_empty(Buffer *self, usize size) {
+ return_if_error(buffer_ensure_capacity(self, self->size + size));
+ self->size += size;
+ return BUFFER_OK;
+}
+
+int buffer_expand(Buffer *self, usize size) {
+ return buffer_ensure_capacity(self, self->size + size);
+}
+
void* buffer_get(Buffer *self, usize index, usize type_size) {
usize real_index;
real_index = index * type_size;
@@ -66,7 +76,7 @@ void buffer_clear(Buffer *self) {
self->size = 0;
}
-void* buffer_start(Buffer *self) {
+void* buffer_begin(Buffer *self) {
return self->data;
}
diff --git a/src/std/hash_map.c b/src/std/hash_map.c
index d9914e7..d13bf3d 100644
--- a/src/std/hash_map.c
+++ b/src/std/hash_map.c
@@ -84,7 +84,7 @@ int hash_map_init(HashMap *self, ScopedAllocator *allocator, usize value_type_si
self->hash_func = hash_func;
return_if_error(buffer_init(&self->buckets, self->allocator));
assert(self->buckets.size == 0);
- return_if_error(buffer_append(&self->buckets, NULL, sizeof(HashMapBucket) * HASH_MAP_INITIAL_SIZE));
+ return_if_error(buffer_append_empty(&self->buckets, sizeof(HashMapBucket) * HASH_MAP_INITIAL_SIZE));
am_memset(self->buckets.data, 0, self->buckets.size);
return 0;
}
@@ -150,7 +150,7 @@ static CHECK_RESULT int hash_map_increase_buckets(HashMap *self) {
usize bytes_to_append;
prev_num_elements = buffer_get_size(&self->buckets, HashMapBucket);
bytes_to_append = (usize)(prev_num_elements * 1.5) * sizeof(HashMapBucket);
- return_if_error(buffer_append(&self->buckets, NULL, bytes_to_append));
+ return_if_error(buffer_append_empty(&self->buckets, bytes_to_append));
am_memset(((HashMapBucket*)self->buckets.data) + prev_num_elements, 0, bytes_to_append);
hash_map_reorder_nodes(self, prev_num_elements);
return 0;
diff --git a/src/std/log.c b/src/std/log.c
index a03e62f..88ff0cf 100644
--- a/src/std/log.c
+++ b/src/std/log.c
@@ -72,4 +72,4 @@ void amal_log_warning(const char *fmt, ...) {
va_end(args);
fprintf(stderr, "\n");
ignore_result_int(amal_mutex_unlock(&mutex));
-} \ No newline at end of file
+}
diff --git a/src/std/scoped_allocator.c b/src/std/scoped_allocator.c
index 3104fd3..8b161a1 100644
--- a/src/std/scoped_allocator.c
+++ b/src/std/scoped_allocator.c
@@ -41,7 +41,7 @@ static void buffer_deinit(Buffer *self) {
static void scoped_allocator_deinit_buffers(ScopedAllocator *self) {
Buffer **buffer;
Buffer **buffers_end;
- buffer = buffer_start(&self->buffers);
+ buffer = buffer_begin(&self->buffers);
buffers_end = buffer_end(&self->buffers);
while(buffer != buffers_end) {
buffer_deinit(*buffer);
@@ -53,7 +53,7 @@ static void scoped_allocator_deinit_buffers(ScopedAllocator *self) {
static void scoped_allocator_deinit_mutexes(ScopedAllocator *self) {
amal_mutex **mutex;
amal_mutex **mutexes_end;
- mutex = buffer_start(&self->mutexes);
+ mutex = buffer_begin(&self->mutexes);
mutexes_end = buffer_end(&self->mutexes);
while(mutex != mutexes_end) {
amal_mutex_deinit(*mutex);
diff --git a/tests/main.c b/tests/main.c
index bc2fbb1..04f2343 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -50,6 +50,10 @@ typedef struct {
bool got_expected_error;
} ErrorExpectedData;
+typedef struct {
+ char *filepath;
+} ErrorUnexpectedData;
+
static void error_callback_assert(const char *err_msg, int err_msg_len, void *userdata) {
ErrorExpectedData *expected_data;
expected_data = userdata;
@@ -71,6 +75,13 @@ static void error_callback_assert(const char *err_msg, int err_msg_len, void *us
expected_data->got_expected_error = bool_true;
}
+static void error_callback(const char *err_msg, int err_msg_len, void *userdata) {
+ ErrorUnexpectedData *data;
+ data = userdata;
+ fprintf(stderr, "Test failed: %s with error: %.*s\n", data->filepath, err_msg_len, err_msg);
+ exit(1);
+}
+
static char* get_full_path(const char *filepath) {
#define PATH_LEN 4096
char *buf;
@@ -106,6 +117,38 @@ static char* join_str(const char *str1, const char *str2, char delimiter) {
return buf;
}
+static void test_load(const char *filepath) {
+ amal_compiler compiler;
+ amal_compiler_options options;
+ int result;
+
+ amal_compiler_options_init(&options);
+ options.error_callback = error_callback;
+ ErrorUnexpectedData data;
+ data.filepath = get_full_path(filepath);
+ options.error_callback_userdata = &data;
+
+ result = amal_compiler_init(&compiler, &options);
+ if(result != AMAL_COMPILER_OK) {
+ fprintf(stderr, "Failed to initialize compiler, error code: %d\n", result);
+ FAIL_TEST(data.filepath);
+ }
+
+ result = amal_compiler_load_file(&compiler, filepath);
+ if(result != AMAL_COMPILER_OK) {
+ fprintf(stderr, "Failed to load file %s, result: %d\n", data.filepath, result);
+ FAIL_TEST(data.filepath);
+ }
+
+ if(amal_compiler_deinit(&compiler) != 0) {
+ fprintf(stderr, "Failed to deinitialize compiler.\n");
+ FAIL_TEST(data.filepath);
+ }
+
+ fprintf(stderr, "Test succeeded: %s\n", data.filepath);
+ free(data.filepath);
+}
+
static void test_load_error(const char *filepath, const char *expected_error) {
amal_compiler compiler;
amal_compiler_options options;
@@ -140,43 +183,39 @@ static void test_load_error(const char *filepath, const char *expected_error) {
fprintf(stderr, "Didn't get expected error message:\n%s\n", expected_error);
FAIL_TEST(expected_data.filepath);
}
+
+ fprintf(stderr, "Test succeeded: %s\n", expected_data.filepath);
free(expected_data.filepath);
free(expected_data.expected_error);
}
/* TODO: Restrict variables in global scope to const */
-int main() {
- /*amal_compiler compiler;
- int result;*/
-
+int main(int argc, char **argv) {
return_if_error(test_hash_map());
- /*
- result = amal_compiler_init(&compiler, NULL);
- if(result != AMAL_COMPILER_OK) {
- fprintf(stderr, "Failed to initialize compiler, error code: %d\n", result);
- return 1;
- }
-
- result = amal_compiler_load_file(&compiler, "tests/main.amal");
- if(result != AMAL_COMPILER_OK) {
- fprintf(stderr, "Failed to load file, error code: %d\n", result);
- return 1;
+ /* Run all tests */
+ if(argc == 1) {
+ test_load("tests/main.amal");
+ test_load_error("tests/errors/duplicate_declaration.amal",
+ "2:7: error: Variable with the name main was declared twice in the same scope\n"
+ "const main = fn {}\n"
+ " ^\n");
+ test_load_error("tests/errors/pub_in_closure.amal",
+ "2:5: error: Only declarations in structs can be public\n"
+ " pub const num = 45;\n"
+ " ^\n");
+ test_load_error("tests/errors/closure_no_lhs.amal",
+ "1:1: error: Expected variable declaration, string, variable or function call\n"
+ "fn {}\n"
+ "^\n");
+ } else if(argc == 2) {
+ test_load(argv[1]);
+ } else {
+ fprintf(stderr, "usage: test [test-file-path]\n");
+ fprintf(stderr, "examples:\n");
+ fprintf(stderr, " test\n");
+ fprintf(stderr, " test tests/main.amal\n");
+ exit(1);
}
-
- return amal_compiler_deinit(&compiler);
- */
- test_load_error("tests/errors/duplicate_declaration.amal",
- "2:7: error: Variable with the name main was declared twice in the same scope\n"
- "const main = fn {}\n"
- " ^\n");
- test_load_error("tests/errors/pub_in_closure.amal",
- "2:5: error: Only declarations in structs can be public\n"
- " pub const num = 45;\n"
- " ^\n");
- test_load_error("tests/errors/closure_no_lhs.amal",
- "1:1: error: Expected variable declaration, string, variable or function call\n"
- "fn {}\n"
- "^\n");
return 0;
}