From 16aaaa19a3ef4220726007d3e644ced0c9e06513 Mon Sep 17 00:00:00 2001
From: dec05eba <dec05eba@protonmail.com>
Date: Mon, 9 Sep 2019 01:08:34 +0200
Subject: Allow referencing code in imported file (right now for function
 calls, allow calling a function in another file)

---
 include/ast.h               | 34 +++++++++++++++++++++++++--------
 include/bytecode/bytecode.h | 46 +++++++++++++++++++++++++++++++++++++++------
 include/defs.h              |  3 +++
 include/parser.h            | 10 ++++++++--
 include/program.h           | 11 +++++++++++
 include/ssa/ssa.h           | 18 ++++++++++++++----
 include/std/buffer.h        |  2 ++
 include/std/buffer_view.h   |  2 +-
 include/std/hash_map.h      |  1 +
 include/std/log.h           |  2 +-
 include/std/mem.h           |  2 +-
 include/std/misc.h          |  8 ++++++--
 include/std/thread.h        |  4 ++--
 13 files changed, 116 insertions(+), 27 deletions(-)

(limited to 'include')

diff --git a/include/ast.h b/include/ast.h
index edf225b..0c34d0b 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -23,7 +23,6 @@ typedef struct FunctionParameter FunctionParameter;
 typedef struct FunctionCall FunctionCall;
 typedef struct StructDecl StructDecl;
 typedef struct StructField StructField;
-typedef struct LhsExpr LhsExpr;
 typedef struct AssignmentExpr AssignmentExpr;
 typedef struct Import Import;
 typedef struct String String;
@@ -147,10 +146,16 @@ typedef struct {
 } VariableType;
 
 struct FileScopeReference {
-    Parser *parser;
+    Parser *parser; /* Borrowed, the parser that belongs to the same file as the FileScopeReference */
     Buffer canonical_path;
 };
 
+struct ParserFileScopeReference {
+    FileScopeReference *file_scope_ref;
+    /* Index in the parser import list. Used by bytecode to know which import an expression belongs to */
+    int import_index;
+};
+
 struct Variable {
     BufferView name;
     ScopeNamedObject resolved_var;
@@ -177,7 +182,7 @@ struct FunctionSignature {
 
 struct FunctionDecl {
     LhsExpr *lhs_expr; /* Borrowed from the LhsExpr that owns this FunctionDecl if it exists, otherwise NULL */
-    FunctionSignature *signature;
+    FunctionSignature *signature; /* TODO: Make this a non-pointer type? */
     Scope body;
     SsaFuncIndex ssa_func_index;
 };
@@ -188,7 +193,15 @@ struct FunctionCall {
 };
 
 struct StructDecl {
+    /*
+        TODO: Instead of having a scope body, use a body with only structdecl. This improves performance
+        and simplifies the code.
+    */
     Scope body;
+    /* The number of fields that are pointers or a type that is different on different platforms (i.e isize, usize, etc), recursive */
+    u32 fields_num_pointers;
+    /* The total size of all fields which are of a type that have the same size on all platforms (i.e u8, i32, etc), recursive */
+    u32 fields_fixed_size_bytes;
 };
 
 struct StructField {
@@ -232,7 +245,7 @@ struct AssignmentExpr {
 
 struct Import {
     BufferView path;
-    FileScopeReference *file_scope;
+    ParserFileScopeReference *file_scope;
 };
 
 struct String {
@@ -278,6 +291,11 @@ struct ReturnExpr {
     Ast *rhs_expr;
 };
 
+typedef struct {
+    u32 num_pointers;
+    u32 fixed_size;
+} TypeSize;
+
 typedef struct {
     jmp_buf env;
     amal_compiler *compiler; /* Borrowed */
@@ -303,6 +321,7 @@ void function_parameter_init(FunctionParameter *self);
 CHECK_RESULT int funcdecl_init(FunctionDecl *self, FunctionSignature *signature, Scope *parent, ArenaAllocator *allocator);
 CHECK_RESULT int funccall_init(FunctionCall *self, BufferView name, ArenaAllocator *allocator);
 CHECK_RESULT int structdecl_init(StructDecl *self, Scope *parent, ArenaAllocator *allocator);
+CHECK_RESULT int structdecl_add_field(StructDecl *self, StructField *field, ArenaAllocator *allocator);
 LhsExpr* structdecl_get_field_by_name(StructDecl *self, BufferView field_name);
 /* Copies @type */
 void structfield_init(StructField *self, BufferView name, VariableType *type);
@@ -318,14 +337,13 @@ CHECK_RESULT int else_if_statement_init(ElseIfStatement *self, Scope *parent, Ar
 CHECK_RESULT int while_statement_init(WhileStatement *self, Scope *parent, ArenaAllocator *allocator);
 void return_expr_init(ReturnExpr *self, Ast *rhs_expr);
 
+TypeSize resolved_type_get_byte_size(AstResolvedType *self);
+
 CHECK_RESULT int scope_init(Scope *self, Scope *parent, ArenaAllocator *allocator);
 CHECK_RESULT int file_scope_reference_init(FileScopeReference *self, BufferView canonical_path, ArenaAllocator *allocator);
 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 b1b5dda..c495d7a 100644
--- a/include/bytecode/bytecode.h
+++ b/include/bytecode/bytecode.h
@@ -26,11 +26,15 @@
     6.2 Opcode(u8) + register(i8) + intermediate(u16)\
     6.3 Opcode(u8) + register(i8) + data(u16)\
     6.4 Opcode(u8) + flags(u8) + num_local_var_reg(u16)
-    7. 5 bytes: Opcode(u8) + index(u16) + num_args(u8) + register(i8)
+    7. 5 bytes: Opcode(u8) + index(u8) + index(u16) + num_args(u8)
     # Registers
     Registers have a range of 128. Local variables start from register 0 and increment while parameters start from -1
     and decrement. Registers have the scope of functions and reset after instructions reach a new function (AMAL_OP_FUNC_START).
+
+    If import index for call and calle is 0, then that means the function resides in the same file the function call
+    is being called from. Which means that import index 1 is actually import index 0 into the import list.
 */
+/* Important: The number of fields in this enum can't exceed 255 */
 typedef enum {
     AMAL_OP_NOP,         /* No operation (do nothing). This can be used for patching code */
     AMAL_OP_SETZ,        /* setz reg                             - Set register value to 0 */
@@ -46,16 +50,17 @@ typedef enum {
     AMAL_OP_PUSH,        /* push reg                             - Push register onto stack */
     AMAL_OP_PUSHI,       /* pushi int                            - Push intermediate onto stack */
     AMAL_OP_PUSHD,       /* pushd data                           - Push data onto stack */
-    AMAL_OP_CALL,        /* call fi, num_args, dst               - Call a function using function index (fi) and num_args arguments. The result is stored in register dst. fi is u16 and num_args is u8 */
+    AMAL_OP_PUSH_RET,    /* push_ret reg                         - Push register onto stack as a return value of the next function call */
+    AMAL_OP_CALL,        /* call ii, fi, num_args                - Call a function in imported file (ii, import index) using function index (fi) and num_args arguments. ii is u8, fi is u16 and num_args is u8 */
     AMAL_OP_CALLR,       /* callr reg, num_args                  - Call a function using a register. Used for function pointers. num_args is u8 */
-    AMAL_OP_CALLE,       /* calle efi, num_args, dst             - Call an extern function using extern function index (efi) and num_args arguments. The result is stored in register dst. efi is u16 and num_args is u8 */
+    AMAL_OP_CALLE,       /* calle ii, efi, num_args              - Call an extern function in imported file (ii, import index) using extern function index (efi) and num_args arguments. ii is u8, efi is u16 and num_args is u8 */
     AMAL_OP_CMP,         /* cmp dst, reg1, reg2                  - Set dst to 1 if reg1 equals reg2, otherwise set it to 0 */
     AMAL_OP_JZ,          /* jz reg, label                        - Jump to label in the current function if reg is zero. label is u16 */
     AMAL_OP_JMP,         /* jmp label                            - Unconditional jump to label in the current function. label is u16 */
     AMAL_OP_RET,         /* ret reg                              - Return from the function with reg result */
     AMAL_OP_FUNC_START,  /* func_start flags, num_local_var_reg  - Start of a function which has @num_local_var_reg local variable registers allocated and has the flag @flag. @flag is u8 and @num_local_var_reg is u16 */
     AMAL_OP_FUNC_END,    /* func_end                             - End of a function. Implementation should do a ret here */
-    AMAL_OP_LABEL,       /* label                                - Label. This is the target of a jump instruction. Jump instructions only jump to labels in the same function scope */
+    AMAL_OP_LABEL        /* label                                - Label. This is the target of a jump instruction. Jump instructions only jump to labels in the same function scope */
 } AmalOpcode;
 
 #define AMAL_BYTECODE_MAGIC_NUMBER (u32)0xdec05eba
@@ -63,6 +68,8 @@ typedef enum {
 #define AMAL_BYTECODE_MINOR_VERSION 0
 #define AMAL_BYTECODE_PATCH_VERSION 0
 
+#define AMAL_BYTECODE_SECTION_MAGIC_NUMBER (u32)0x004005e4 /* "section\0" in ascii */
+
 #define AMAL_BYTECODE_NUM_REGISTERS 256
 
 typedef enum {
@@ -72,13 +79,40 @@ typedef enum {
 
 typedef u8 AmalOpcodeType;
 
+/* TODO: Make sure this pragma pack works on all platforms */
+#pragma pack(push, 1)
+typedef struct {
+    u32 func_offset;
+    u8 num_params;
+    u32 params_num_pointers;
+    u32 params_fixed_size;
+
+    u8 num_return_types;
+    u32 return_types_num_pointers;
+    u32 return_types_fixed_size;
+} BytecodeHeaderFunction;
+#pragma pack(pop)
+
+/* TODO: Make sure this pragma pack works on all platforms */
+#pragma pack(push, 1)
 typedef struct {
+    u32 function_index;
+    #define parser_index function_index
+    u32 extern_function_index;
+} BytecodeHeaderImport;
+#pragma pack(pop)
+
+struct Bytecode {
     Buffer/*<headers + instruction data>*/ data;
-} Bytecode;
+    usize import_index;     /* Reference inside @data where imports start */
+    u32 funcs_index;        /* Reference inside @data where funcs start */
+    u32 extern_funcs_index; /* Reference inside @data where extern funcs start */
+    u32 offset;             /* Offset that this bytecode starts from in the final program (all bytecodes combined) */
+};
 
 typedef struct {
     jmp_buf env;
-    Bytecode bytecode;
+    Bytecode *bytecode;
     Parser *parser; /* borrowed */
 } BytecodeCompilerContext;
 
diff --git a/include/defs.h b/include/defs.h
index 669d9c9..bb96421 100644
--- a/include/defs.h
+++ b/include/defs.h
@@ -5,8 +5,11 @@ typedef struct amal_compiler amal_compiler;
 typedef struct Parser Parser;
 typedef struct Scope Scope;
 typedef struct FileScopeReference FileScopeReference;
+typedef struct ParserFileScopeReference ParserFileScopeReference;
 typedef struct FunctionDecl FunctionDecl;
 typedef struct FunctionSignature FunctionSignature;
+typedef struct LhsExpr LhsExpr;
 typedef struct Tokenizer Tokenizer;
+typedef struct Bytecode Bytecode;
 
 #endif
diff --git a/include/parser.h b/include/parser.h
index 81895e1..ae5cfa6 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -4,7 +4,6 @@
 #include "std/buffer_view.h"
 #include "std/arena_allocator.h"
 #include "std/thread.h"
-#include "bytecode/bytecode.h"
 #include "tokenizer.h"
 #include "ast.h"
 #include "defs.h"
@@ -36,7 +35,14 @@ struct Parser {
     TokenizerError error;
     ErrorContext error_context;
     jmp_buf parse_env;
-    Bytecode bytecode;
+    Bytecode *bytecode;
+    Buffer/*<ParserFileScopeReference*>*/ imports;
+    HashMapType(BufferView, usize) imports_by_name; /* The value is an index inside @imports */
+    /*
+        Index in the compilers list of parsers. Used by bytecodes import header
+        to point to the index that contains references to another files variables.
+    */
+    u32 index; 
 };
 
 CHECK_RESULT int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator);
diff --git a/include/program.h b/include/program.h
index e3a4ac9..b398a3a 100644
--- a/include/program.h
+++ b/include/program.h
@@ -35,9 +35,13 @@
 #define AMAL_PROGRAM_INVALID_EXPORTED_FUNCTIONS_SIZE -23
 #define AMAL_PROGRAM_INSTRUCTION_INVALID_EXPORTED_FUNC_INDEX -24
 #define AMAL_PROGRAM_NO_MAIN_FUNC -25
+#define AMAL_PROGRAM_INVALID_IMPORTS -26
+#define AMAL_PROGRAM_SECTION_ERROR -27
 
 #define AMAL_PROGRAM_ARGS_SIZE_VARARGS -1
 
+#define AMAL_PROGRAM_MAX_RETURN_VALUES 128
+
 typedef struct {
     void *func;
     int args_byte_size; /* -1 if varargs (AMAL_PROGRAM_ARGS_SIZE_VARARGS) */
@@ -49,9 +53,11 @@ typedef struct {
     u32 *extern_func_indices;
     u8 *intermediates_start;  /* Reference inside @data */
     u8 *strings_start;        /* Reference inside @data */
+    u8 *funcs_start;          /* Reference inside @data */
     u8 *extern_funcs_start;   /* Reference inside @data */
     u8 *exported_funcs;       /* Reference inside @data */
     u8 *exported_funcs_end;   /* Reference inside @data */
+    u8 *imports_start;        /* Reference inside @data */
 
     usize read_index;
     u32 main_func_instruction_offset;
@@ -61,9 +67,14 @@ typedef struct {
     u16 num_functions;
     u16 num_extern_functions;
     u16 num_exported_functions;
+    u8 num_imports;
 
     ArenaAllocator allocator; /* Owned. Used by @extern_funcs_map */
     HashMapType(BufferView, ProgramExternFunc) extern_funcs_map;
+    /* key=((func_index<<32)&funcs_start), value=Buffer<u32=current_code_index> */
+    HashMapType(u64, Buffer) deferred_func_calls;
+    i8 return_values_stack[AMAL_PROGRAM_MAX_RETURN_VALUES];
+    int return_value_index;
 } amal_program;
 
 CHECK_RESULT int amal_program_init(amal_program *self);
diff --git a/include/ssa/ssa.h b/include/ssa/ssa.h
index 9d6949d..0b6501b 100644
--- a/include/ssa/ssa.h
+++ b/include/ssa/ssa.h
@@ -10,6 +10,7 @@
 
 #define SSA_ERR_EXTERN_FUNC_SIG_MISMATCH -20
 
+/* Important: The number of fields in this enum can't exceed 255 */
 typedef enum {
     SSA_ASSIGN_INTER,
     SSA_ASSIGN_STRING,
@@ -24,6 +25,7 @@ typedef enum {
     SSA_FUNC_START,
     SSA_FUNC_END,
     SSA_PUSH,
+    SSA_PUSH_RET,
     SSA_CALL,
     SSA_CALL_EXTERN,
     SSA_JUMP_ZERO,
@@ -55,6 +57,10 @@ typedef struct {
     BufferView name;
 } SsaExportFunc;
 
+typedef struct {
+    FunctionSignature *func_sig;
+} SsaFunc;
+
 typedef i16 JumpOffset;
 typedef i16 SsaRegister;
 typedef u16 SsaIntermediateIndex;
@@ -73,13 +79,15 @@ typedef struct {
     HashMapType(BufferView, SsaExternFuncIndex) extern_funcs_map;
     Buffer/*SsaExternFunc*/ extern_funcs;
     Buffer/*SsaExportFunc*/ export_funcs;
+    Buffer/*SsaFunc*/ funcs;
+
     SsaIntermediateIndex intermediate_counter;
     SsaStringIndex string_counter;
     SsaExternFuncIndex extern_func_counter;
     SsaExportFuncIndex export_func_counter;
+    SsaFuncIndex func_counter;
     SsaRegister reg_counter;
     SsaRegister param_counter;
-    SsaFuncIndex func_counter;
     SsaLabelIndex label_counter;
     Parser *parser; /* Borrowed */
 } Ssa;
@@ -102,14 +110,14 @@ typedef struct {
 
 typedef struct {
     u8 num_args;
-    SsaRegister result;
     FunctionDecl *func_decl;
+    u8 import_index;
 } SsaInsFuncCall;
 
 typedef struct {
     u8 num_args;
-    SsaRegister result;
-    SsaExternFuncIndex extern_func_index;
+    LhsExpr *func_decl_lhs;
+    int import_index;
 } SsaInsFuncCallExtern;
 
 typedef struct {
@@ -134,6 +142,8 @@ typedef struct {
     jmp_buf env;
     Ssa *ssa;
     amal_compiler *compiler;
+    /* 0 if the current scope belongs to the file, otherwise ParserFileScopeReference's import_index (the import file that contains the scope) */
+    u8 import_index;
 } SsaCompilerContext;
 
 /* longjump to context->env on failure */
diff --git a/include/std/buffer.h b/include/std/buffer.h
index d194881..3c2d79c 100644
--- a/include/std/buffer.h
+++ b/include/std/buffer.h
@@ -32,6 +32,8 @@ 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 change the capacity */
 void buffer_clear(Buffer *self);
+/* Also changes size if @new_capacity is less than buffer size */
+CHECK_RESULT int buffer_set_capacity(Buffer *self, usize new_capacity);
 void* buffer_begin(Buffer *self);
 void* buffer_end(Buffer *self);
 usize __buffer_get_size(Buffer *self, usize type_size);
diff --git a/include/std/buffer_view.h b/include/std/buffer_view.h
index 59a97d3..9c0a722 100644
--- a/include/std/buffer_view.h
+++ b/include/std/buffer_view.h
@@ -8,7 +8,7 @@ typedef struct {
     usize size;
 } BufferView;
 
-BufferView create_buffer_view_null();
+BufferView create_buffer_view_null(void);
 BufferView create_buffer_view(const char *data, usize size);
 bool buffer_view_equals(const BufferView *self, const BufferView *other);
 
diff --git a/include/std/hash_map.h b/include/std/hash_map.h
index c9e5b51..05755ce 100644
--- a/include/std/hash_map.h
+++ b/include/std/hash_map.h
@@ -35,6 +35,7 @@ CHECK_RESULT int hash_map_insert(HashMap *self, BufferView key, void *value);
     If @value is NULL, then the value is not copied and the functions works the same as @hash_map_contains
 */
 CHECK_RESULT bool hash_map_get(HashMap *self, BufferView key, void *value);
+CHECK_RESULT bool hash_map_get_ref(HashMap *self, BufferView key, void **value);
 CHECK_RESULT bool hash_map_contains(HashMap *self, BufferView key);
 
 int hash_map_compare_string(const void *a, const void *b);
diff --git a/include/std/log.h b/include/std/log.h
index cd376c6..12b52e1 100644
--- a/include/std/log.h
+++ b/include/std/log.h
@@ -3,7 +3,7 @@
 
 #include "defs.h"
 
-amal_mutex* amal_log_get_mutex();
+amal_mutex* amal_log_get_mutex(void);
 void amal_log_debug(const char *fmt, ...);
 void amal_log_error(const char *fmt, ...);
 void amal_log_info(const char *fmt, ...);
diff --git a/include/std/mem.h b/include/std/mem.h
index 2afce0d..1cc06bf 100644
--- a/include/std/mem.h
+++ b/include/std/mem.h
@@ -9,6 +9,6 @@ int am_memcmp(const void *lhs, const void *rhs, usize size);
 bool am_memeql(const void *lhs, const void *rhs, usize size);
 void am_memset(void *dest, int value, usize size);
 
-long am_pagesize();
+long am_pagesize(void);
 
 #endif
diff --git a/include/std/misc.h b/include/std/misc.h
index e89f1eb..a9bd5b6 100644
--- a/include/std/misc.h
+++ b/include/std/misc.h
@@ -21,8 +21,7 @@
 
 #define return_if_error(result) \
     do { \
-        int return_if_result; \
-        return_if_result = (result); \
+        int return_if_result = (result); \
         if(return_if_result != 0) { \
             return_if_debug_msg; \
             return return_if_result; \
@@ -31,6 +30,11 @@
 
 #define cleanup_if_error(result) do { if((result) != 0) { cleanup_if_debug_msg; goto cleanup; } } while(0)
 
+typedef struct {
+    int result;
+    void *data;
+} ResultMem;
+
 #if defined(__GNUC__) && __GNUC__ >= 4
 #define CHECK_RESULT __attribute__ ((warn_unused_result))
 #elif defined(_MSC_VER) && _MSC_VER >= 1700
diff --git a/include/std/thread.h b/include/std/thread.h
index 2765204..ae8fe39 100644
--- a/include/std/thread.h
+++ b/include/std/thread.h
@@ -43,9 +43,9 @@ CHECK_RESULT int amal_thread_deinit(amal_thread *self);
 CHECK_RESULT int amal_thread_detach(amal_thread *self);
 CHECK_RESULT int amal_thread_join(amal_thread *self, void **result);
 
-bool amal_thread_is_main();
+bool amal_thread_is_main(void);
 /* Returns 0 if the number of usable threads is unknown */
-int amal_get_usable_thread_count();
+int amal_get_usable_thread_count(void);
 
 CHECK_RESULT int amal_mutex_init(amal_mutex *self);
 void amal_mutex_deinit(amal_mutex *self);
-- 
cgit v1.2.3-70-g09d2