aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-07-31 22:29:24 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commit0f26e1d204d3a3026ca3edfc4c6bd9638b2632e7 (patch)
treede196ca25cf8f685e14b219198162d68c61efcfd /src
parentfa2a9e79e21063137f863887adc88fc74d3573e2 (diff)
Add nullable, add bytecode documentation
Diffstat (limited to 'src')
-rw-r--r--src/asm/x86_64.c2
-rw-r--r--src/ast.c31
-rw-r--r--src/bytecode/bytecode.c44
-rw-r--r--src/compiler.c2
-rw-r--r--src/nullable.c8
-rw-r--r--src/parser.c12
-rw-r--r--src/program.c28
-rw-r--r--src/ssa/ssa.c27
-rw-r--r--src/std/arena_allocator.c2
9 files changed, 99 insertions, 57 deletions
diff --git a/src/asm/x86_64.c b/src/asm/x86_64.c
index 2cbeead..16e6bc6 100644
--- a/src/asm/x86_64.c
+++ b/src/asm/x86_64.c
@@ -109,9 +109,11 @@ static CHECK_RESULT int asm_ensure_capacity(Asm *self, usize size) {
return 0;
}
+#ifdef DEBUG
static isize asm_get_capacity_left(Asm *self) {
return (isize)self->size - (isize)((u8*)self->code_it - (u8*)self->code);
}
+#endif
int asm_nop(Asm *self) {
return_if_error(asm_ensure_capacity(self, 1));
diff --git a/src/ast.c b/src/ast.c
index 35ece2e..db2f61d 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -107,7 +107,7 @@ void lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, Buf
self->type.type = VARIABLE_TYPE_NONE;
self->type.value.variable = NULL;
self->var_name = var_name;
- self->rhs_expr = NULL;
+ nullable_assign(self->rhs_expr, NULL);
}
void assignmentexpr_init(AssignmentExpr *self, Ast *lhs_expr, Ast *rhs_expr) {
@@ -333,11 +333,11 @@ static BufferView variable_type_get_name(VariableType *self) {
static LhsExpr* lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context) {
LhsExpr *rhs_resolved_type;
- ast_resolve(self->rhs_expr, context);
- if(ast_is_decl(self->rhs_expr))
+ ast_resolve(nullable_unwrap(self->rhs_expr), context);
+ if(ast_is_decl(nullable_unwrap(self->rhs_expr)))
rhs_resolved_type = self;
else
- rhs_resolved_type = self->rhs_expr->resolve_data.type;
+ rhs_resolved_type = nullable_unwrap(self->rhs_expr)->resolve_data.type;
return rhs_resolved_type;
}
@@ -354,15 +354,15 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
the parameters and return types have been resolved as recursive function calls should
be allowed but recursive function calls still require parameters and return types to be known.
*/
- if(self->rhs_expr) {
+ if(is_not_null(self->rhs_expr)) {
LhsExpr *rhs_resolve_type;
- if(self->rhs_expr->type == AST_FUNCTION_DECL) {
+ if(nullable_unwrap(self->rhs_expr)->type == AST_FUNCTION_DECL) {
/*
The function declaration itself always resolves the signature, but we also do it here because we
want to have the signature solved before setting the lhs expr as solved. Also function signatures can exist
without lhs expr (anonymous function).
*/
- function_signature_resolve(self->rhs_expr->value.func_decl->signature, context);
+ function_signature_resolve(nullable_unwrap(self->rhs_expr)->value.func_decl->signature, context);
ast->resolve_data.status = AST_RESOLVED;
/*
If rhs is a function declaration then there is no need to wait until it has been resolved before setting the type as the type
@@ -374,9 +374,8 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
rhs_resolve_type = lhsexpr_resolve_rhs(self, context);
- /* self->rhs_expr can be null here because this is valid: var num: i32; */
/* TODO: Add casting */
- if(ast->resolve_data.type && self->rhs_expr && ast->resolve_data.type != rhs_resolve_type) {
+ if(ast->resolve_data.type && ast->resolve_data.type != rhs_resolve_type) {
Parser *parser;
parser = scope_get_parser(context->scope);
/*
@@ -463,9 +462,9 @@ static void import_resolve(Ast *ast, AstCompilerContext *context) {
static Scope* lhsexpr_get_scope(LhsExpr *self) {
AstValue value;
- if(self->rhs_expr) {
- value = self->rhs_expr->value;
- switch(self->rhs_expr->type) {
+ if(is_not_null(self->rhs_expr)) {
+ value = nullable_unwrap(self->rhs_expr)->value;
+ switch(nullable_unwrap(self->rhs_expr)->type) {
case AST_FUNCTION_DECL:
return &value.func_decl->body;
case AST_STRUCT_DECL:
@@ -496,9 +495,9 @@ static void funcdecl_resolve(FunctionDecl *self, AstCompilerContext *context) {
Dont need to check if @self is resolved, since it will always be partially resolved when called from @funccall_resolve.
Meaning the resolve status wont be set to solved but the resolve type will be set.
*/
-static bool is_func_decl(Ast *self) {
+bool resolved_type_is_func_decl(Ast *self) {
const LhsExpr *resolved_type = self->resolve_data.type;
- return (resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_FUNCTION_DECL) ||
+ return (is_not_null(resolved_type->rhs_expr) && nullable_unwrap(resolved_type->rhs_expr)->type == AST_FUNCTION_DECL) ||
resolved_type->type.type == VARIABLE_TYPE_SIGNATURE;
}
@@ -510,7 +509,7 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) {
func_call = self->value.func_call;
variable_resolve(&func_call->func, context, &self->resolve_data);
/* Attemping to use call syntax (variable_name ( ) ) with a variable that is not a function */
- if(!is_func_decl(self)) {
+ if(!resolved_type_is_func_decl(self)) {
Parser *caller_parser;
Parser *callee_parser;
BufferView callee_code_ref;
@@ -550,7 +549,7 @@ static void structfield_resolve(Ast *self, AstCompilerContext *context) {
static bool is_struct_decl(Ast *self) {
const LhsExpr *resolved_type = self->resolve_data.type;
assert(self->resolve_data.status == AST_RESOLVED);
- return resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_STRUCT_DECL;
+ return is_not_null(resolved_type->rhs_expr) && nullable_unwrap(resolved_type->rhs_expr)->type == AST_STRUCT_DECL;
}
static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) {
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index ffcd2e0..d670407 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -59,6 +59,20 @@ static CHECK_RESULT usize ssa_extract_jump(u8 *instruction_data, SsaInsJump *res
}
static void add_intermediates(BytecodeCompilerContext *self) {
+ /*doc(Bytecode intermediates)
+ # Intermediates layout
+ |Type |Field |Description |
+ |------------|------------------|-------------------------------------------------------------------------------|
+ |u32 |Intermediates size|The size of the intermediates section, in bytes. |
+ |Intermediate|Intermediate data |Multiple intermediates, where the total size is defined by @Intermediates size.|
+
+ # Intermediate
+ |Type|Field|Description |
+ |----|-----|----------------------------------------------------|
+ |u8 |Type |The type of the number. 0=integer, 1=float. |
+ |u64 |Value|The type of the value depends on the value of @Type.|
+ */
+
Ssa *ssa;
Buffer *instructions;
SsaNumber *intermediate;
@@ -81,6 +95,21 @@ static void add_intermediates(BytecodeCompilerContext *self) {
}
void add_strings(BytecodeCompilerContext *self) {
+ /*doc(Bytecode strings)
+ # Strings layout
+ |Type |Field |Description |
+ |-------|-----------------|------------------------------------------------------------------|
+ |u16 |Number of strings|The number of strings. |
+ |u32 |Strings size |The size of the strings section, in bytes. |
+ |String*|Strings data |Multiple strings, where the total size is defined by @Strings size|
+
+ # String
+ |Type|Field|Description |
+ |----|----|----------------------------------------------------------------------------------------|
+ |u16 |Size|The size of the string, in bytes. |
+ |u8* |Data|The data of the string, where the size is defined by @Size. Strings are null-terminated.|
+ */
+
Ssa *ssa;
Buffer *instructions;
BufferView *string;
@@ -100,7 +129,7 @@ void add_strings(BytecodeCompilerContext *self) {
strings_size = 0;
for(; string != strings_end; ++string) {
- strings_size += sizeof(u16) + string->size;
+ strings_size += sizeof(u16) + string->size + 1; /* +1 for null-termination of string */
}
string = buffer_begin(&ssa->strings);
@@ -108,8 +137,10 @@ void add_strings(BytecodeCompilerContext *self) {
throw_if_error(buffer_append(instructions, &num_strings, sizeof(u16)));
throw_if_error(buffer_append(instructions, &strings_size, sizeof(u32)));
for(; string != strings_end; ++string) {
+ char null_s = '\0';
throw_if_error(buffer_append(instructions, &string->size, sizeof(u16)));
throw_if_error(buffer_append(instructions, string->data, string->size));
+ throw_if_error(buffer_append(instructions, &null_s, sizeof(char)));
}
}
@@ -223,6 +254,14 @@ static const char* lhs_expr_get_c_name(BytecodeCompilerContext *self, LhsExpr *l
#endif
static void add_instructions(BytecodeCompilerContext *self) {
+ /*doc(Bytecode instructions)
+ # Instructions layout
+ |Type |Field |Description |
+ |------------|-----------------|---------------------------------------------------------------------------|
+ |u32 |Instructions size|The size of the instructions section, in bytes. |
+ |Instruction*|Instructions data|The instructions data. Each instructions begins with an opcode, see #Opcode|
+ */
+
Ssa *ssa;
u8 *instruction;
u8 *instructions_end;
@@ -486,7 +525,8 @@ static void add_instructions(BytecodeCompilerContext *self) {
/* Prepend instructions with its size */
{
u32 instructions_size;
- instructions_size = self->bytecode.data.size - num_instructions_index - sizeof(instructions_size); /* Remove the count itself from the size of the instructions size */
+ /* -sizeof to Remove the count itself from the size of the instructions size */
+ instructions_size = self->bytecode.data.size - num_instructions_index - sizeof(instructions_size);
am_memcpy(&self->bytecode.data.data[num_instructions_index], &instructions_size, sizeof(instructions_size));
}
diff --git a/src/compiler.c b/src/compiler.c
index 8c3266c..524b555 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -34,7 +34,7 @@ static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char
return_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(LhsExpr), (void**)lhs_expr));
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, struct_decl, AST_STRUCT_DECL, &nullable_raw((*lhs_expr)->rhs_expr)));
return_if_error(ast_create(&compiler->allocator, *lhs_expr, AST_LHS, &expr));
expr->resolve_data.type = *lhs_expr;
expr->resolve_data.status = AST_RESOLVED;
diff --git a/src/nullable.c b/src/nullable.c
new file mode 100644
index 0000000..df69148
--- /dev/null
+++ b/src/nullable.c
@@ -0,0 +1,8 @@
+#include "../include/nullable.h"
+#include <assert.h>
+
+int assert_not_null(void *val) {
+ (void)val;
+ assert(val);
+ return 1;
+}
diff --git a/src/parser.c b/src/parser.c
index fdf34ce..7d991a2 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -62,7 +62,7 @@ int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator
return_if_error(structdecl_init(&self->struct_decl, &compiler->root_scope, allocator));
self->struct_decl.body.parser = self;
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));
+ return_if_error(ast_create(self->allocator, &self->struct_decl, AST_STRUCT_DECL, &nullable_raw(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));
@@ -667,21 +667,21 @@ Ast* parser_parse_body(Parser *self) {
func_decl = parser_parse_closure(self);
if(func_decl) {
- throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &lhs_expr->rhs_expr));
+ throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &nullable_raw(lhs_expr->rhs_expr)));
return result;
}
struct_decl = parser_parse_struct_decl(self);
if(struct_decl) {
- throw_if_error(ast_create(self->allocator, struct_decl, AST_STRUCT_DECL, &lhs_expr->rhs_expr));
+ throw_if_error(ast_create(self->allocator, struct_decl, AST_STRUCT_DECL, &nullable_raw(lhs_expr->rhs_expr)));
return result;
}
import = parser_parse_import(self);
if(import) {
parser_queue_file(self, import->path, &import->file_scope);
- throw_if_error(ast_create(self->allocator, import, AST_IMPORT, &lhs_expr->rhs_expr));
- parser_parse_body_semicolon(self, lhs_expr->rhs_expr);
+ throw_if_error(ast_create(self->allocator, import, AST_IMPORT, &nullable_raw(lhs_expr->rhs_expr)));
+ parser_parse_body_semicolon(self, nullable_unwrap(lhs_expr->rhs_expr));
return result;
}
} else {
@@ -696,7 +696,7 @@ Ast* parser_parse_body(Parser *self) {
self->error_context = ERROR_CONTEXT_NONE;
/* Variable declaration with lhs and rhs */
if(lhs_expr) {
- lhs_expr->rhs_expr = rhs_expr;
+ nullable_assign(lhs_expr->rhs_expr, rhs_expr);
} else {
bool match;
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EQUALS, &match));
diff --git a/src/program.c b/src/program.c
index 92fcb6c..60e9870 100644
--- a/src/program.c
+++ b/src/program.c
@@ -28,12 +28,12 @@ typedef struct {
static CHECK_RESULT int amal_program_append_header(amal_program *self) {
/*doc(Bytecode header)
# Header layout
- |Size|Name |Description |
+ |Type|Field |Description |
|----|-------------|----------------------------------------------------------------------------|
- |4 |Magic number |The magic number used to identify an amalgam bytecode file. |
- |1 |Major version|The major version of the bytecode. Updates in this is a breaking change. |
- |1 |Minor version|The minor version of the bytecode. Updates in this are backwards compatible.|
- |1 |Patch version|The patch version of the bytecode. Updates in this are only minor bug fixes.|
+ |u32 |Magic number |The magic number used to identify an amalgam bytecode file. |
+ |u8 |Major version|The major version of the bytecode. Updates in this is a breaking change. |
+ |u8 |Minor version|The minor version of the bytecode. Updates in this are backwards compatible.|
+ |u8 |Patch version|The patch version of the bytecode. Updates in this are only minor bug fixes.|
The versions in the header only changes for every release, not every change.
*/
@@ -142,18 +142,7 @@ static CHECK_RESULT int amal_program_read_intermediates(amal_program *self) {
}
self->intermediates_start = &self->data.data[self->read_index];
- if(intermediates_size > 0)
- self->num_intermediates = intermediates_size / (sizeof(u8) + sizeof(u64));
- /*
- read_end = self->read_index + intermediates_size;
- while(self->read_index < read_end) {
- NumberType type;
- NumberUnion value;
- am_memcpy(&type, &self->data.data[self->read_index], sizeof(u8));
- am_memcpy(&value, &self->data.data[self->read_index + sizeof(u8)], sizeof(u64));
- self->read_index += sizeof(u8) + sizeof(u64);
- }
- */
+ self->num_intermediates = intermediates_size / (sizeof(u8) + sizeof(u64));
self->read_index += intermediates_size;
return AMAL_PROGRAM_OK;
@@ -203,7 +192,7 @@ static CHECK_RESULT int amal_program_read_strings(amal_program *self) {
if(bytes_left_to_read(self) < string_size)
return AMAL_PROGRAM_INVALID_STRINGS;
- self->read_index += string_size;
+ self->read_index += string_size +1; /* +1 to skip null-termination character */
}
assert(self->read_index == read_end);
@@ -248,10 +237,12 @@ static i64 abs_i64(i64 value) {
return value >= 0 ? value : -value;
}
+#ifdef DEBUG
static int assert_reg_outside_stack() {
assert(bool_false && "Register outside stack!");
return 0;
}
+#endif
static CHECK_RESULT int amal_program_read_instructions(amal_program *self) {
u32 instructions_size;
@@ -262,6 +253,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self) {
func_num_registers = 0;
inside_func = bool_false;
+ (void)inside_func;
if(bytes_left_to_read(self) < sizeof(instructions_size))
return AMAL_PROGRAM_INVALID_INSTRUCTIONS_SIZE;
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index b95cd10..405d8e4 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -342,22 +342,23 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
if(lhs_expr->is_extern)
return lhsexpr_extern_generate_ssa(lhs_expr, context);
- if(lhs_expr->rhs_expr) {
+ if(is_not_null(lhs_expr->rhs_expr)) {
+ Ast *rhs_expr = nullable_unwrap(lhs_expr->rhs_expr);
SsaRegister rhs_reg;
- rhs_reg = ast_generate_ssa(lhs_expr->rhs_expr, context);
+ rhs_reg = ast_generate_ssa(rhs_expr, context);
/*
Declarations (struct and function declaration) resolves to itself and in that case this expression
is just a compile-time name for the declaration.
Import expression also has no meaning in SSA until it's used.
TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types?
*/
- if(self->resolve_data.type == lhs_expr || lhs_expr->rhs_expr->type == AST_IMPORT) {
+ if(self->resolve_data.type == lhs_expr || rhs_expr->type == AST_IMPORT) {
/*assert(bool_false);*/
return 0;
}
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);
+ amal_log_error("rhs_expr is same as reg.. rhs type: %d", rhs_expr->type);
}
assert(reg != rhs_reg);
throw_if_error(ssa_ins_assign_reg(context->ssa, reg, rhs_reg));
@@ -432,7 +433,7 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont
throw_if_error(ssa_ins_push(context->ssa, arg_reg));
}
- assert((self->resolve_data.type->rhs_expr && self->resolve_data.type->rhs_expr->type == AST_FUNCTION_DECL) ||
+ assert((is_not_null(self->resolve_data.type->rhs_expr) && nullable_unwrap(self->resolve_data.type->rhs_expr)->type == AST_FUNCTION_DECL) ||
self->resolve_data.type->type.type == VARIABLE_TYPE_SIGNATURE);
if(self->resolve_data.type->is_extern) {
amal_log_error("TODO: Implement extern function call (extern function %.*s was called)", func_call->func.name.size, func_call->func.name.data);
@@ -440,7 +441,8 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont
assert(bool_false && "TODO: Implement extern function call!");
} else {
FunctionDecl *func_to_call;
- func_to_call = self->resolve_data.type->rhs_expr->value.func_decl;
+ /* rhs wont be null here because only extern variable can't have rhs */
+ func_to_call = nullable_unwrap(self->resolve_data.type->rhs_expr)->value.func_decl;
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));
}
@@ -497,19 +499,18 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_
}
static CHECK_RESULT SsaRegister binop_generate_ssa(Binop *self, SsaCompilerContext *context) {
- SsaRegister lhs_reg;
- SsaRegister rhs_reg;
SsaRegister reg;
/*
- const std = @import("std.amal");
- std.printf
+ Syntax example for binop dot + func_decl expr
+ const std = @import("std.amal");
+ std.printf
*/
- if(self->type == BINOP_DOT && self->rhs->resolve_data.type->rhs_expr->type == AST_FUNCTION_DECL) {
+ if(self->type == BINOP_DOT && resolved_type_is_func_decl(self->rhs)) {
reg = ast_generate_ssa(self->rhs, context);
} else {
- lhs_reg = ast_generate_ssa(self->lhs, context);
- rhs_reg = ast_generate_ssa(self->rhs, context);
+ const SsaRegister lhs_reg = ast_generate_ssa(self->lhs, context);
+ const SsaRegister rhs_reg = ast_generate_ssa(self->rhs, context);
throw_if_error(ssa_ins_binop(context->ssa, binop_type_to_ssa_type(self->type, (amal_default_type*)self->lhs->resolve_data.type), lhs_reg, rhs_reg, &reg));
}
return reg;
diff --git a/src/std/arena_allocator.c b/src/std/arena_allocator.c
index 20f0394..14787f1 100644
--- a/src/std/arena_allocator.c
+++ b/src/std/arena_allocator.c
@@ -105,6 +105,6 @@ int arena_allocator_alloc(ArenaAllocator *self, usize size, void **mem) {
int arena_allocator_add_mem(ArenaAllocator *self, usize *result_index) {
void *null_data;
null_data = NULL;
- *result_index = buffer_get_size(&self->mems, sizeof(void*));
+ *result_index = buffer_get_size(&self->mems, void*);
return buffer_append(&self->mems, &null_data, sizeof(void*));
}