aboutsummaryrefslogtreecommitdiff
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
parentfa2a9e79e21063137f863887adc88fc74d3573e2 (diff)
Add nullable, add bytecode documentation
-rwxr-xr-xbuild.sh10
-rw-r--r--doc/Documentation.md48
-rw-r--r--include/ast.h14
-rw-r--r--include/bytecode/bytecode.h2
-rw-r--r--include/nullable.h29
-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
14 files changed, 185 insertions, 74 deletions
diff --git a/build.sh b/build.sh
index 8fd07b8..8470eb6 100755
--- a/build.sh
+++ b/build.sh
@@ -10,8 +10,8 @@ if [ -z "$CC" ]; then
CC=cc
fi
-CFLAGS=""
-LIBS=""
+CFLAGS="-Wall -Wextra -Werror -Wno-format-security -Wnull-dereference -Wjump-misses-init -std=c89 -D_GNU_SOURCE "
+LIBS="-pthread "
if [ ! -z "$SANITIZE_ADDRESS" ]; then
CFLAGS+="-fsanitize=address "
@@ -24,8 +24,7 @@ if [ ! -z "$PEDANTIC" ]; then
fi
build_test() {
- CFLAGS+="-Wall -Wextra -Werror -Wno-format-security -g -O0 -DDEBUG -std=c89 -D_GNU_SOURCE"
- LIBS+="-pthread"
+ CFLAGS+="-g -O0 -DDEBUG"
BUILD_ARGS="$source_files $CFLAGS $LIBS -shared -fpic -o "$this_script_dir/libamalgam.so""
set -x
@@ -62,8 +61,7 @@ build_test() {
}
build_release() {
- CFLAGS+="-Wall -Wextra -Werror -Wno-format-security -O2 -DNDEBUG -std=c89 -D_GNU_SOURCE -s"
- LIBS+="-pthread"
+ CFLAGS+="-O2 -DNDEBUG -s"
BUILD_ARGS="$source_files $CFLAGS $LIBS -shared -fpic -o "$this_script_dir/libamalgam.so""
set -x
diff --git a/doc/Documentation.md b/doc/Documentation.md
index f7dde0a..01b6a6b 100644
--- a/doc/Documentation.md
+++ b/doc/Documentation.md
@@ -1,7 +1,7 @@
# Opcode
Variable length opcodes. Sizes range from 1 to 4 bytes.
## Instruction formats
-Instructions can be in 6 different formats:
+Instructions can be in 7 different formats:
1. 1 byte: Opcode(u8)
2. 2 bytes: Opcode(u8) + register(u8)
3. 3 bytes: Opcode(u8) + register(u8) + register(u8)
@@ -27,11 +27,45 @@ and may even lose performance because of it.
# 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. \ No newline at end of file
+The versions in the header only changes for every release, not every change.
+
+# 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.|
+
+# 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.|
+
+# 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| \ No newline at end of file
diff --git a/include/ast.h b/include/ast.h
index 4c54766..6a40980 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -2,6 +2,7 @@
#define AMALGAM_AST_H
#include "defs.h"
+#include "nullable.h"
#include "std/defs.h"
#include "std/buffer_view.h"
#include "std/buffer.h"
@@ -17,6 +18,7 @@
#define AST_ERR -1
#define AST_ERR_DEF_DUP -20
+typedef struct Ast Ast;
typedef struct FunctionSignature FunctionSignature;
typedef struct FunctionCall FunctionCall;
typedef struct StructDecl StructDecl;
@@ -79,12 +81,14 @@ typedef struct {
Parser *parser; /* Borrowed. This is the parser that is currently parsing the expression */
} AstResolveData;
-typedef struct {
+struct Ast {
AstValue value;
AstType type;
AstResolveData resolve_data;
SsaRegister ssa_reg;
-} Ast;
+};
+
+DefineNullablePtrType(Ast);
struct Scope {
Buffer/*<Ast*>*/ ast_objects;
@@ -156,7 +160,7 @@ struct LhsExpr {
bool is_const;
BufferView var_name;
VariableType type;
- Ast *rhs_expr;
+ NullablePtr(Ast) rhs_expr;
};
struct AssignmentExpr {
@@ -244,4 +248,8 @@ CHECK_RESULT int scope_add_child(Scope *self, Ast *child);
/* longjump to compiler env on failure */
void scope_resolve(Scope *self, AstCompilerContext *context);
+
+
+CHECK_RESULT bool resolved_type_is_func_decl(Ast *self);
+
#endif
diff --git a/include/bytecode/bytecode.h b/include/bytecode/bytecode.h
index 32488cc..4c54fbd 100644
--- a/include/bytecode/bytecode.h
+++ b/include/bytecode/bytecode.h
@@ -11,7 +11,7 @@
/*doc(Opcode)
Variable length opcodes. Sizes range from 1 to 4 bytes.
# Instruction formats
- Instructions can be in 6 different formats:
+ Instructions can be in 7 different formats:
1. 1 byte: Opcode(u8)
2. 2 bytes: Opcode(u8) + register(u8)
3. 3 bytes: Opcode(u8) + register(u8) + register(u8)
diff --git a/include/nullable.h b/include/nullable.h
new file mode 100644
index 0000000..6c4d3a7
--- /dev/null
+++ b/include/nullable.h
@@ -0,0 +1,29 @@
+#ifndef AMAL_NULLABLE_H
+#define AMAL_NULLABLE_H
+
+struct __nullable_type_dummy{ int _; };
+
+int assert_not_null(void *val);
+
+#ifdef DEBUG
+#define DefineNullablePtrType(type) \
+ typedef struct type##_nullable type##_nullable; \
+ struct type##_nullable { \
+ type *value; \
+ }
+#define NullablePtr(type) type##_nullable
+#define nullable_unwrap(nullable_type) \
+ (assert_not_null((nullable_type).value) ? ((nullable_type).value) : NULL)
+#define nullable_assign(nullable_type, new_value) ((nullable_type).value = (new_value))
+#define is_not_null(nullable_type) ((nullable_type).value != NULL)
+#define nullable_raw(nullable_type) ((nullable_type).value)
+#else
+#define DefineNullablePtrType(type)
+#define NullablePtr(type) type*
+#define nullable_unwrap(value) value
+#define nullable_assign(nullable_type, new_value) ((nullable_type) = (new_value))
+#define is_not_null(nullable_type) ((nullable_type) != NULL)
+#define nullable_raw(nullable_type) (nullable_type)
+#endif
+
+#endif
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*));
}