aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-08-12 09:48:55 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commitea97370f973374f863e4296c2bb872be8b5235a3 (patch)
treebcf74846c250dd5b1f84049622ed2766605365e7 /src
parent4ca3b74621c3608de42a91730a71892d9d7c27b5 (diff)
Before interpreter. Cleanup build script. Begin writing code analyzer tool to find common mistakes
Diffstat (limited to 'src')
-rw-r--r--src/asm/x86_64.c385
-rw-r--r--src/ast.c18
-rw-r--r--src/compiler.c35
-rw-r--r--src/parser.c38
-rw-r--r--src/ssa/ssa.c4
-rw-r--r--src/std/hash_map.c11
6 files changed, 74 insertions, 417 deletions
diff --git a/src/asm/x86_64.c b/src/asm/x86_64.c
deleted file mode 100644
index e246fbc..0000000
--- a/src/asm/x86_64.c
+++ /dev/null
@@ -1,385 +0,0 @@
-#include "../../include/asm/x86_64.h"
-
-#include "../../include/std/mem.h"
-#include "../../include/std/log.h"
-#include <errno.h>
-#include <assert.h>
-#include <stdio.h>
-
-#include <sys/mman.h>
-
-#define REX_W 0x48
-
-void asm_ptr_init(AsmPtr *self, Reg64 base) {
- self->base = base;
- self->index = -1;
- self->disp = 0;
- self->scale = 0;
-}
-
-void asm_ptr_init_index(AsmPtr *self, Reg64 base, Reg64 index) {
- self->base = base;
- self->index = index;
- self->disp = 0;
- self->scale = 0;
-}
-
-void asm_ptr_init_disp(AsmPtr *self, Reg64 base, i32 disp) {
- self->base = base;
- self->index = -1;
- self->disp = disp;
- self->scale = 0;
-}
-
-void asm_ptr_init_index_disp(AsmPtr *self, Reg64 base, Reg64 index, i32 disp) {
- self->base = base;
- self->index = index;
- self->disp = disp;
- self->scale = 0;
-}
-
-int asm_init(Asm *self) {
- self->size = am_pagesize();
- amal_log_debug("asm: page size: %u", self->size);
- self->code = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if(self->code == MAP_FAILED)
- return -errno;
- self->code_it = self->code;
- return 0;
-}
-
-void asm_deinit(Asm *self) {
- if(self->code)
- munmap(self->code, self->size);
- self->code = NULL;
- self->code_it = NULL;
- self->size = 0;
-}
-
-static void asm_print_code_hex(Asm *self) {
- u8 *ptr;
- int off;
- ptr = self->code;
- off = 0;
- while(ptr != self->code_it) {
- printf("%02x", *ptr);
- ++ptr;
- ++off;
- if(off == 8) {
- putc('\n', stdout);
- off = 0;
- } else {
- putc(' ', stdout);
- }
- }
- if(off != 0)
- putc('\n', stdout);
-}
-
-int asm_execute(Asm *self) {
- void (*func)();
- if(mprotect(self->code, self->size, PROT_READ | PROT_EXEC) != 0)
- return -errno;
-
- asm_print_code_hex(self);
-
- /* TODO: Verify if this is valid on all platforms. According to ISO C standard it isn't? */
- *(void**)(&func) = self->code;
- func();
- return 0;
-}
-
-/* TODO: See how this can be optimized */
-static CHECK_RESULT int asm_ensure_capacity(Asm *self, usize size) {
- usize current_offset;
- current_offset = (u8*)self->code_it - (u8*)self->code;
- if(current_offset + size > self->size) {
- void *new_mem;
- usize new_size;
- new_size = self->size + am_pagesize();
- new_mem = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if(self->code == MAP_FAILED)
- return -errno;
-
- am_memcpy(new_mem, self->code, self->size);
- self->code = new_mem;
- self->size = new_size;
- self->code_it = (u8*)self->code + current_offset;
- }
- 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));
- *self->code_it++ = 0x90;
- return 0;
-}
-
-static i32 abs_i32(i32 value) {
- return value >= 0 ? value : -value;
-}
-
-/*
-TODO: Implement 1 and 2 byte displacement?
-There has to be at least 6 bytes left in the asm buffer before calling this function.
-*/
-static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) {
- u8 rm_byte;
- u8 disp_bytes;
- assert(asm_get_capacity_left(self) >= 6);
- if((int)mem->index != -1) {
- u8 sib_offset;
- if(mem->disp == 0) {
- rm_byte = 0x04;
- disp_bytes = 0;
- } else if(abs_i32(mem->disp) <= INT8_MAX) {
- rm_byte = 0x44;
- disp_bytes = 1;
- } else {
- rm_byte = 0x84;
- disp_bytes = 4;
- }
-
- #ifdef DEBUG
- if(mem->scale != 0 && mem->scale != 2 && mem->scale != 4 && mem->scale != 8) {
- amal_log_error("Invalid scale %d, expected 0, 2, 4, or 8", mem->scale);
- assert(bool_false);
- }
- #endif
- assert(mem->base != RBP && "TODO: Implement RBP base for sib byte. RBP is special and requires different logic");
- sib_offset = (mem->scale << 5) + 8*mem->index + mem->base;
-
- *self->code_it++ = rm_byte;
- *self->code_it++ = sib_offset;
- } else {
- if(mem->disp == 0) {
- if(mem->base == RBP) {
- rm_byte = 0x45;
- disp_bytes = 1;
- } else {
- rm_byte = mem->base;
- disp_bytes = 0;
- }
- } else if(abs_i32(mem->disp) <= INT8_MAX) {
- rm_byte = 0x40 + mem->base;
- disp_bytes = 1;
- } else {
- rm_byte = 0x80 + mem->base;
- disp_bytes = 4;
- }
- *self->code_it++ = (reg << 3) | rm_byte;
- }
-
- am_memcpy(self->code_it, &mem->disp, disp_bytes);
- self->code_it += disp_bytes;
-}
-
-/* There has to be at least 1 byte left in the asm buffer before calling this function. */
-static void asm_rr(Asm *self, Reg64 dst, Reg64 src) {
- assert(asm_get_capacity_left(self) >= 1);
- *self->code_it++ = 0xC0 + dst + 8*src;
-}
-
-/* TODO: Implement 1 and 2 byte immediate? */
-int asm_mov_mi(Asm *self, AsmPtr *dst, i32 immediate) {
- /* 12 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 12));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0xC7;
- asm_rm(self, dst, 0);
- am_memcpy(self->code_it, &immediate, sizeof(immediate));
- self->code_it += sizeof(immediate);
- return 0;
-}
-
-int asm_mov_mr(Asm *self, AsmPtr *dst, Reg64 src) {
- /* 8 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 8));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0x89;
- asm_rm(self, dst, src);
- return 0;
-}
-
-int asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) {
- /* 8 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 8));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0x8B;
- asm_rm(self, src, dst);
- return 0;
-}
-
-int asm_mov_ri(Asm *self, Reg64 dst, i64 immediate) {
- /* 10 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 10));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0xB8 + dst;
- am_memcpy(self->code_it, &immediate, sizeof(immediate));
- self->code_it += sizeof(immediate);
- return 0;
-}
-
-int asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) {
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 3));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0x89;
- asm_rr(self, dst, src);
- return 0;
-}
-
-int asm_add_rr(Asm *self, Reg64 dst, Reg64 src) {
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 3));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0x01;
- asm_rr(self, dst, src);
- return 0;
-}
-
-int asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) {
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 3));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0x29;
- asm_rr(self, dst, src);
- return 0;
-}
-
-int asm_imul_rr(Asm *self, Reg64 dst, Reg64 src) {
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
- return_if_error(asm_ensure_capacity(self, 4));
- *self->code_it++ = REX_W;
- *self->code_it++ = 0x0F;
- *self->code_it++ = 0xAF;
- asm_rr(self, dst, src);
- return 0;
-}
-
-int asm_pushr(Asm *self, Reg64 reg) {
- return_if_error(asm_ensure_capacity(self, 1));
- *self->code_it++ = 0x50 + reg;
- return 0;
-}
-
-int asm_popr(Asm *self, Reg64 reg) {
- return_if_error(asm_ensure_capacity(self, 1));
- *self->code_it++ = 0x58 + reg;
- return 0;
-}
-
-/* /r */
-#define DEFINE_INS_RM(mnemonic, opcode) \
-int asm_##mnemonic##_rm32(Asm *self, Reg32 dst, Reg32 src) { \
- return_if_error(asm_ensure_capacity(self, 2)); \
- *self->code_it++ = opcode; \
- *self->code_it++ = 0xC0 + 8*dst + src; \
- return 0; \
-} \
- \
-int asm_##mnemonic##_rm64(Asm *self, Reg64 dst, Reg64 src) { \
- return_if_error(asm_ensure_capacity(self, 1)); \
- *self->code_it++ = REX_W; \
- return asm_##mnemonic##_rm32(self, (Reg32)dst, (Reg32)src); \
-}
-
-DEFINE_INS_RM(mov, 0x8B)
-DEFINE_INS_RM(add, 0x03)
-DEFINE_INS_RM(sub, 0x2B)
-DEFINE_INS_RM(and, 0x23)
-DEFINE_INS_RM(or, 0x0B)
-DEFINE_INS_RM(xor, 0x33)
-DEFINE_INS_RM(cmp, 0x3B)
-
-/*
- /number
- The number is called the extension, a number from 0 to 7;
- It's a number used to extend the opcode type, since the instruction only uses
- one register the other register can be encoded for that.
-*/
-#define DEFINE_INS_EXT_IMM(mnemonic, extension) \
-int asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i32 immediate) { \
- if(abs_i32(immediate) <= INT8_MAX) { \
- return_if_error(asm_ensure_capacity(self, 3)); \
- *self->code_it++ = 0x83; \
- *self->code_it++ = 0xC0 + 8*extension + reg; \
- *self->code_it++ = (u8)immediate; \
- } else { \
- return_if_error(asm_ensure_capacity(self, 6)); \
- *self->code_it++ = 0x81; \
- *self->code_it++ = 0xC0 + 8*extension + reg; \
- am_memcpy(self->code_it, &immediate, sizeof(immediate)); \
- self->code_it += sizeof(immediate); \
- } \
- return 0; \
-} \
- \
-int asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i32 immediate) { \
- return_if_error(asm_ensure_capacity(self, 1)); \
- *self->code_it++ = REX_W; \
- return asm_##mnemonic##_rm32_imm(self, (Reg32)reg, immediate); \
-}
-
-DEFINE_INS_EXT_IMM(add, 0)
-DEFINE_INS_EXT_IMM(or, 1)
-DEFINE_INS_EXT_IMM(adc, 2)
-DEFINE_INS_EXT_IMM(sbb, 3)
-DEFINE_INS_EXT_IMM(and, 4)
-DEFINE_INS_EXT_IMM(sub, 5)
-DEFINE_INS_EXT_IMM(xor, 6)
-DEFINE_INS_EXT_IMM(cmp, 7)
-
-/*
- /number
- The number is called the extension, a number from 0 to 7;
- It's a number used to extend the opcode type, since the instruction only uses
- one register the other register can be encoded for that.
-*/
-#define DEFINE_INS_SHIFT_IMM8(mnemonic, extension) \
-int asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i8 immediate) { \
- if(immediate == 1) { \
- return_if_error(asm_ensure_capacity(self, 2)); \
- *self->code_it++ = 0xC1; \
- *self->code_it++ = 0xC0 + 8*reg + extension; \
- } else { \
- return_if_error(asm_ensure_capacity(self, 3)); \
- *self->code_it++ = 0xD1; \
- *self->code_it++ = 0xC0 + 8*reg + extension; \
- *self->code_it++ = immediate; \
- } \
- return 0; \
-} \
- \
-int asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i8 immediate) { \
- return_if_error(asm_ensure_capacity(self, 1)); \
- *self->code_it++ = REX_W; \
- return asm_##mnemonic##_rm32_imm(self, (Reg32)reg, immediate); \
-}
-
-DEFINE_INS_SHIFT_IMM8(rol, 0)
-DEFINE_INS_SHIFT_IMM8(ror, 1)
-DEFINE_INS_SHIFT_IMM8(rcl, 2)
-DEFINE_INS_SHIFT_IMM8(rcr, 3)
-DEFINE_INS_SHIFT_IMM8(shl, 4)
-DEFINE_INS_SHIFT_IMM8(shr, 5)
-/*DEFINE_INS_SHIFT_IMM8(shl, 6)*/
-DEFINE_INS_SHIFT_IMM8(sar, 7)
-
-int asm_ret(Asm *self, u16 bytes) {
- if(bytes == 0) {
- return_if_error(asm_ensure_capacity(self, 1));
- *self->code_it++ = 0xC3;
- } else {
- return_if_error(asm_ensure_capacity(self, 3));
- *self->code_it++ = 0xC2;
- am_memcpy(self->code_it, &bytes, sizeof(bytes));
- }
- return 0;
-}
diff --git a/src/ast.c b/src/ast.c
index e28b072..0aa19d4 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -95,15 +95,21 @@ int structdecl_init(StructDecl *self, Scope *parent, ArenaAllocator *allocator)
return scope_init(&self->body, parent, allocator);
}
+LhsExpr* structdecl_get_field_by_name(StructDecl *self, BufferView field_name) {
+ Ast* result;
+ if(!hash_map_get(&self->body.named_objects, field_name, &result))
+ return NULL;
+ return result->value.lhs_expr;
+}
+
void structfield_init(StructField *self, BufferView name, BufferView type_name) {
self->name = name;
variable_init(&self->type, type_name);
}
-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;
+void lhsexpr_init(LhsExpr *self, DeclFlag decl_flag, BufferView var_name) {
+ assert(!((decl_flag & DECL_FLAG_EXTERN) && (decl_flag & DECL_FLAG_EXPORT)) && "Expression cant be both extern and export");
+ self->decl_flags = decl_flag;
self->type.type = VARIABLE_TYPE_NONE;
self->type.value.variable = NULL;
self->var_name = var_name;
@@ -423,7 +429,7 @@ static void assignmentexpr_resolve(Ast *ast, AstCompilerContext *context) {
/* This also covers extern variables, since extern variables are always const */
/* TODO: var.field type expressions should also be checked */
- if(lhs_source && lhs_source->is_const) {
+ if(lhs_source && LHS_EXPR_IS_CONST(lhs_source)) {
Parser *parser;
parser = scope_get_parser(context->scope);
parser_print_error(parser, ast_get_code_reference(self->lhs_expr).data, "Can't assign to a const value");
@@ -587,7 +593,7 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) {
throw(AST_ERR);
}
- if(!self->rhs->resolve_data.type->is_pub) {
+ if(!LHS_EXPR_IS_PUB(self->rhs->resolve_data.type)) {
parser_print_error(caller_parser, caller_code_ref.data, "Can't access non-public field \"%.*s\"", caller_code_ref.size, caller_code_ref.data);
/* TODO: use tokenizer_print_note, once it has been added */
/* TODO: Print type */
diff --git a/src/compiler.c b/src/compiler.c
index 8c3266c..39cbb00 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -33,7 +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(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)));
+ lhsexpr_init(*lhs_expr, DECL_FLAG_EXTERN | DECL_FLAG_PUB | DECL_FLAG_CONST, 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;
@@ -540,7 +540,6 @@ int amal_compiler_load_file(amal_compiler_options *options, amal_program *progra
int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) {
int result;
- BufferView filepath_view;
ParserThreadData *parser_thread_data;
ThreadWorkData thread_work_data;
bool main_job;
@@ -548,9 +547,8 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath,
return_if_error(try_create_file_scope(self, filepath, file_scope, &new_entry));
assert(file_scope && *file_scope && (*file_scope)->canonical_path.data);
- filepath_view = create_buffer_view((*file_scope)->canonical_path.data, (*file_scope)->canonical_path.size);
if(!new_entry) {
- amal_log_info("amal_compiler_load_file: file already parsed: %.*s", filepath_view.size, filepath_view.data);
+ amal_log_info("amal_compiler_load_file: file already parsed: %.*s", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data);
return 0;
}
@@ -575,11 +573,40 @@ int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath,
and writing it to a file, which is an IO bottlenecked operation and it won't benefit from multithreading
and may even lose performance because of it.
*/
+ const BufferView main_func_name = { "main", 4 };
+ LhsExpr *main_func_expr;
return_if_error(amal_compiler_load_file_join_threads(self));
assert(amal_compiler_check_all_threads_done(self));
amal_log_info("Finished parsing all files, resolving AST");
+ main_func_expr = structdecl_get_field_by_name(&(*file_scope)->parser->struct_decl, main_func_name);
+ if(!main_func_expr) {
+ amal_log_error("main function missing from start file \"%.*s\"", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data);
+ return AMAL_COMPILER_ERR;
+ }
+
+ if(!main_func_expr->rhs_expr || main_func_expr->rhs_expr->type != AST_FUNCTION_DECL) {
+ amal_log_error("main exists in start file \"%.*s\" but it's not an non-extern function", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data);
+ return AMAL_COMPILER_ERR;
+ }
+
+ if(!LHS_EXPR_IS_CONST(main_func_expr)) {
+ amal_log_error("main function in start file \"%.*s\" has to be const", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data);
+ return AMAL_COMPILER_ERR;
+ }
+
+ if(LHS_EXPR_IS_EXTERN(main_func_expr)) {
+ amal_log_error("main function in start file \"%.*s\" can't be declared as extern", (*file_scope)->canonical_path.size, (*file_scope)->canonical_path.data);
+ return AMAL_COMPILER_ERR;
+ }
+
+ /*
+ The main function is the start file needs to be exported, so it's accessible in the program execution
+ to find the entry (main) function.
+ */
+ main_func_expr->decl_flags |= DECL_FLAG_EXPORT;
+
return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_RESOLVE_AST));
assert(amal_compiler_check_all_threads_done(self));
amal_log_info("Finished resolving AST, generating SSA");
diff --git a/src/parser.c b/src/parser.c
index fdf34ce..e36790f 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -61,7 +61,7 @@ int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator
self->error_context = ERROR_CONTEXT_NONE;
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());
+ lhsexpr_init(&self->file_decl, DECL_FLAG_EXTERN | DECL_FLAG_PUB | DECL_FLAG_CONST, 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;
@@ -192,29 +192,39 @@ LHS_DECLARATION = 'extern'? 'pub'? 'const'|'var' TOK_IDENTIFIER VAR_TYPE_DEF?
*/
static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) {
LhsExpr *result;
+ DeclFlag decl_flag;
bool is_extern;
bool is_pub;
bool is_const;
BufferView var_name;
+ decl_flag = DECL_FLAG_NONE;
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EXTERN, &is_extern));
- 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 global structs can be extern");
- throw(PARSER_UNEXPECTED_TOKEN);
+ if(is_extern) {
+ decl_flag |= DECL_FLAG_EXTERN;
+ if(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 global structs can be extern");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
}
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_PUB, &is_pub));
- 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 global structs can be public");
- throw(PARSER_UNEXPECTED_TOKEN);
+ if(is_pub) {
+ decl_flag |= DECL_FLAG_PUB;
+ if(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 global structs can be public");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
}
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_CONST, &is_const));
- if(!is_const) {
+ if(is_const) {
+ decl_flag |= DECL_FLAG_CONST;
+ } else {
bool isVar;
if(is_extern) {
@@ -232,7 +242,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(arena_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&result));
- lhsexpr_init(result, is_extern, is_pub, is_const, var_name);
+ lhsexpr_init(result, decl_flag, var_name);
parser_parse_var_type_def(self, &result->type);
return result;
@@ -642,7 +652,7 @@ Ast* parser_parse_body(Parser *self) {
bool match;
throw_if_error(ast_create(self->allocator, lhs_expr, AST_LHS, &result));
- if(lhs_expr->is_extern) {
+ if(LHS_EXPR_IS_EXTERN(lhs_expr)) {
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON));
if (lhs_expr->type.type == VARIABLE_TYPE_NONE) {
self->error = tokenizer_create_error(&self->tokenizer, self->tokenizer.prev_index, "A variable can't be declared without a type or assignment");
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index 707ccd0..f3679aa 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -339,7 +339,7 @@ static CHECK_RESULT SsaRegister lhsexpr_generate_ssa(Ast *self, SsaCompilerConte
assert(self->type == AST_LHS);
lhs_expr = self->value.lhs_expr;
- if(lhs_expr->is_extern)
+ if(LHS_EXPR_IS_EXTERN(lhs_expr))
return lhsexpr_extern_generate_ssa(lhs_expr, context);
if(lhs_expr->rhs_expr) {
@@ -435,7 +435,7 @@ static CHECK_RESULT SsaRegister funccall_generate_ssa(Ast *self, SsaCompilerCont
assert((self->resolve_data.type->rhs_expr && 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) {
+ if(LHS_EXPR_IS_EXTERN(self->resolve_data.type)) {
amal_log_error("TODO: Implement extern function call (extern function %.*s was called)", func_call->func.name.size, func_call->func.name.data);
reg = 0;
assert(bool_false && "TODO: Implement extern function call!");
diff --git a/src/std/hash_map.c b/src/std/hash_map.c
index bcb43eb..c2e42c1 100644
--- a/src/std/hash_map.c
+++ b/src/std/hash_map.c
@@ -205,13 +205,12 @@ bool hash_map_get(HashMap *self, BufferView key, void *value) {
int hash_map_compare_string(const void *a, const void *b) {
const BufferView *lhs;
const BufferView *rhs;
- int mem_diff;
lhs = a;
rhs = b;
- mem_diff = am_memcmp(lhs->data, rhs->data, MIN(lhs->size, rhs->size));
- if(mem_diff == 0)
- return (int)lhs->size - (int)rhs->size;
- else
- return mem_diff;
+
+ if(lhs->size != rhs->size)
+ return -1;
+
+ return am_memcmp(lhs->data, rhs->data, MIN(lhs->size, rhs->size));
}