diff --git a/base/sources/iron_gc.c b/base/sources/iron_gc.c index 9698fadf..1825ed3b 100644 --- a/base/sources/iron_gc.c +++ b/base/sources/iron_gc.c @@ -1,7 +1,56 @@ #include "iron_gc.h" -#ifdef NO_GC +#ifdef NO_GC_USE_HEAP + +#include +#include +#include +#include +#include + +#define HEAP_SIZE 512 * 1024 * 1024 +static uint8_t *heap = NULL; +static size_t heap_top = 0; + +void *gc_alloc(size_t size) { + size_t old_top = heap_top; + heap_top += size; + if (heap_top >= HEAP_SIZE) { + printf("gc_alloc: out of memory\n"); + } + return &heap[old_top]; +} + +void gc_array(void *ptr, uint32_t *length) {} +void gc_leaf(void *ptr) {} +void gc_root(void *ptr) {} +void gc_unroot(void *ptr) {} + +void *gc_cut(void *ptr, size_t pos, size_t size) { + return NULL; +} + +void *gc_realloc(void *ptr, size_t size) { + void *new_ptr = gc_alloc(size); + if (ptr != NULL) { + memcpy(new_ptr, ptr, size); + } + return new_ptr; +} + +void gc_free(void *ptr) {} +void gc_pause() {} +void gc_resume() {} +void gc_run() {} + +void gc_start(void *bos) { + heap = (uint8_t *)calloc(HEAP_SIZE, 1); +} + +void gc_stop() {} + +#elif defined(NO_GC) #include #include diff --git a/base/tools/amake/alang.c b/base/tools/amake/alang.c index 7b5a641c..4fe9773f 100644 --- a/base/tools/amake/alang.c +++ b/base/tools/amake/alang.c @@ -1,3830 +1,1630 @@ -// Based on https://github.com/Kode/Kongruent by RobDangerous -#include "alang.h" -#include -#include -#include -#include +#include #include -#include -#include -// #define STB_DS_IMPLEMENTATION -#include "../../sources/libs/kong/libs/stb_ds.h" -#ifdef WIN32 -#include -#endif -#ifdef __android__ -#include -#endif -#define static_array(type, name, max_size) \ - typedef struct name { \ - type values[max_size]; \ - size_t size; \ - size_t max; \ - } name; +typedef struct any_map *string_map_t; +typedef struct string_t_array *string_array_t; +typedef struct string_t_array { + string_t **buffer; + int length; + int capacity; +} string_t_array_t; +typedef struct string_array_t_array { + string_array_t **buffer; + int length; + int capacity; +} string_array_t_array_t; -#define static_array_init(array) \ - array.size = 0; \ - array.max = sizeof(array.values) / sizeof(array.values[0]) +bool is_alpha_numeric(i32 code); +bool is_alpha(i32 code); +bool is_numeric(i32 code); +bool is_white_space(i32 code); +string_t *read_token(); +void alang_parse(); +void handle_tabs(string_t *token); +void handle_new_line(string_t *token); +void handle_spaces(string_t *token); +string_t *get_token(i32 off); +string_t *get_token_after_piece(); +void skip_until(string_t *s); +void skip_block(); +string_t *function_return_type(); +string_t *join_type_name(string_t *type, string_t *name); +string_t *read_type(); +string_t *enum_access(string_t *s); +string_t *struct_access(string_t *s); +string_t *struct_alloc(string_t *token, string_t *type); +string_t *array_type(string_t *name); +string_t_array_t *array_contents(string_t *type); +string_t *member_name(string_t *name); +string_t *array_create(string_t *token, string_t *name, string_t *content_type); +string_t *array_access(string_t *token); +bool is_struct(string_t *type); +string_t *strip(string_t *name, i32 len); +string_t *strip_optional(string_t *name); +i32 param_pos(); +void param_pos_add(); +string_t *fn_call(); +string_t *fill_fn_params(string_t *token); +string_t *get_token_c(); +string_t *fill_default_params(string_t *piece); +void skip_piece(i32 nested); +string_t *read_piece(i32 nested); +string_t *string_len(string_t *token); +string_t *value_type(string_t *value); +void set_fn_param_types(); +string_t *number_to_string(string_t *token); +bool token_is_string(string_t *token); +string_t *string_add(string_t *token); +string_t *string_ops(string_t *token); +string_t *array_ops(string_t *token); +string_t *map_ops(string_t *token); +string_t *_t_to_struct(string_t *type); +void stream_write(string_t *token); +void string_write(string_t *token); +void null_write(string_t *token); +void write_enums(); +void write_types(); +void write_array_types(); +void write_fn_declarations(); +void write_globals(); +void write_kickstart(); +void write_function(); +void write_functions(); +void write_iron_c(); +void alang(string_t *_alang_source, string_t *_alang_output); -#define static_array_push(array, value) \ - if (array.size >= array.max) { \ - debug_context context = {0}; \ - error(context, "Array overflow"); \ - } \ - array.values[array.size++] = value; +string_t *alang_output; +string_t *alang_source; +i32 alang_source_length; +string_t_array_t *specials; +bool is_comment; +bool is_string; +i32 pos; +string_t_array_t *tokens; +string_t *header; +any fhandle; +string_t_array_t *strings; +i32 tabs; +bool new_line; +string_t_array_t *basic_types; +string_t_array_t *pass_by_value_types; +string_t_array_t *enums; +any_map_t *value_types; +any_map_t *struct_types; +any_map_t *fn_declarations; +any_map_t *fn_default_params; +string_t_array_t *fn_call_stack; +i32_array_t *param_pos_stack; +bool is_for_loop; +string_t_array_t *global_inits; +string_t_array_t *global_ptrs; +string_array_t_array_t *acontents; +i32_array_t *fnested; +string_t_array_t *add_space_keywords; +i32 array_contents_depth; +void (*out)(string_t *); -#define static_array_push_p(array, value) \ - if (array->size >= array->max) { \ - debug_context context = {0}; \ - error(context, "Array overflow"); \ - } \ - array->values[array->size++] = value; - -// based on https://valkey.io/blog/new-hash-table/ - -struct meta { - uint8_t c : 1; - uint8_t presence : 7; - uint8_t hashes[7]; -}; - -struct container { - int key; -}; - -struct bucket { - struct meta meta; - void *entries[7]; -}; - -#define HASH_MAP_SIZE 256 - -struct hash_map { - struct bucket buckets[HASH_MAP_SIZE]; -}; - -static inline uint64_t hash(int key) { - uint64_t primary = key % HASH_MAP_SIZE; - uint8_t secondary = key % HASH_MAP_SIZE; - return primary | ((uint64_t)secondary << 56); +void _kickstart() { + alang_output = null; + alang_source = null; + gc_unroot(specials); + specials = any_array_create_from_raw( + (any[]){ + ":", + ";", + ",", + "(", + ")", + "[", + "]", + "{", + "}", + "<", + ">", + "!", + }, + 12); + gc_root(specials); + is_comment = false; + is_string = false; + pos = 0; + gc_unroot(tokens); + tokens = any_array_create_from_raw((any[]){}, 0); + gc_root(tokens); + header = ""; + gc_unroot(strings); + strings = any_array_create_from_raw((any[]){}, 0); + gc_root(strings); + tabs = 0; + new_line = false; + gc_unroot(basic_types); + basic_types = any_array_create_from_raw( + (any[]){ + "i8", + "u8", + "i16", + "u16", + "i32", + "u32", + "f32", + "i64", + "u64", + "f64", + "bool", + }, + 11); + gc_root(basic_types); + gc_unroot(pass_by_value_types); + pass_by_value_types = any_array_create_from_raw( + (any[]){ + "vec4_t", + "vec3_t", + "vec2_t", + "quat_t", + "mat4_t", + "mat3_t", + }, + 6); + gc_root(pass_by_value_types); + gc_unroot(enums); + enums = any_array_create_from_raw((any[]){}, 0); + gc_root(enums); + gc_unroot(value_types); + value_types = any_map_create(); + gc_root(value_types); + gc_unroot(struct_types); + struct_types = any_map_create(); + gc_root(struct_types); + gc_unroot(fn_call_stack); + fn_call_stack = any_array_create_from_raw((any[]){}, 0); + gc_root(fn_call_stack); + gc_unroot(param_pos_stack); + param_pos_stack = i32_array_create_from_raw((i32[]){}, 0); + gc_root(param_pos_stack); + is_for_loop = false; + gc_unroot(global_inits); + global_inits = any_array_create_from_raw((any[]){}, 0); + gc_root(global_inits); + gc_unroot(global_ptrs); + global_ptrs = any_array_create_from_raw((any[]){}, 0); + gc_root(global_ptrs); + gc_unroot(acontents); + acontents = any_array_create_from_raw((any[]){}, 0); + gc_root(acontents); + gc_unroot(fnested); + fnested = i32_array_create_from_raw((i32[]){}, 0); + gc_root(fnested); + gc_unroot(add_space_keywords); + add_space_keywords = any_array_create_from_raw( + (any[]){ + "return", + "else", + }, + 2); + gc_root(add_space_keywords); + array_contents_depth = 0; + gc_unroot(out); + out = stream_write; + gc_root(out); } -static inline struct bucket *allocate_bucket(void) { -#ifdef _WIN32 - struct bucket *new_bucket = (struct bucket *)_aligned_malloc(sizeof(struct bucket), 64); -#else - struct bucket *new_bucket = (struct bucket *)aligned_alloc(64, sizeof(struct bucket)); -#endif - assert(new_bucket != NULL); - memset(new_bucket, 0, sizeof(struct bucket)); - - // cache line check - assert((uint64_t)new_bucket % 64 == 0); - assert(sizeof(struct bucket) == 64); - - return new_bucket; +bool is_alpha_numeric(i32 code) { + return (code > 47 && code < 58) || (code == 45) || (code == 43) || (code == 95) || (code == 46) || (code > 64 && code < 91) || (code > 96 && code < 123); } -static inline struct hash_map *hash_map_create(void) { -#ifdef _WIN32 - struct hash_map *map = _aligned_malloc(sizeof(struct hash_map), 64); -#else - struct hash_map *map = aligned_alloc(64, sizeof(struct hash_map)); -#endif - assert(map != NULL); - memset(map, 0, sizeof(struct hash_map)); - - // cache line check - assert((uint64_t)map % 64 == 0); - - return map; +bool is_alpha(i32 code) { + return (code > 96 && code < 123) || (code > 64 && code < 91) || (code == 95); } -static inline void hash_map_destroy(struct hash_map *map) {} +bool is_numeric(i32 code) { + return (code > 47 && code < 58); +} -static inline void hash_map_add_to_bucket(struct bucket *bucket, struct container *value, uint8_t secondary_hash) { - for (uint32_t index = 0; index < 7; ++index) { - if (((bucket->meta.presence >> index) & 1) == 0) { - bucket->entries[index] = value; - bucket->meta.hashes[index] = secondary_hash; +bool is_white_space(i32 code) { + return code == 32 || code == 9 || code == 13 || code == 10; +} - bucket->meta.presence |= (1 << index); - - return; +string_t *read_token() { + while (is_white_space(char_code_at(alang_source, pos))) { + pos++; + } + string_t *token = ""; + bool first = true; + bool is_anum = false; + while (pos < alang_source_length) { + string_t *c = char_at(alang_source, pos); + if (string_equals(token, "//")) { + is_comment = true; } - } - - if (bucket->meta.c) { - hash_map_add_to_bucket((struct bucket *)bucket->entries[6], value, secondary_hash); - } - else { - bucket->meta.c = 1; - - struct container *previous = (struct container *)bucket->entries[6]; - uint8_t previous_secondary_hash = bucket->meta.hashes[6]; - - struct bucket *new_bucket = allocate_bucket(); - - bucket->entries[6] = new_bucket; - - hash_map_add_to_bucket(new_bucket, previous, previous_secondary_hash); - hash_map_add_to_bucket(new_bucket, value, secondary_hash); - } -} - -static inline void hash_map_add(struct hash_map *map, struct container *value) { - uint64_t hash_value = hash(value->key); - uint64_t primary = hash_value & 0xffffffffffffffu; - uint8_t secondary = (uint8_t)(hash_value << 56); - - hash_map_add_to_bucket(&map->buckets[primary], value, secondary); -} - -static inline struct container *hash_map_get_from_bucket(struct bucket *bucket, int key, uint8_t secondary_hash) { - for (uint32_t index = 0; index < 6; ++index) { - if (((bucket->meta.presence >> index) & 1) != 0 && bucket->meta.hashes[index] == secondary_hash) { - struct container *value = (struct container *)bucket->entries[index]; - - if (value->key == key) { - return value; - } - } - } - - if (bucket->meta.c) { - struct bucket *next_bucket = (struct bucket *)bucket->entries[6]; - return hash_map_get_from_bucket(next_bucket, key, secondary_hash); - } - else { - if (((bucket->meta.presence >> 6) & 1) != 0 && bucket->meta.hashes[6] == secondary_hash) { - struct container *value = (struct container *)bucket->entries[6]; - - if (value->key == key) { - return value; - } - } - } - - return NULL; -} - -static inline struct container *hash_map_get(struct hash_map *map, int key) { - uint64_t hash_value = hash(key); - uint64_t primary = hash_value & 0xffffffffffffffu; - uint8_t secondary = (uint8_t)(hash_value << 56); - - struct bucket *bucket = &map->buckets[primary]; - - return hash_map_get_from_bucket(bucket, key, secondary); -} - -static inline void hash_map_iterate_in_bucket(struct bucket *bucket, void (*callback)(struct container *, void *data), void *data) { - for (uint32_t index = 0; index < 6; ++index) { - if (((bucket->meta.presence >> index) & 1) != 0) { - struct container *value = (struct container *)bucket->entries[index]; - callback(value, data); - } - } - - if (bucket->meta.c) { - struct bucket *next_bucket = (struct bucket *)bucket->entries[6]; - hash_map_iterate_in_bucket(next_bucket, callback, data); - } - else { - if (((bucket->meta.presence >> 6) & 1) != 0) { - struct container *value = (struct container *)bucket->entries[6]; - callback(value, data); - } - } -} - -static inline void hash_map_iterate(struct hash_map *map, void (*callback)(struct container *, void *data), void *data) { - for (uint32_t bucket_index = 0; bucket_index < HASH_MAP_SIZE; ++bucket_index) { - struct bucket *bucket = &map->buckets[bucket_index]; - hash_map_iterate_in_bucket(bucket, callback, data); - } -} - -typedef struct debug_context { - const char *filename; - uint32_t column; - uint32_t line; -} debug_context; - -static void error(debug_context context, const char *message, ...); -static void error_no_context(const char *message, ...); -static void error_args(debug_context context, const char *message, va_list args); -static void error_args_no_context(const char *message, va_list args); -static void check_function(bool test, debug_context context, const char *message, ...); -#define check(test, context, message, ...) \ - assert(test); \ - check_function(test, context, message, ##__VA_ARGS__) - -typedef enum { - LOG_LEVEL_INFO, - LOG_LEVEL_WARNING, - LOG_LEVEL_ERROR -} log_level_t; -static void kong_log(log_level_t log_level, const char *format, ...); -static void kong_log_args(log_level_t log_level, const char *format, va_list args); - -//// - -#define OP_SIZE(op, opmember) offsetof(opcode, opmember) + sizeof(op.opmember) -#define NO_FUNCTION 0xFFFFFFFF -#define NO_NAME 0 -#define NO_TYPE 0xFFFFFFFF -#define MAX_MEMBERS 1024 - -struct statement; - -typedef uint32_t global_id; - -typedef struct global_array { - global_id globals[256]; - bool readable[256]; - bool writable[256]; - size_t size; -} global_array; - -struct expression; - -typedef struct expressions { - struct expression *e[256]; - size_t size; -} expressions; - -typedef struct expression { - enum { - EXPRESSION_BINARY, - EXPRESSION_UNARY, - EXPRESSION_BOOLEAN, - EXPRESSION_FLOAT, - EXPRESSION_INT, - // EXPRESSION_STRING, - EXPRESSION_VARIABLE, - EXPRESSION_GROUPING, - EXPRESSION_CALL, - EXPRESSION_MEMBER, - EXPRESSION_ELEMENT - } kind; - - type_ref type; - - union { - struct { - struct expression *left; - operatorr op; - struct expression *right; - } binary; - struct { - operatorr op; - struct expression *right; - } unary; - bool boolean; - double number; - // char string[MAX_IDENTIFIER_SIZE]; - name_id variable; - uint32_t index; - struct expression *grouping; - struct { - name_id func_name; - expressions parameters; - } call; - struct { - struct expression *of; - name_id member_name; - } member; - struct { - struct expression *of; - struct expression *element_index; - } element; - }; -} expression; - -struct statement; - -typedef struct statements { - struct statement *s[256]; - size_t size; -} statements; - -typedef struct local_variable { - name_id name; - type_ref type; - uint64_t variable_id; -} local_variable; - -typedef struct local_variables { - local_variable v[256]; - size_t size; -} local_variables; - -typedef struct block { - struct block *parent; - local_variables vars; - statements statements; -} block; - -typedef struct statement { - enum { - STATEMENT_EXPRESSION, - STATEMENT_RETURN_EXPRESSION, - STATEMENT_IF, - STATEMENT_WHILE, - STATEMENT_DO_WHILE, - STATEMENT_BLOCK, - STATEMENT_LOCAL_VARIABLE - } kind; - - union { - expression *expression; - struct { - expression *test; - struct statement *if_block; - expression *else_tests[64]; - struct statement *else_blocks[64]; - uint16_t else_size; - } iffy; - struct { - expression *test; - struct statement *while_block; - } whiley; - block block; - struct { - local_variable var; - expression *init; - } local_variable; - }; -} statement; - -typedef struct definition { - enum { - DEFINITION_FUNCTION, - DEFINITION_STRUCT, - DEFINITION_CONST_CUSTOM, - DEFINITION_CONST_BASIC - } kind; - - union { - function_id function; - global_id global; - type_id type; - }; -} definition; - -typedef struct member { - name_id name; - type_ref type; - token value; -} member; - -typedef struct members { - member m[MAX_MEMBERS]; - size_t size; -} members; - -typedef struct type { - attribute_list attributes; - name_id name; - bool built_in; - members members; - type_id base; - uint32_t array_size; -} type; - -static void allocate_globals(void); -void _compile_function_block(opcodes *code, struct statement *block); -static variable allocate_variable(type_ref type, variable_kind kind); - -void _functions_init(void); -static function_id add_function(name_id name); -static function_id find_function(name_id name); -function *_get_function(function_id function); - -void _globals_init(void); -static global_id add_global(type_id type, attribute_list attributes, name_id name); -static global_id add_global_with_value(type_id type, attribute_list attributes, name_id name, global_value value); -static global *find_global(name_id name); -static global *get_global(global_id id); -static void assign_global_var(global_id id, uint64_t var_index); - -void _names_init(void); -static name_id add_name(char *name); -char *_get_name(name_id index); - -void _parse(const char *filename, tokens *tokens); -static token tokens_get(tokens *arr, size_t index); -tokens _tokenize(const char *filename, const char *source); - -void _resolve_types(void); -static void init_type_ref(type_ref *t, name_id name); -void _types_init(void); -static type_id add_type(name_id name); -static type_id add_full_type(type *t); -static type_id find_type_by_name(name_id name); -static type_id find_type_by_ref(type_ref *t); -static type *get_type(type_id t); - -static void kong_log(log_level_t level, const char *format, ...) { - va_list args; - va_start(args, format); - kong_log_args(level, format, args); - va_end(args); -} - -static void kong_log_args(log_level_t level, const char *format, va_list args) { -#ifdef WIN32 - { - char buffer[4096]; - vsnprintf(buffer, 4090, format, args); - strcat(buffer, "\r\n"); - OutputDebugStringA(buffer); - } -#endif - - { - char buffer[4096]; - vsnprintf(buffer, 4090, format, args); - strcat(buffer, "\n"); - fprintf(level == LOG_LEVEL_INFO ? stdout : stderr, "%s", buffer); - } -} - -static void debug_break(void) { -#ifndef NDEBUG -#if defined(_MSC_VER) - __debugbreak(); -#elif defined(__clang__) - __builtin_debugtrap(); -#else -#if defined(__aarch64__) - __asm__ volatile(".inst 0xd4200000"); -#elif defined(__x86_64__) - __asm__ volatile("int $0x03"); -#else - kong_log(LOG_LEVEL_WARNING, "Oh no, debug_break is not implemented for the current compiler and CPU."); -#endif -#endif -#endif -} - -static void error_args(debug_context context, const char *message, va_list args) { - char buffer[4096]; - if (context.filename != NULL) { - sprintf(buffer, "In column %i at line %i in %s: ", context.column + 1, context.line + 1, context.filename); - } - else { - sprintf(buffer, "In column %i at line %i: ", context.column + 1, context.line + 1); - } - strcat(buffer, message); - kong_log_args(LOG_LEVEL_ERROR, buffer, args); - debug_break(); - exit(1); -} - -static void error_args_no_context(const char *message, va_list args) { - kong_log_args(LOG_LEVEL_ERROR, message, args); - exit(1); -} - -static void error(debug_context context, const char *message, ...) { - va_list args; - va_start(args, message); - error_args(context, message, args); - va_end(args); -} - -static void error_no_context(const char *message, ...) { - va_list args; - va_start(args, message); - error_args_no_context(message, args); - va_end(args); -} - -static void check_function(bool test, debug_context context, const char *message, ...) { - if (!test) { - va_list args; - va_start(args, message); - error_args(context, message, args); - va_end(args); - } -} - -//// - -typedef enum modifier { - MODIFIER_IN, - // Out, -} modifier_t; - -typedef enum mode { - MODE_SELECT, - MODE_NUMBER, - // MODE_STRING, - MODE_OPERATOR, - MODE_IDENTIFIER, - MODE_LINE_COMMENT, - MODE_COMMENT -} mode; - -typedef struct modifiers { - modifier_t m[16]; - size_t size; -} modifiers_t; - -typedef struct tokenizer_state { - const char *iterator; - char next; - char next_next; - int line, column; - bool line_end; -} tokenizer_state; - -typedef struct block_ids { - uint64_t start; - uint64_t end; -} block_ids; - -typedef struct state { - tokens *tokens; - size_t index; - debug_context context; -} state_t; - -typedef struct tokenizer_buffer { - char *buf; - size_t current_size; - size_t max_size; - int column, line; -} tokenizer_buffer; - -typedef struct prefix { - char str[5]; - size_t size; -} prefix; - -struct { - char *key; - name_id value; -} *names_hash = NULL; - -allocated_global __allocated_globals[1024]; -size_t __allocated_globals_size = 0; -static const char all_names[1024 * 1024]; -static uint64_t next_variable_id = 1; -static variable all_variables[1024 * 1024]; -static function *functions = NULL; -static function_id functions_size = 128; -static function_id next_function_index = 0; -static global globals[1024]; -static global_id globals_size = 0; -static char *names = NULL; -static size_t names_size = 1024 * 1024; -static name_id names_index = 1; -static statement statements_buffer[8192]; -static int statement_index = 0; -static expression experessions_buffer[8192]; -static int expression_index = 0; -static type *types = NULL; -static type_id types_size = 1024; -static type_id next_type_index = 0; -type_id _void_id; -type_id _float_id; -type_id _int_id; -type_id _uint_id; -type_id _bool_id; -static type_id function_type_id; - -static definition parse_definition(state_t *state); -static statement *parse_statement(state_t *state, block *parent_block); -static expression *parse_expression(state_t *state); -static definition parse_struct(state_t *state); -static definition parse_function(state_t *state); -static definition parse_const(state_t *state, attribute_list attributes); -static void resolve_types_in_expression(statement *parent, expression *e); - -static allocated_global find_allocated_global(name_id name) { - for (size_t i = 0; i < __allocated_globals_size; ++i) { - if (name == __allocated_globals[i].g->name) { - return __allocated_globals[i]; - } - } - - allocated_global a; - a.g = NULL; - a.variable_id = 0; - return a; -} - -static variable find_local_var(block *b, name_id name) { - if (b == NULL) { - variable var; - var.index = 0; - init_type_ref(&var.type, NO_NAME); - return var; - } - - for (size_t i = 0; i < b->vars.size; ++i) { - if (b->vars.v[i].name == name) { - debug_context context = {0}; - check(b->vars.v[i].type.type != NO_TYPE, context, "Local variable does not have a type"); - variable var; - var.index = b->vars.v[i].variable_id; - var.type = b->vars.v[i].type; - var.kind = VARIABLE_LOCAL; - return var; - } - } - - return find_local_var(b->parent, name); -} - -static variable find_variable(block *parent, name_id name) { - variable local_var = find_local_var(parent, name); - if (local_var.index == 0) { - allocated_global global = find_allocated_global(name); - if (global.g->type != NO_TYPE && global.variable_id != 0) { - variable v; - init_type_ref(&v.type, NO_NAME); - v.type.type = global.g->type; - v.index = global.variable_id; - v.kind = VARIABLE_GLOBAL; - return v; - } - else { - debug_context context = {0}; - error(context, "Variable %s not found", _get_name(name)); - - variable v; - v.index = 0; - return v; - } - } - else { - return local_var; - } -} - -static variable allocate_variable(type_ref type, variable_kind kind) { - variable v; - v.index = next_variable_id; - v.type = type; - v.kind = kind; - all_variables[v.index] = v; - ++next_variable_id; - return v; -} - -static opcode *emit_op(opcodes *code, opcode *o) { - assert(code->size + o->size < OPCODES_SIZE); - - uint8_t *location = &code->o[code->size]; - - memcpy(&code->o[code->size], o, o->size); - - code->size += o->size; - - return (opcode *)location; -} - -static variable emit_expression(opcodes *code, block *parent, expression *e) { - switch (e->kind) { - case EXPRESSION_BINARY: { - expression *left = e->binary.left; - expression *right = e->binary.right; - - debug_context context = {0}; - - switch (e->binary.op) { - case OPERATOR_EQUALS: - case OPERATOR_NOT_EQUALS: - case OPERATOR_GREATER: - case OPERATOR_GREATER_EQUAL: - case OPERATOR_LESS: - case OPERATOR_LESS_EQUAL: - case OPERATOR_AND: - case OPERATOR_OR: { - variable right_var = emit_expression(code, parent, right); - variable left_var = emit_expression(code, parent, left); - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = _bool_id; - variable result_var = allocate_variable(t, VARIABLE_INTERNAL); - - opcode o; - switch (e->binary.op) { - case OPERATOR_EQUALS: - o.type = OPCODE_EQUALS; - break; - case OPERATOR_NOT_EQUALS: - o.type = OPCODE_NOT_EQUALS; - break; - case OPERATOR_GREATER: - o.type = OPCODE_GREATER; - break; - case OPERATOR_GREATER_EQUAL: - o.type = OPCODE_GREATER_EQUAL; - break; - case OPERATOR_LESS: - o.type = OPCODE_LESS; - break; - case OPERATOR_LESS_EQUAL: - o.type = OPCODE_LESS_EQUAL; - break; - case OPERATOR_AND: - o.type = OPCODE_AND; - break; - case OPERATOR_OR: - o.type = OPCODE_OR; - break; - default: { - error(context, "Unexpected operator"); - } - } - o.size = OP_SIZE(o, op_binary); - o.op_binary.right = right_var; - o.op_binary.left = left_var; - o.op_binary.result = result_var; - emit_op(code, &o); - - return result_var; - } - case OPERATOR_MINUS: - case OPERATOR_PLUS: - case OPERATOR_DIVIDE: - case OPERATOR_MULTIPLY: - case OPERATOR_MOD: - case OPERATOR_BITWISE_XOR: - case OPERATOR_BITWISE_AND: - case OPERATOR_BITWISE_OR: - case OPERATOR_LEFT_SHIFT: - case OPERATOR_RIGHT_SHIFT: { - variable right_var = emit_expression(code, parent, right); - variable left_var = emit_expression(code, parent, left); - variable result_var = allocate_variable(e->type, VARIABLE_INTERNAL); - - opcode o; - switch (e->binary.op) { - case OPERATOR_MINUS: - o.type = OPCODE_SUB; - break; - case OPERATOR_PLUS: - o.type = OPCODE_ADD; - break; - case OPERATOR_DIVIDE: - o.type = OPCODE_DIVIDE; - break; - case OPERATOR_MULTIPLY: - o.type = OPCODE_MULTIPLY; - break; - case OPERATOR_MOD: - o.type = OPCODE_MOD; - break; - case OPERATOR_BITWISE_XOR: - o.type = OPCODE_BITWISE_XOR; - break; - case OPERATOR_BITWISE_AND: - o.type = OPCODE_BITWISE_AND; - break; - case OPERATOR_BITWISE_OR: - o.type = OPCODE_BITWISE_OR; - break; - case OPERATOR_LEFT_SHIFT: - o.type = OPCODE_LEFT_SHIFT; - break; - case OPERATOR_RIGHT_SHIFT: - o.type = OPCODE_RIGHT_SHIFT; - break; - default: { - error(context, "Unexpected operator"); - } - } - o.size = OP_SIZE(o, op_binary); - o.op_binary.right = right_var; - o.op_binary.left = left_var; - o.op_binary.result = result_var; - emit_op(code, &o); - - return result_var; - } - case OPERATOR_NOT: { - error(context, "! is not a binary operator"); - } - case OPERATOR_ASSIGN: - case OPERATOR_MINUS_ASSIGN: - case OPERATOR_PLUS_ASSIGN: - case OPERATOR_DIVIDE_ASSIGN: - case OPERATOR_MULTIPLY_ASSIGN: { - variable v = emit_expression(code, parent, right); - - switch (left->kind) { - case EXPRESSION_VARIABLE: { - opcode o; - switch (e->binary.op) { - case OPERATOR_ASSIGN: - o.type = OPCODE_STORE_VARIABLE; - break; - case OPERATOR_MINUS_ASSIGN: - o.type = OPCODE_SUB_AND_STORE_VARIABLE; - break; - case OPERATOR_PLUS_ASSIGN: - o.type = OPCODE_ADD_AND_STORE_VARIABLE; - break; - case OPERATOR_DIVIDE_ASSIGN: - o.type = OPCODE_DIVIDE_AND_STORE_VARIABLE; - break; - case OPERATOR_MULTIPLY_ASSIGN: - o.type = OPCODE_MULTIPLY_AND_STORE_VARIABLE; - break; - default: { - error(context, "Unexpected operator"); + if (is_comment) { + token = string_join(token, c); + pos++; + if (string_equals(c, "\n")) { + is_comment = false; + if (starts_with(token, "/// include") || starts_with(token, "/// define")) { + gc_unroot(header); + header = string_join(header, string_join("#", substring(token, 4, string_length(token)))); + gc_root(header); } - } - o.size = OP_SIZE(o, op_store_var); - o.op_store_var.from = v; - o.op_store_var.to = find_variable(parent, left->variable); - emit_op(code, &o); + return read_token(); + } + continue; + } + if (string_equals(c, "\"")) { + string_t *last = string_length(token) > 0 ? char_at(token, string_length(token) - 1) : ""; + string_t *last_last = string_length(token) > 1 ? char_at(token, string_length(token) - 2) : ""; + bool is_escaped = string_equals(last, "\\") && !string_equals(last_last, "\\"); + if (!is_escaped) { + is_string = !is_string; + } + if (!is_string) { + token = string_join(token, c); + pos++; break; } - case EXPRESSION_ELEMENT: - case EXPRESSION_MEMBER: { - opcode o; - switch (e->binary.op) { - case OPERATOR_ASSIGN: - o.type = OPCODE_STORE_ACCESS_LIST; - break; - case OPERATOR_MINUS_ASSIGN: - o.type = OPCODE_SUB_AND_STORE_ACCESS_LIST; - break; - case OPERATOR_PLUS_ASSIGN: - o.type = OPCODE_ADD_AND_STORE_ACCESS_LIST; - break; - case OPERATOR_DIVIDE_ASSIGN: - o.type = OPCODE_DIVIDE_AND_STORE_ACCESS_LIST; - break; - case OPERATOR_MULTIPLY_ASSIGN: - o.type = OPCODE_MULTIPLY_AND_STORE_ACCESS_LIST; - break; - default: { - error(context, "Unexpected operator"); - } - } - o.size = OP_SIZE(o, op_store_access_list); - o.op_store_access_list.from = v; - - expression *of = left; - - access access_list[64]; - uint32_t access_list_size = 0; - - while (of->kind == EXPRESSION_ELEMENT || of->kind == EXPRESSION_MEMBER) { - access *a = &access_list[access_list_size]; - a->type = of->type.type; - - switch (of->kind) { - case EXPRESSION_ELEMENT: - a->kind = ACCESS_ELEMENT; - a->access_element.index = emit_expression(code, parent, of->element.element_index); - - of = of->element.of; - - break; - case EXPRESSION_MEMBER: - a->kind = ACCESS_MEMBER; - a->access_member.name = of->member.member_name; - - of = of->member.of; - - break; - default: - assert(false); - break; - } - - access_list_size += 1; - } - - o.op_store_access_list.access_list_size = access_list_size; - - for (uint32_t access_index = 0; access_index < access_list_size; ++access_index) { - o.op_store_access_list.access_list[access_list_size - access_index - 1] = access_list[access_index]; - } - - o.op_store_access_list.to = emit_expression(code, parent, of); - - emit_op(code, &o); - break; + } + if (is_string) { + if (string_equals(c, "\r")) { + pos++; + continue; } - default: { - debug_context context = {0}; - error(context, "Expected a variable or an access"); - } - } - - return v; + token = string_join(token, c); + pos++; + continue; } + if (is_white_space(char_code_at(alang_source, pos))) { + break; } - break; - } - case EXPRESSION_UNARY: { - debug_context context = {0}; - switch (e->unary.op) { - case OPERATOR_EQUALS: - error(context, "not implemented"); - case OPERATOR_NOT_EQUALS: - error(context, "not implemented"); - case OPERATOR_GREATER: - error(context, "not implemented"); - case OPERATOR_GREATER_EQUAL: - error(context, "not implemented"); - case OPERATOR_LESS: - error(context, "not implemented"); - case OPERATOR_LESS_EQUAL: - error(context, "not implemented"); - case OPERATOR_MINUS: { - variable v = emit_expression(code, parent, e->unary.right); - opcode o; - o.type = OPCODE_NEGATE; - o.size = OP_SIZE(o, op_negate); - o.op_negate.from = v; - o.op_negate.to = allocate_variable(v.type, VARIABLE_INTERNAL); - emit_op(code, &o); - return o.op_negate.to; + if (first) { + first = false; + is_anum = is_alpha_numeric(char_code_at(c, 0)); } - case OPERATOR_PLUS: - error(context, "not implemented"); - case OPERATOR_DIVIDE: - error(context, "not implemented"); - case OPERATOR_MULTIPLY: - error(context, "not implemented"); - case OPERATOR_NOT: { - variable v = emit_expression(code, parent, e->unary.right); - opcode o; - o.type = OPCODE_NOT; - o.size = OP_SIZE(o, op_not); - o.op_not.from = v; - o.op_not.to = allocate_variable(v.type, VARIABLE_INTERNAL); - emit_op(code, &o); - return o.op_not.to; + bool is_special = char_ptr_array_index_of(specials, c) > -1; + if (is_anum && is_special) { + break; } - case OPERATOR_OR: - error(context, "not implemented"); - case OPERATOR_BITWISE_XOR: - error(context, "not implemented"); - case OPERATOR_BITWISE_AND: - error(context, "not implemented"); - case OPERATOR_BITWISE_OR: - error(context, "not implemented"); - case OPERATOR_LEFT_SHIFT: - error(context, "not implemented"); - case OPERATOR_RIGHT_SHIFT: - error(context, "not implemented"); - case OPERATOR_AND: - error(context, "not implemented"); - case OPERATOR_MOD: - error(context, "not implemented"); - case OPERATOR_ASSIGN: - error(context, "not implemented"); - case OPERATOR_PLUS_ASSIGN: - case OPERATOR_MINUS_ASSIGN: - case OPERATOR_MULTIPLY_ASSIGN: - case OPERATOR_DIVIDE_ASSIGN: - error(context, "not implemented"); - } - } - case EXPRESSION_BOOLEAN: { - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = _float_id; - variable v = allocate_variable(t, VARIABLE_INTERNAL); - - opcode o; - o.type = OPCODE_LOAD_BOOL_CONSTANT; - o.size = OP_SIZE(o, op_load_bool_constant); - o.op_load_bool_constant.boolean = e->boolean; - o.op_load_bool_constant.to = v; - emit_op(code, &o); - - return v; - } - case EXPRESSION_FLOAT: { - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = _float_id; - variable v = allocate_variable(t, VARIABLE_INTERNAL); - - opcode o; - o.type = OPCODE_LOAD_FLOAT_CONSTANT; - o.size = OP_SIZE(o, op_load_float_constant); - o.op_load_float_constant.number = (float)e->number; - o.op_load_float_constant.to = v; - emit_op(code, &o); - - return v; - } - case EXPRESSION_INT: { - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = _int_id; - variable v = allocate_variable(t, VARIABLE_INTERNAL); - - opcode o; - o.type = OPCODE_LOAD_INT_CONSTANT; - o.size = OP_SIZE(o, op_load_float_constant); - o.op_load_int_constant.number = (int)e->number; - o.op_load_int_constant.to = v; - emit_op(code, &o); - - return v; - } - // case EXPRESSION_STRING: - // error("not implemented", 0, 0); - case EXPRESSION_VARIABLE: { - return find_variable(parent, e->variable); - } - case EXPRESSION_GROUPING: { - return emit_expression(code, parent, e->grouping); - } - case EXPRESSION_CALL: { - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = e->type.type; - variable v = allocate_variable(t, VARIABLE_INTERNAL); - - opcode o; - o.type = OPCODE_CALL; - o.size = OP_SIZE(o, op_call); - o.op_call.func = e->call.func_name; - o.op_call.var = v; - - debug_context context = {0}; - check(e->call.parameters.size <= sizeof(o.op_call.parameters) / sizeof(variable), context, "Call parameters missized"); - for (size_t i = 0; i < e->call.parameters.size; ++i) { - o.op_call.parameters[i] = emit_expression(code, parent, e->call.parameters.e[i]); - } - o.op_call.parameters_size = (uint8_t)e->call.parameters.size; - - emit_op(code, &o); - - return v; - } - case EXPRESSION_ELEMENT: - case EXPRESSION_MEMBER: { - opcode o; - o.type = OPCODE_LOAD_ACCESS_LIST; - o.size = OP_SIZE(o, op_load_access_list); - - variable v = allocate_variable(e->type, VARIABLE_INTERNAL); - o.op_load_access_list.to = v; - - expression *of = e; - - access access_list[64]; - uint32_t access_list_size = 0; - - while (of->kind == EXPRESSION_ELEMENT || of->kind == EXPRESSION_MEMBER) { - access *a = &access_list[access_list_size]; - a->type = of->type.type; - - switch (of->kind) { - case EXPRESSION_ELEMENT: - a->kind = ACCESS_ELEMENT; - a->access_element.index = emit_expression(code, parent, of->element.element_index); - - of = of->element.of; - - break; - case EXPRESSION_MEMBER: - a->kind = ACCESS_MEMBER; - a->access_member.name = of->member.member_name; - - of = of->member.of; - - break; - default: - assert(false); - break; - } - - access_list_size += 1; - } - - o.op_load_access_list.access_list_size = access_list_size; - - for (uint32_t access_index = 0; access_index < access_list_size; ++access_index) { - o.op_load_access_list.access_list[access_list_size - access_index - 1] = access_list[access_index]; - } - - o.op_load_access_list.from = emit_expression(code, parent, of); - - emit_op(code, &o); - - return v; - } - default: { - debug_context context = {0}; - error(context, "not implemented"); - } - } - - { - debug_context context = {0}; - error(context, "Supposedly unreachable code reached"); - variable v; - v.index = 0; - return v; - } -} - -static block_ids emit_statement(opcodes *code, block *parent, statement *statement) { - switch (statement->kind) { - case STATEMENT_EXPRESSION: - emit_expression(code, parent, statement->expression); - break; - case STATEMENT_RETURN_EXPRESSION: { - opcode o; - o.type = OPCODE_RETURN; - variable v = emit_expression(code, parent, statement->expression); - if (v.index == 0) { - o.size = offsetof(opcode, op_return); - } - else { - o.size = OP_SIZE(o, op_return); - o.op_return.var = v; - } - emit_op(code, &o); - break; - } - case STATEMENT_IF: { - struct previous_condition { - variable condition; - variable summed_condition; - }; - struct previous_condition previous_conditions[64] = {0}; - uint8_t previous_conditions_size = 0; - - { - opcode o; - o.type = OPCODE_IF; - o.size = OP_SIZE(o, op_if); - - variable initial_condition = emit_expression(code, parent, statement->iffy.test); - - o.op_if.condition = initial_condition; - - opcode *written_opcode = emit_op(code, &o); - - previous_conditions[previous_conditions_size].condition = initial_condition; - previous_conditions_size += 1; - - block_ids ids = emit_statement(code, parent, statement->iffy.if_block); - - written_opcode->op_if.start_id = ids.start; - written_opcode->op_if.end_id = ids.end; - } - - for (uint16_t i = 0; i < statement->iffy.else_size; ++i) { - variable current_condition; - { - opcode o; - o.type = OPCODE_NOT; - o.size = OP_SIZE(o, op_not); - o.op_not.from = previous_conditions[previous_conditions_size - 1].condition; - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = _bool_id; - current_condition = allocate_variable(t, VARIABLE_INTERNAL); - o.op_not.to = current_condition; - emit_op(code, &o); - } - - variable summed_condition; - if (previous_conditions_size == 1) { - summed_condition = previous_conditions[0].summed_condition = current_condition; - } - else { - opcode o; - o.type = OPCODE_AND; - o.size = OP_SIZE(o, op_binary); - o.op_binary.left = previous_conditions[previous_conditions_size - 2].summed_condition; - o.op_binary.right = current_condition; - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = _bool_id; - summed_condition = allocate_variable(t, VARIABLE_INTERNAL); - o.op_binary.result = summed_condition; - emit_op(code, &o); - } - - opcode o; - o.type = OPCODE_IF; - o.size = OP_SIZE(o, op_if); - - if (statement->iffy.else_tests[i] != NULL) { - variable v = emit_expression(code, parent, statement->iffy.else_tests[i]); - - variable else_test; - { - opcode o; - o.type = OPCODE_AND; - o.size = OP_SIZE(o, op_binary); - o.op_binary.left = summed_condition; - o.op_binary.right = v; - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = _bool_id; - else_test = allocate_variable(t, VARIABLE_INTERNAL); - o.op_binary.result = else_test; - emit_op(code, &o); - } - - o.op_if.condition = else_test; - - previous_conditions[previous_conditions_size].condition = v; - previous_conditions_size += 1; - } - else { - o.op_if.condition = summed_condition; - } - - { - opcode *written_opcode = emit_op(code, &o); - - block_ids ids = emit_statement(code, parent, statement->iffy.else_blocks[i]); - - written_opcode->op_if.start_id = ids.start; - written_opcode->op_if.end_id = ids.end; - } - } - - break; - } - case STATEMENT_WHILE: { - uint64_t start_id = next_variable_id; - ++next_variable_id; - uint64_t continue_id = next_variable_id; - ++next_variable_id; - uint64_t end_id = next_variable_id; - ++next_variable_id; - - { - opcode o; - o.type = OPCODE_WHILE_START; - o.op_while_start.start_id = start_id; - o.op_while_start.continue_id = continue_id; - o.op_while_start.end_id = end_id; - o.size = OP_SIZE(o, op_while_start); - emit_op(code, &o); - } - - { - opcode o; - o.type = OPCODE_WHILE_CONDITION; - o.size = OP_SIZE(o, op_while); - - variable v = emit_expression(code, parent, statement->whiley.test); - - o.op_while.condition = v; - o.op_while.end_id = end_id; - - emit_op(code, &o); - } - - emit_statement(code, parent, statement->whiley.while_block); - - { - opcode o; - o.type = OPCODE_WHILE_END; - o.op_while_end.start_id = start_id; - o.op_while_end.continue_id = continue_id; - o.op_while_end.end_id = end_id; - o.size = OP_SIZE(o, op_while_end); - emit_op(code, &o); - } - - break; - } - case STATEMENT_DO_WHILE: { - uint64_t start_id = next_variable_id; - ++next_variable_id; - uint64_t continue_id = next_variable_id; - ++next_variable_id; - uint64_t end_id = next_variable_id; - ++next_variable_id; - - { - opcode o; - o.type = OPCODE_WHILE_START; - o.op_while_start.start_id = start_id; - o.op_while_start.continue_id = continue_id; - o.op_while_start.end_id = end_id; - o.size = OP_SIZE(o, op_while_start); - emit_op(code, &o); - } - - emit_statement(code, parent, statement->whiley.while_block); - - { - opcode o; - o.type = OPCODE_WHILE_CONDITION; - o.size = OP_SIZE(o, op_while); - - variable v = emit_expression(code, parent, statement->whiley.test); - - o.op_while.condition = v; - o.op_while.end_id = end_id; - - emit_op(code, &o); - } - - { - opcode o; - o.type = OPCODE_WHILE_END; - o.op_while_end.start_id = start_id; - o.op_while_end.continue_id = continue_id; - o.op_while_end.end_id = end_id; - o.size = OP_SIZE(o, op_while_end); - emit_op(code, &o); - } - - break; - } - case STATEMENT_BLOCK: { - for (size_t i = 0; i < statement->block.vars.size; ++i) { - variable var = allocate_variable(statement->block.vars.v[i].type, VARIABLE_LOCAL); - statement->block.vars.v[i].variable_id = var.index; - } - - uint64_t start_block_id = next_variable_id; - ++next_variable_id; - - uint64_t end_block_id = next_variable_id; - ++next_variable_id; - - { - opcode o; - o.type = OPCODE_BLOCK_START; - o.op_block.id = start_block_id; - o.size = OP_SIZE(o, op_block); - emit_op(code, &o); - } - - for (size_t i = 0; i < statement->block.statements.size; ++i) { - emit_statement(code, &statement->block, statement->block.statements.s[i]); - } - - { - opcode o; - o.type = OPCODE_BLOCK_END; - o.op_block.id = end_block_id; - o.size = OP_SIZE(o, op_block); - emit_op(code, &o); - } - - block_ids ids; - ids.start = start_block_id; - ids.end = end_block_id; - return ids; - } - case STATEMENT_LOCAL_VARIABLE: { - opcode o; - o.type = OPCODE_VAR; - o.size = OP_SIZE(o, op_var); - - variable init_var = {0}; - if (statement->local_variable.init != NULL) { - init_var = emit_expression(code, parent, statement->local_variable.init); - } - - variable local_var = find_local_var(parent, statement->local_variable.var.name); - statement->local_variable.var.variable_id = local_var.index; - o.op_var.var.index = statement->local_variable.var.variable_id; - debug_context context = {0}; - check(statement->local_variable.var.type.type != NO_TYPE, context, "Local var has no type"); - o.op_var.var.type = statement->local_variable.var.type; - emit_op(code, &o); - - if (statement->local_variable.init != NULL) { - opcode o; - o.type = OPCODE_STORE_VARIABLE; - o.size = OP_SIZE(o, op_store_var); - - o.op_store_var.from = init_var; - o.op_store_var.to = local_var; - - emit_op(code, &o); - } - - break; - } - } - - block_ids ids; - ids.start = 0; - ids.end = 0; - return ids; -} - -static void allocate_globals(void) { - for (global_id i = 0; get_global(i) != NULL && get_global(i)->type != NO_TYPE; ++i) { - global *g = get_global(i); - - type_ref t; - init_type_ref(&t, NO_NAME); - t.type = g->type; - variable v = allocate_variable(t, VARIABLE_GLOBAL); - __allocated_globals[__allocated_globals_size].g = g; - __allocated_globals[__allocated_globals_size].variable_id = v.index; - __allocated_globals_size += 1; - - assign_global_var(i, v.index); - } -} - -void _compile_function_block(opcodes *code, struct statement *block) { - if (block == NULL) { - // built-in - return; - } - - if (block->kind != STATEMENT_BLOCK) { - debug_context context = {0}; - error(context, "Expected a block"); - } - for (size_t i = 0; i < block->block.vars.size; ++i) { - variable var = allocate_variable(block->block.vars.v[i].type, VARIABLE_LOCAL); - block->block.vars.v[i].variable_id = var.index; - } - for (size_t i = 0; i < block->block.statements.size; ++i) { - emit_statement(code, &block->block, block->block.statements.s[i]); - } -} - -static void add_func_int(char *name) { - function_id func = add_function(add_name(name)); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("int")); - f->return_type.type = find_type_by_ref(&f->return_type); - f->parameters_size = 0; - f->block = NULL; -} - -static void add_func_float(char *name) { - function_id func = add_function(add_name(name)); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("float")); - f->return_type.type = find_type_by_ref(&f->return_type); - f->parameters_size = 0; - f->block = NULL; -} - -static void add_func_uint(char *name) { - function_id func = add_function(add_name(name)); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("uint")); - f->return_type.type = find_type_by_ref(&f->return_type); - f->parameters_size = 0; - f->block = NULL; -} - -static void add_func_float_float(char *name) { - function_id func = add_function(add_name(name)); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("float")); - f->return_type.type = find_type_by_ref(&f->return_type); - f->parameter_names[0] = add_name("a"); - init_type_ref(&f->parameter_types[0], add_name("float")); - f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); - f->parameters_size = 1; - f->block = NULL; -} - -void _functions_init(void) { - function *new_functions = realloc(functions, functions_size * sizeof(function)); - debug_context context = {0}; - check(new_functions != NULL, context, "Could not allocate functions"); - functions = new_functions; - next_function_index = 0; - - { - function_id func = add_function(add_name("float")); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("float")); - f->return_type.type = find_type_by_ref(&f->return_type); - f->parameter_names[0] = add_name("x"); - init_type_ref(&f->parameter_types[0], add_name("float")); - f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); - - f->parameters_size = 1; - - f->block = NULL; - } - - { - function_id func = add_function(add_name("int")); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("int")); - f->return_type.type = find_type_by_ref(&f->return_type); - - f->parameter_names[0] = add_name("x"); - init_type_ref(&f->parameter_types[0], add_name("int")); - f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); - - f->parameters_size = 1; - - f->block = NULL; - } - - { - function_id func = add_function(add_name("uint")); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("uint")); - f->return_type.type = find_type_by_ref(&f->return_type); - - f->parameter_names[0] = add_name("x"); - init_type_ref(&f->parameter_types[0], add_name("uint")); - f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); - - f->parameters_size = 1; - - f->block = NULL; - } - - { - function_id func = add_function(add_name("bool")); - function *f = _get_function(func); - init_type_ref(&f->return_type, add_name("bool")); - f->return_type.type = find_type_by_ref(&f->return_type); - - f->parameter_names[0] = add_name("x"); - init_type_ref(&f->parameter_types[0], add_name("bool")); - f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); - - f->parameters_size = 1; - - f->block = NULL; - } - - add_func_float_float("print"); - // add_func_float_float("sin"); - // add_func_float_float("cos"); -} - -static void grow_functions_if_needed(uint64_t size) { - while (size >= functions_size) { - functions_size *= 2; - function *new_functions = realloc(functions, functions_size * sizeof(function)); - debug_context context = {0}; - check(new_functions != NULL, context, "Could not allocate functions"); - functions = new_functions; - } -} - -static function_id add_function(name_id name) { - grow_functions_if_needed(next_function_index + 1); - - function_id f = next_function_index; - ++next_function_index; - - functions[f].name = name; - functions[f].attributes.attributes_count = 0; - init_type_ref(&functions[f].return_type, NO_NAME); - functions[f].parameters_size = 0; - memset(functions[f].parameter_attributes, 0, sizeof(functions[f].parameter_attributes)); - functions[f].block = NULL; - memset(functions[f].code.o, 0, sizeof(functions[f].code.o)); - functions[f].code.size = 0; - - return f; -} - -function *_get_function(function_id function) { - if (function >= next_function_index) { - return NULL; - } - return &functions[function]; -} - -void _globals_init(void) { - global_value int_value; - int_value.kind = GLOBAL_VALUE_INT; - - attribute_list attributes = {0}; - - // int_value.value.ints[0] = 0; - // add_global_with_value(_float_id, attributes, add_name("COMPARE_ALWAYS"), int_value); - - // global_value uint_value; - // uint_value.kind = GLOBAL_VALUE_UINT; - - // uint_value.value.uints[0] = 0; - // add_global_with_value(_uint_id, attributes, add_name("TEXTURE_FORMAT_R8_UNORM"), uint_value); -} - -static global_id add_global(type_id type, attribute_list attributes, name_id name) { - uint32_t index = globals_size; - globals[index].name = name; - globals[index].type = type; - globals[index].var_index = 0; - globals[index].value.kind = GLOBAL_VALUE_NONE; - globals[index].attributes = attributes; - globals[index].usage = 0; - globals_size += 1; - return index; -} - -static global_id add_global_with_value(type_id type, attribute_list attributes, name_id name, global_value value) { - uint32_t index = globals_size; - globals[index].name = name; - globals[index].type = type; - globals[index].var_index = 0; - globals[index].value = value; - globals[index].attributes = attributes; - globals[index].usage = 0; - globals_size += 1; - return index; -} - -static global *find_global(name_id name) { - for (uint32_t i = 0; i < globals_size; ++i) { - if (globals[i].name == name) { - return &globals[i]; - } - } - - return NULL; -} - -static global *get_global(global_id id) { - if (id >= globals_size) { - return NULL; - } - - return &globals[id]; -} - -static void assign_global_var(global_id id, uint64_t var_index) { - debug_context context = {0}; - check(id < globals_size, context, "Encountered a global with a weird id"); - globals[id].var_index = var_index; -} - -void _names_init(void) { - char *new_names = realloc(names, names_size); - debug_context context = {0}; - check(new_names != NULL, context, "Could not allocate names"); - names = new_names; - names[0] = 0; // make NO_NAME a proper string - - sh_new_arena(names_hash); // TODO: Get rid of this by using indices internally in the hash-map so it can survive grow_names_if_needed -} - -static void grow_names_if_needed(size_t size) { - while (size >= names_size) { - names_size *= 2; - char *new_names = realloc(names, names_size); - debug_context context = {0}; - check(new_names != NULL, context, "Could not allocate names"); - names = new_names; - } -} - -static name_id add_name(char *name) { - ptrdiff_t old_id_index = shgeti(names_hash, name); - - if (old_id_index >= 0) { - return names_hash[old_id_index].value; - } - - size_t length = strlen(name); - - grow_names_if_needed(names_index + length + 1); - - name_id id = names_index; - - memcpy(&names[id], name, length); - names[id + length] = 0; - - names_index += length + 1; - - shput(names_hash, &names[id], id); - - return id; -} - -char *_get_name(name_id id) { - debug_context context = {0}; - check(id < names_index, context, "Encountered a weird name id"); - return &names[id]; -} - -static statement *statement_allocate(void) { - //// - // statement *s = (statement *)malloc(sizeof(statement)); - statement *s = &statements_buffer[statement_index]; - statement_index++; - //// - debug_context context = {0}; - check(s != NULL, context, "Could not allocate statement"); - return s; -} - -// static void statement_free(statement *statement) { -// free(statement); -// } - -static void statements_init(statements *statements) { - statements->size = 0; -} - -static void statements_add(statements *statements, statement *statement) { - statements->s[statements->size] = statement; - statements->size += 1; -} - -static expression *expression_allocate(void) { - //// - // expression *e = (expression *)malloc(sizeof(expression)); - expression *e = &experessions_buffer[expression_index]; - expression_index++; - //// - debug_context context = {0}; - check(e != NULL, context, "Could not allocate expression"); - init_type_ref(&e->type, NO_NAME); - return e; -} - -// static void expression_free(expression *expression) { -// free(expression); -// } - -static token current(state_t *state) { - token token = tokens_get(state->tokens, state->index); - return token; -} - -static void update_debug_context(state_t *state) { - state->context.column = current(state).column; - state->context.line = current(state).line; -} - -static void advance_state(state_t *state) { - state->index += 1; - update_debug_context(state); -} - -static void match_token(state_t *state, int token, const char *error_message) { - int current_token = current(state).kind; - if (current_token != token) { - error(state->context, error_message); - } -} - -static void match_token_identifier(state_t *state) { - if (current(state).kind != TOKEN_IDENTIFIER) { - error(state->context, "Expected an identifier"); - } -} - -void _parse(const char *filename, tokens *tokens) { - state_t state = {0}; - state.context.filename = filename; - state.tokens = tokens; - state.index = 0; - - for (;;) { - token token = current(&state); - if (token.kind == TOKEN_NONE) { - return; - } - else { - parse_definition(&state); - } - } -} - -static statement *parse_block(state_t *state, block *parent_block) { - match_token(state, TOKEN_LEFT_CURLY, "Expected an opening curly bracket"); - advance_state(state); - - statements statements; - statements_init(&statements); - - statement *new_block = statement_allocate(); - new_block->kind = STATEMENT_BLOCK; - new_block->block.parent = parent_block; - new_block->block.vars.size = 0; - - for (;;) { - switch (current(state).kind) { - case TOKEN_RIGHT_CURLY: { - advance_state(state); - new_block->block.statements = statements; - return new_block; - } - case TOKEN_NONE: { - update_debug_context(state); - error(state->context, "File ended before a block ended"); - return NULL; - } - default: - statements_add(&statements, parse_statement(state, &new_block->block)); + token = string_join(token, c); + pos++; + if (is_special) { break; } } + return token; } -// static void modifiers_init(modifiers_t *modifiers) { -// modifiers->size = 0; -// } - -// static void modifiers_add(modifiers_t *modifiers, modifier_t modifier) { -// modifiers->m[modifiers->size] = modifier; -// modifiers->size += 1; -// } - -static definition parse_definition(state_t *state) { - attribute_list attributes = {0}; - - switch (current(state).kind) { - case TOKEN_STRUCT: { - definition structy = parse_struct(state); - get_type(structy.type)->attributes = attributes; - return structy; - } - case TOKEN_FUNCTION: { - definition d = parse_function(state); - function *f = _get_function(d.function); - f->attributes = attributes; - return d; - } - case TOKEN_CONST: { - definition d = parse_const(state, attributes); - return d; - } - default: { - update_debug_context(state); - error(state->context, "Expected a struct, a function or a const"); - - definition d = {0}; - return d; - } +void alang_parse() { + pos = 0; + while (true) { + string_t *token = read_token(); + if (string_equals(token, "=") && string_equals(tokens->buffer[tokens->length - 1], "!")) { + tokens->buffer[tokens->length - 1] = "!="; + continue; + } + if (string_equals(token, "")) { + break; + } + any_array_push(tokens, token); } } -static type_ref parse_type_ref(state_t *state) { - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - token type_name = current(state); - advance_state(state); - - uint32_t array_size = 0; - if (current(state).kind == TOKEN_LEFT_SQUARE) { - advance_state(state); - if (current(state).kind == TOKEN_INT) { - array_size = (uint32_t)current(state).number; - if (array_size == 0) { - error(state->context, "Array size of 0 is not allowed"); - } - advance_state(state); - } - else { - array_size = UINT32_MAX; - } - match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); - advance_state(state); +void handle_tabs(string_t *token) { + if (string_equals(token, "{")) { + tabs++; } + else if (string_equals(token, "}")) { + tabs--; + } + if (is_for_loop) { + return; + } + if (new_line) { + for (i32 i = 0; i < tabs; ++i) { + out("\t"); + } + } +} - type_ref t; - init_type_ref(&t, type_name.identifier); - t.unresolved.array_size = array_size; +void handle_new_line(string_t *token) { + if (is_for_loop) { + return; + } + new_line = string_equals(token, ";") || string_equals(token, "{") || string_equals(token, "}"); + if (new_line) { + out("\n"); + } +} + +void handle_spaces(string_t *token) { + if (char_ptr_array_index_of(add_space_keywords, token) > -1) { + out(" "); + } +} + +string_t *get_token(i32 off) { + if (pos + off >= 0 && pos + off < tokens->length) { + return tokens->buffer[pos + off]; + } + return ""; +} + +string_t *get_token_after_piece() { + i32 _pos = pos; + skip_piece(0); + string_t *t = get_token(1); + pos = _pos; return t; } -static statement *parse_statement(state_t *state, block *parent_block) { - switch (current(state).kind) { - case TOKEN_IF: { - advance_state(state); - match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); - advance_state(state); +void skip_until(string_t *s) { + while (true) { + string_t *token = get_token(0); + if (string_equals(token, s)) { + break; + } + pos++; + } +} - expression *test = parse_expression(state); - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); +void skip_block() { + pos++; + i32 nested = 1; + while (true) { + string_t *token = get_token(0); + if (string_equals(token, "}")) { + nested--; + if (nested == 0) { + break; + } + } + else if (string_equals(token, "{")) { + nested++; + } + pos++; + } +} - statement *if_block = parse_statement(state, parent_block); - statement *s = statement_allocate(); - s->kind = STATEMENT_IF; - s->iffy.test = test; - s->iffy.if_block = if_block; +string_t *function_return_type() { + i32 _pos = pos; + skip_until("{"); + string_t *t = get_token(-1); + if (string_equals(t, "]")) { + pos -= 2; + } + else if (string_equals(t, ">")) { + pos -= 5; + } + pos -= 2; + string_t *result = string_equals(get_token(0), ":") ? read_type() : "void"; + pos = _pos; + return result; +} - s->iffy.else_size = 0; +string_t *join_type_name(string_t *type, string_t *name) { + any_map_set(value_types, name, type); + if (string_index_of(type, "(*NAME)(") > 0) { + return string_replace_all(type, "NAME", name); + } + return string_join(string_join(type, " "), name); +} - while (current(state).kind == TOKEN_ELSE) { - advance_state(state); - - if (current(state).kind == TOKEN_IF) { - advance_state(state); - match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); - advance_state(state); - - expression *test = parse_expression(state); - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); - - statement *if_block = parse_statement(state, parent_block); - - s->iffy.else_tests[s->iffy.else_size] = test; - s->iffy.else_blocks[s->iffy.else_size] = if_block; +string_t *read_type() { + pos++; + string_t *type = get_token(0); + if (string_equals(type, "(") && string_equals(get_token(1), "(")) { + pos++; + } + if (string_equals(get_token(1), ")") && string_equals(get_token(2), "[")) { + pos++; + } + if (string_equals(type, "(")) { + string_t *params = "("; + if (!string_equals(get_token(1), ")")) { + while (true) { + skip_until(":"); + params = string_join(params, read_type()); + pos++; + if (string_equals(get_token(0), ")")) { + break; + } + params = string_join(params, ","); + } + } + else { + params = string_join(params, "void"); + } + params = string_join(params, ")"); + skip_until("=>"); + string_t *ret = read_type(); + type = string_join(string_join(ret, "(*NAME)"), params); + } + if (string_equals(type, "color_t")) { + type = "i32"; + } + else if (string_equals(type, "string")) { + type = "string_t"; + } + if (string_equals(get_token(1), "[")) { + if (is_struct(type)) { + type = string_join(type, "_array_t"); + } + else if (string_equals(type, "bool")) { + type = "u8_array_t"; + } + else { + type = string_join(type, "_array_t"); + } + pos += 2; + } + if (is_struct(type) && char_ptr_array_index_of(pass_by_value_types, type) == -1) { + type = string_join(type, " *"); + } + if (string_equals(type, "map_t *") && string_equals(get_token(1), "<")) { + string_t *mv = get_token(4); + if (string_equals(mv, "f32")) { + type = string_join("f32_", type); + } + else if (char_ptr_array_index_of(basic_types, mv) > -1) { + string_t *mk = get_token(2); + if (string_equals(mk, "i32")) { + type = string_join("i32_i", type); } else { - statement *else_block = parse_statement(state, parent_block); - s->iffy.else_tests[s->iffy.else_size] = NULL; - s->iffy.else_blocks[s->iffy.else_size] = else_block; + type = string_join("i32_", type); } - - s->iffy.else_size += 1; - assert(s->iffy.else_size < 64); } + else { + string_t *mk = get_token(2); + if (string_equals(mk, "i32")) { + type = string_join("any_i", type); + } + else { + type = string_join("any_", type); + } + } + skip_until(">"); + } + return type; +} +string_t *enum_access(string_t *s) { + if (string_index_of(s, "_t.") > -1) { + for (i32 i = 0; i < enums->length; ++i) { + string_t *e = enums->buffer[i]; + if (string_index_of(s, e) > -1) { + s = string_copy(string_replace_all(s, "_t.", "_")); + s = string_copy(to_upper_case(s)); + break; + } + } + } + return s; +} + +string_t *struct_access(string_t *s) { + i32 dot = string_index_of(s, "."); + if (dot == -1) { return s; } - case TOKEN_WHILE: { - advance_state(state); - match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); - advance_state(state); - - expression *test = parse_expression(state); - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); - - statement *while_block = parse_statement(state, parent_block); - - statement *s = statement_allocate(); - s->kind = STATEMENT_WHILE; - s->whiley.test = test; - s->whiley.while_block = while_block; - + if (is_numeric(char_code_at(s, dot + 1))) { return s; } - case TOKEN_DO: { - advance_state(state); - - statement *do_block = parse_statement(state, parent_block); - - statement *s = statement_allocate(); - s->kind = STATEMENT_DO_WHILE; - s->whiley.while_block = do_block; - - match_token(state, TOKEN_WHILE, "Expected \"while\""); - advance_state(state); - match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); - advance_state(state); - - expression *test = parse_expression(state); - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); - - s->whiley.test = test; - - match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); - advance_state(state); - + if (string_index_of(s, "\"") > -1) { return s; } - case TOKEN_FOR: { - statements outer_block_statements; - statements_init(&outer_block_statements); - - statement *outer_block = statement_allocate(); - outer_block->kind = STATEMENT_BLOCK; - outer_block->block.parent = parent_block; - outer_block->block.vars.size = 0; - outer_block->block.statements = outer_block_statements; - - advance_state(state); - - match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); - advance_state(state); - - statement *pre = parse_statement(state, &outer_block->block); - statements_add(&outer_block->block.statements, pre); - - expression *test = parse_expression(state); - match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); - advance_state(state); - - expression *post_expression = parse_expression(state); - - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); - - statement *inner_block = parse_statement(state, &outer_block->block); - - statement *post_statement = statement_allocate(); - post_statement->kind = STATEMENT_EXPRESSION; - post_statement->expression = post_expression; - - statements_add(&inner_block->block.statements, post_statement); - - statement *s = statement_allocate(); - s->kind = STATEMENT_WHILE; - s->whiley.test = test; - s->whiley.while_block = inner_block; - - statements_add(&outer_block->block.statements, s); - - return outer_block; + if (starts_with(s, "GC_ALLOC_INIT")) { + return s; } - case TOKEN_LEFT_CURLY: { - return parse_block(state, parent_block); - } - case TOKEN_VAR: { - advance_state(state); - - match_token_identifier(state); - token name = current(state); - advance_state(state); - - match_token(state, TOKEN_COLON, "Expected a colon"); - advance_state(state); - - type_ref type = parse_type_ref(state); - - expression *init = NULL; - - if (current(state).kind == TOKEN_OPERATOR) { - check(current(state).op == OPERATOR_ASSIGN, state->context, "Expected an assign"); - advance_state(state); - init = parse_expression(state); - } - - match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); - advance_state(state); - - statement *statement = statement_allocate(); - statement->kind = STATEMENT_LOCAL_VARIABLE; - statement->local_variable.var.name = name.identifier; - statement->local_variable.var.type = type; - statement->local_variable.var.variable_id = 0; - statement->local_variable.init = init; - return statement; - } - case TOKEN_RETURN: { - advance_state(state); - - expression *expr = parse_expression(state); - match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); - advance_state(state); - - statement *statement = statement_allocate(); - statement->kind = STATEMENT_RETURN_EXPRESSION; - statement->expression = expr; - return statement; - } - default: { - expression *expr = parse_expression(state); - match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); - advance_state(state); - - statement *statement = statement_allocate(); - statement->kind = STATEMENT_EXPRESSION; - statement->expression = expr; - return statement; - } - } -} - -static expression *parse_assign(state_t *state); - -static expression *parse_expression(state_t *state) { - return parse_assign(state); -} - -static expression *parse_logical(state_t *state); - -static expression *parse_assign(state_t *state) { - expression *expr = parse_logical(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_ASSIGN || op == OPERATOR_MINUS_ASSIGN || op == OPERATOR_PLUS_ASSIGN || op == OPERATOR_DIVIDE_ASSIGN || - op == OPERATOR_MULTIPLY_ASSIGN) { - advance_state(state); - expression *right = parse_logical(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_bitwise(state_t *state); - -static expression *parse_logical(state_t *state) { - expression *expr = parse_bitwise(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_OR || op == OPERATOR_AND) { - advance_state(state); - expression *right = parse_bitwise(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_equality(state_t *state); - -static expression *parse_bitwise(state_t *state) { - expression *expr = parse_equality(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_BITWISE_XOR || op == OPERATOR_BITWISE_OR || op == OPERATOR_BITWISE_AND) { - advance_state(state); - expression *right = parse_equality(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_comparison(state_t *state); - -static expression *parse_equality(state_t *state) { - expression *expr = parse_comparison(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_EQUALS || op == OPERATOR_NOT_EQUALS) { - advance_state(state); - expression *right = parse_comparison(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_shift(state_t *state); - -static expression *parse_comparison(state_t *state) { - expression *expr = parse_shift(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_GREATER || op == OPERATOR_GREATER_EQUAL || op == OPERATOR_LESS || op == OPERATOR_LESS_EQUAL) { - advance_state(state); - expression *right = parse_shift(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_addition(state_t *state); - -static expression *parse_shift(state_t *state) { - expression *expr = parse_addition(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_LEFT_SHIFT || op == OPERATOR_RIGHT_SHIFT) { - advance_state(state); - expression *right = parse_addition(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_multiplication(state_t *state); - -static expression *parse_addition(state_t *state) { - expression *expr = parse_multiplication(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_MINUS || op == OPERATOR_PLUS) { - advance_state(state); - expression *right = parse_multiplication(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_unary(state_t *state); - -static expression *parse_multiplication(state_t *state) { - expression *expr = parse_unary(state); - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_DIVIDE || op == OPERATOR_MULTIPLY || op == OPERATOR_MOD) { - advance_state(state); - expression *right = parse_unary(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_BINARY; - expression->binary.left = expr; - expression->binary.op = op; - expression->binary.right = right; - expr = expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return expr; -} - -static expression *parse_primary(state_t *state); - -static expression *parse_unary(state_t *state) { - bool done = false; - while (!done) { - if (current(state).kind == TOKEN_OPERATOR) { - operatorr op = current(state).op; - if (op == OPERATOR_NOT || op == OPERATOR_MINUS) { - advance_state(state); - expression *right = parse_unary(state); - expression *expression = expression_allocate(); - expression->kind = EXPRESSION_UNARY; - expression->unary.op = op; - expression->unary.right = right; - return expression; - } - else { - done = true; - } - } - else { - done = true; - } - } - return parse_primary(state); -} - -static expression *parse_member_or_element_access(state_t *state, expression *of) { - if (current(state).kind == TOKEN_DOT) { - advance_state(state); - - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - - token token = current(state); - - advance_state(state); - - expression *member = expression_allocate(); - member->kind = EXPRESSION_MEMBER; - member->member.of = of; - member->member.member_name = token.identifier; - - expression *sub = parse_member_or_element_access(state, member); - - return sub; - } - else if (current(state).kind == TOKEN_LEFT_SQUARE) { - advance_state(state); - - expression *index = parse_expression(state); - - match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); - - advance_state(state); - - expression *element = expression_allocate(); - element->kind = EXPRESSION_ELEMENT; - element->element.of = of; - element->element.element_index = index; - - expression *sub = parse_member_or_element_access(state, element); - - return sub; - } - - if (current(state).kind == TOKEN_LEFT_PAREN) { - error(state->context, "Function members not supported."); - } - - return of; -} - -static expression *parse_call(state_t *state, name_id func_name); - -static expression *parse_primary(state_t *state) { - expression *left = NULL; - - switch (current(state).kind) { - case TOKEN_BOOLEAN: { - bool value = current(state).boolean; - advance_state(state); - left = expression_allocate(); - left->kind = EXPRESSION_BOOLEAN; - left->boolean = value; - break; - } - case TOKEN_FLOAT: { - double value = current(state).number; - advance_state(state); - left = expression_allocate(); - left->kind = EXPRESSION_FLOAT; - left->number = value; - break; - } - case TOKEN_INT: { - double value = current(state).number; - advance_state(state); - left = expression_allocate(); - left->kind = EXPRESSION_INT; - left->number = value; - break; - } - /*case TOKEN_STRING: { - token token = current(state); - advance_state(state); - left = expression_allocate(); - left->kind = EXPRESSION_STRING; - left->string = add_name(token.string); - break; - }*/ - case TOKEN_IDENTIFIER: { - token token = current(state); - advance_state(state); - if (current(state).kind == TOKEN_LEFT_PAREN) { - left = parse_call(state, token.identifier); - } - else { - expression *var = expression_allocate(); - var->kind = EXPRESSION_VARIABLE; - var->variable = token.identifier; - left = var; - } - break; - } - case TOKEN_LEFT_PAREN: { - advance_state(state); - expression *expr = parse_expression(state); - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); - left = expression_allocate(); - left->kind = EXPRESSION_GROUPING; - left->grouping = expr; - break; - } - default: - error(state->context, "Unexpected token"); - return NULL; - } - - return parse_member_or_element_access(state, left); -} - -static expressions parse_parameters(state_t *state) { - expressions e; - e.size = 0; - - if (current(state).kind == TOKEN_RIGHT_PAREN) { - advance_state(state); - return e; - } - - for (;;) { - e.e[e.size] = parse_expression(state); - e.size += 1; - - if (current(state).kind == TOKEN_COMMA) { - advance_state(state); - } - else { - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); - return e; - } - } -} - -static expression *parse_call(state_t *state, name_id func_name) { - match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); - advance_state(state); - - expression *call = NULL; - call = expression_allocate(); - call->kind = EXPRESSION_CALL; - call->call.func_name = func_name; - call->call.parameters = parse_parameters(state); - - return parse_member_or_element_access(state, call); -} - -static definition parse_struct_inner(state_t *state, name_id name) { - match_token(state, TOKEN_LEFT_CURLY, "Expected an opening curly bracket"); - advance_state(state); - - token member_names[MAX_MEMBERS]; - type_ref type_refs[MAX_MEMBERS]; - token member_values[MAX_MEMBERS]; - size_t count = 0; - - while (current(state).kind != TOKEN_RIGHT_CURLY) { - debug_context context = {0}; - check(count < MAX_MEMBERS, context, "Out of members"); - - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - member_names[count] = current(state); - - advance_state(state); - - if (current(state).kind == TOKEN_COLON) { - advance_state(state); - type_refs[count] = parse_type_ref(state); - } - else { - type_ref t; - t.type = NO_TYPE; - t.unresolved.name = NO_NAME; - t.unresolved.array_size = 0; - type_refs[count] = t; - } - - if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_ASSIGN) { - advance_state(state); - if (current(state).kind == TOKEN_BOOLEAN || current(state).kind == TOKEN_FLOAT || current(state).kind == TOKEN_INT || - current(state).kind == TOKEN_IDENTIFIER) { - member_values[count] = current(state); - advance_state(state); - - if (current(state).kind == TOKEN_LEFT_PAREN) { - advance_state(state); - match_token(state, TOKEN_RIGHT_PAREN, "Expected a right paren"); - advance_state(state); + bool has_minus = starts_with(s, "-"); + string_t *base = substring(s, has_minus ? 1 : 0, dot); + string_t *type = any_map_get(value_types, base); + if (type != null) { + i32 dot_last = string_last_index_of(s, "."); + if (dot != dot_last) { + string_t_array_t *parts = string_split(s, "."); + for (i32 i = 1; i < parts->length - 1; ++i) { + any_map_t *struct_value_types = any_map_get(struct_types, type); + if (struct_value_types != null) { + type = string_copy(any_map_get(struct_value_types, parts->buffer[i])); + if (starts_with(type, "struct ") && ends_with(type, " *")) { + type = string_copy(substring(type, 0, string_length(type) - 2)); + type = string_join(substring(type, 7, string_length(type)), "_t *"); + } } } - else { - debug_context context = {0}; - error(context, "Unsupported assign in struct"); + if (!ends_with(type, " *")) { + string_t *first = string_replace_all(substring(s, 0, dot_last), ".", "->"); + string_t *last = substring(s, dot_last, string_length(s)); + return string_join(first, last); } } - else { - member_values[count].kind = TOKEN_NONE; - member_values[count].identifier = NO_NAME; + else if (!ends_with(type, " *")) { + return s; } - - match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); - - advance_state(state); - - ++count; } + return string_replace_all(s, ".", "->"); +} - advance_state(state); - - definition definition; - definition.kind = DEFINITION_STRUCT; - - definition.type = add_type(name); - - type *s = get_type(definition.type); - - for (size_t i = 0; i < count; ++i) { - member member; - member.name = member_names[i].identifier; - member.value = member_values[i]; - if (member.value.kind != TOKEN_NONE) { - if (member.value.kind == TOKEN_BOOLEAN) { - init_type_ref(&member.type, add_name("bool")); +string_t *struct_alloc(string_t *token, string_t *type) { + if ((string_equals(get_token(-1), "=") && string_equals(token, "{") && !string_equals(get_token(-3), "type")) || type != null) { + if (type == null) { + i32 i = string_equals(get_token(-3), ":") ? -4 : -2; + string_t *t = struct_access(get_token(i)); + type = string_copy(value_type(t)); + if (ends_with(type, " *")) { + type = string_copy(substring(type, 0, string_length(type) - 2)); } - else if (member.value.kind == TOKEN_FLOAT) { - init_type_ref(&member.type, add_name("float")); + if (starts_with(type, "struct ")) { + type = string_join(substring(type, 7, string_length(type)), "_t"); } - else if (member.value.kind == TOKEN_INT) { - init_type_ref(&member.type, add_name("int")); + } + token = string_join(string_join("GC_ALLOC_INIT(", type), ", {"); + pos++; + i32 ternary = 0; + while (true) { + string_t *t = get_token(0); + if (string_equals(t, "}")) { + break; } - else if (member.value.kind == TOKEN_IDENTIFIER) { - global *g = find_global(member.value.identifier); - if (g != NULL && g->name != NO_NAME) { - init_type_ref(&member.type, get_type(g->type)->name); + string_t *tc = get_token_c(); + tc = string_copy(string_ops(tc)); + if (string_equals(get_token(1), ":") && !ternary) { + tc = string_join(".", tc); + } + if (string_equals(t, ":")) { + if (ternary > 0) { + ternary--; } else { - init_type_ref(&member.type, add_name("fun")); + tc = "="; } } - else { - debug_context context = {0}; - error(context, "Unsupported value in struct"); + else if (string_equals(t, "?")) { + ternary++; } + else if (string_equals(t, "[") && string_equals(get_token(-1), ":")) { + string_t *member = get_token(-2); + any_map_t *types = any_map_get(struct_types, string_join(type, " *")); + string_t *content_type = any_map_get(types, member); + content_type = string_copy(substring(content_type, 7, string_length(content_type) - 8)); + tc = string_copy(array_create("[", "", content_type)); + } + token = string_join(token, tc); + pos++; } - else { - member.type = type_refs[i]; + if (string_equals(get_token(-1), "{")) { + token = string_join(token, "0"); } - - s->members.m[i] = member; + token = string_join(token, get_token(0)); + token = string_join(token, ")"); + tabs--; } - s->members.size = count; - - return definition; -} - -static definition parse_struct(state_t *state) { - advance_state(state); - - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - token name = current(state); - advance_state(state); - - return parse_struct_inner(state, name.identifier); -} - -static definition parse_function(state_t *state) { - advance_state(state); - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - - token name = current(state); - advance_state(state); - match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); - advance_state(state); - - uint8_t parameters_size = 0; - name_id param_names[256] = {0}; - type_ref param_types[256] = {0}; - name_id param_attributes[256] = {0}; - - while (current(state).kind != TOKEN_RIGHT_PAREN) { - if (current(state).kind == TOKEN_HASH) { - advance_state(state); - match_token(state, TOKEN_LEFT_SQUARE, "Expected an opening square bracket"); - advance_state(state); - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - token attribute_name = current(state); - param_attributes[parameters_size] = attribute_name.identifier; - advance_state(state); - match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); - advance_state(state); - } - - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - param_names[parameters_size] = current(state).identifier; - advance_state(state); - match_token(state, TOKEN_COLON, "Expected a colon"); - advance_state(state); - param_types[parameters_size] = parse_type_ref(state); - if (current(state).kind == TOKEN_COMMA) { - advance_state(state); - } - parameters_size += 1; - } - - match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); - advance_state(state); - match_token(state, TOKEN_COLON, "Expected a colon"); - advance_state(state); - - type_ref return_type = parse_type_ref(state); - - statement *block = parse_block(state, NULL); - - definition d; - d.kind = DEFINITION_FUNCTION; - d.function = add_function(name.identifier); - function *f = _get_function(d.function); - f->return_type = return_type; - f->parameters_size = parameters_size; - for (uint8_t parameter_index = 0; parameter_index < parameters_size; ++parameter_index) { - f->parameter_names[parameter_index] = param_names[parameter_index]; - f->parameter_types[parameter_index] = param_types[parameter_index]; - f->parameter_attributes[parameter_index] = param_attributes[parameter_index]; - } - f->block = block; - - return d; -} - -static definition parse_const(state_t *state, attribute_list attributes) { - advance_state(state); - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - - token name = current(state); - advance_state(state); - match_token(state, TOKEN_COLON, "Expected a colon"); - advance_state(state); - - name_id type_name = NO_NAME; - type_id type = NO_TYPE; - name_id format_name = NO_NAME; - - if (current(state).kind == TOKEN_LEFT_CURLY) { - type = parse_struct_inner(state, NO_NAME).type; - } - else { - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - type_name = current(state).identifier; - advance_state(state); - } - - bool array = false; - uint32_t array_size = UINT32_MAX; - - if (current(state).kind == TOKEN_LEFT_SQUARE) { - array = true; - advance_state(state); - - if (current(state).kind == TOKEN_INT) { - array_size = (uint32_t)current(state).number; - advance_state(state); - } - - match_token(state, TOKEN_RIGHT_SQUARE, "Expected a right square bracket"); - advance_state(state); - } - - expression *value = NULL; - if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_ASSIGN) { - advance_state(state); - value = parse_expression(state); - } - - if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_LESS) { - advance_state(state); - match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); - format_name = current(state).identifier; - advance_state(state); - - if (current(state).kind == TOKEN_LEFT_PAREN) { - advance_state(state); - match_token(state, TOKEN_RIGHT_PAREN, "Expected a right paren"); - advance_state(state); - } - - if (current(state).kind != TOKEN_OPERATOR || current(state).op != OPERATOR_GREATER) { - error(state->context, "Expected a greater than"); - } - advance_state(state); - } - - match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); - advance_state(state); - - definition d = {0}; - - if (type_name == NO_NAME) { - debug_context context = {0}; - check(type != NO_TYPE, context, "Const has no type"); - d.kind = DEFINITION_CONST_CUSTOM; - d.global = add_global(type, attributes, name.identifier); - } - else if (type_name == add_name("float")) { - debug_context context = {0}; - check(value != NULL, context, "const float requires an initialization value"); - check(value->kind == EXPRESSION_FLOAT || value->kind == EXPRESSION_INT, context, "const float requires a number"); - - global_value float_value; - float_value.kind = GLOBAL_VALUE_FLOAT; - - float_value.value.floats[0] = (float)value->number; - - d.kind = DEFINITION_CONST_BASIC; - d.global = add_global_with_value(_float_id, attributes, name.identifier, float_value); - } - else { - debug_context context = {0}; - error(context, "Unsupported global"); - } - - return d; -} - -static token tokens_get(tokens *tokens, size_t index) { - debug_context context = {0}; - check(tokens->current_size > index, context, "Token index out of bounds"); - return tokens->t[index]; -} - -static bool is_num(char ch, char chch) { - return (ch >= '0' && ch <= '9') || (ch == '-' && chch >= '0' && chch <= '9'); -} - -static bool is_op(char ch) { - return ch == '&' || ch == '|' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=' || ch == '!' || ch == '<' || ch == '>' || ch == '%' || - ch == '^'; -} - -static bool is_whitespace(char ch) { - return ch == ' ' || (ch >= 9 && ch <= 13); -} - -static void tokenizer_state_init(debug_context *context, tokenizer_state *state, const char *source) { - state->line = state->column = 0; - state->iterator = source; - state->next = *state->iterator; - if (*state->iterator != 0) { - state->iterator += 1; - } - state->next_next = *state->iterator; - state->line_end = false; - - context->column = 0; - context->line = 0; -} - -static void tokenizer_state_advance(debug_context *context, tokenizer_state *state) { - state->next = state->next_next; - if (*state->iterator != 0) { - state->iterator += 1; - } - state->next_next = *state->iterator; - - if (state->line_end) { - state->line_end = false; - state->line += 1; - state->column = 0; - } - else { - state->column += 1; - } - - if (state->next == '\n') { - state->line_end = true; - } - - context->column = state->column; - context->line = state->line; -} - -static void tokenizer_buffer_init(tokenizer_buffer *buffer) { - buffer->max_size = 1024 * 1024; - buffer->buf = (char *)malloc(buffer->max_size); - buffer->current_size = 0; - buffer->column = buffer->line = 0; -} - -static void tokenizer_buffer_reset(tokenizer_buffer *buffer, tokenizer_state *state) { - buffer->current_size = 0; - buffer->column = state->column; - buffer->line = state->line; -} - -static void tokenizer_buffer_add(tokenizer_buffer *buffer, char ch) { - debug_context context = {0}; - check(buffer->current_size < buffer->max_size, context, "Token buffer is too small"); - buffer->buf[buffer->current_size] = ch; - buffer->current_size += 1; -} - -static bool tokenizer_buffer_equals(tokenizer_buffer *buffer, const char *str) { - buffer->buf[buffer->current_size] = 0; - return strcmp(buffer->buf, str) == 0; -} - -static name_id tokenizer_buffer_to_name(tokenizer_buffer *buffer) { - debug_context context = {0}; - check(buffer->current_size < buffer->max_size, context, "Token buffer is too small"); - buffer->buf[buffer->current_size] = 0; - buffer->current_size += 1; - return add_name(buffer->buf); -} - -static double tokenizer_buffer_parse_number(tokenizer_buffer *buffer) { - buffer->buf[buffer->current_size] = 0; - return strtod(buffer->buf, NULL); -} - -static token token_create(int kind, tokenizer_state *state) { - token token; - token.kind = kind; - token.column = state->column; - token.line = state->line; return token; } -static void tokens_init(tokens *tokens) { - tokens->max_size = 1024 * 1024; - tokens->t = malloc(tokens->max_size * sizeof(token)); - tokens->current_size = 0; +string_t *array_type(string_t *name) { + string_t *type = value_type(name); + if (type == null) { + return "any"; + } + if (starts_with(type, "struct ")) { + type = string_join(substring(type, 7, string_length(type) - 2), "_t *"); + } + type = string_copy(strip(type, 10)); + if (char_ptr_array_index_of(basic_types, type) > -1) { + return type; + } + return "any"; } -static void tokens_add(tokens *tokens, token token) { - tokens->t[tokens->current_size] = token; - tokens->current_size += 1; - debug_context context = {0}; - check(tokens->current_size <= tokens->max_size, context, "Out of tokens"); -} - -static void tokens_add_identifier(tokenizer_state *state, tokens *tokens, tokenizer_buffer *buffer) { - token token; - - if (tokenizer_buffer_equals(buffer, "true")) { - token = token_create(TOKEN_BOOLEAN, state); - token.boolean = true; - } - else if (tokenizer_buffer_equals(buffer, "false")) { - token = token_create(TOKEN_BOOLEAN, state); - token.boolean = false; - } - else if (tokenizer_buffer_equals(buffer, "if")) { - token = token_create(TOKEN_IF, state); - } - else if (tokenizer_buffer_equals(buffer, "else")) { - token = token_create(TOKEN_ELSE, state); - } - else if (tokenizer_buffer_equals(buffer, "while")) { - token = token_create(TOKEN_WHILE, state); - } - else if (tokenizer_buffer_equals(buffer, "do")) { - token = token_create(TOKEN_DO, state); - } - else if (tokenizer_buffer_equals(buffer, "for")) { - token = token_create(TOKEN_FOR, state); - } - else if (tokenizer_buffer_equals(buffer, "in")) { - token = token_create(TOKEN_IN, state); - } - else if (tokenizer_buffer_equals(buffer, "struct")) { - token = token_create(TOKEN_STRUCT, state); - } - else if (tokenizer_buffer_equals(buffer, "fun")) { - token = token_create(TOKEN_FUNCTION, state); - } - else if (tokenizer_buffer_equals(buffer, "var")) { - token = token_create(TOKEN_VAR, state); - } - else if (tokenizer_buffer_equals(buffer, "const")) { - token = token_create(TOKEN_CONST, state); - } - else if (tokenizer_buffer_equals(buffer, "return")) { - token = token_create(TOKEN_RETURN, state); - } - else { - token = token_create(TOKEN_IDENTIFIER, state); - token.identifier = tokenizer_buffer_to_name(buffer); - } - - token.column = buffer->column; - token.line = buffer->line; - tokens_add(tokens, token); -} - -tokens _tokenize(const char *filename, const char *source) { - mode mode = MODE_SELECT; - bool number_has_dot = false; - - tokens tokens; - tokens_init(&tokens); - - debug_context context = {0}; - context.filename = filename; - - tokenizer_state state; - tokenizer_state_init(&context, &state, source); - - tokenizer_buffer buffer; - tokenizer_buffer_init(&buffer); - - for (;;) { - if (state.next == 0) { - switch (mode) { - case MODE_IDENTIFIER: - tokens_add_identifier(&state, &tokens, &buffer); - break; - case MODE_NUMBER: { - token token = token_create(number_has_dot ? TOKEN_FLOAT : TOKEN_INT, &state); - token.number = tokenizer_buffer_parse_number(&buffer); - tokens_add(&tokens, token); - break; - } - case MODE_SELECT: - case MODE_LINE_COMMENT: - break; - // case MODE_STRING: - // error("Unclosed string", state.column, state.line); - case MODE_OPERATOR: - error(context, "File ends with an operator"); - case MODE_COMMENT: - error(context, "Unclosed comment"); - } - - tokens_add(&tokens, token_create(TOKEN_NONE, &state)); - //// - free(buffer.buf); - //// - return tokens; - } - else { - char ch = (char)state.next; - switch (mode) { - case MODE_SELECT: { - if (ch == '/') { - if (state.next_next >= 0) { - char chch = state.next_next; - switch (chch) { - case '/': - mode = MODE_LINE_COMMENT; - break; - case '*': - mode = MODE_COMMENT; - break; - default: - tokenizer_buffer_reset(&buffer, &state); - tokenizer_buffer_add(&buffer, ch); - mode = MODE_OPERATOR; - } - } - } - else if (is_num(ch, state.next_next)) { - mode = MODE_NUMBER; - number_has_dot = false; - tokenizer_buffer_reset(&buffer, &state); - tokenizer_buffer_add(&buffer, ch); - } - else if (is_op(ch)) { - mode = MODE_OPERATOR; - tokenizer_buffer_reset(&buffer, &state); - tokenizer_buffer_add(&buffer, ch); - } - else if (is_whitespace(ch)) { - } - else if (ch == '(') { - tokens_add(&tokens, token_create(TOKEN_LEFT_PAREN, &state)); - } - else if (ch == ')') { - tokens_add(&tokens, token_create(TOKEN_RIGHT_PAREN, &state)); - } - else if (ch == '{') { - tokens_add(&tokens, token_create(TOKEN_LEFT_CURLY, &state)); - } - else if (ch == '}') { - tokens_add(&tokens, token_create(TOKEN_RIGHT_CURLY, &state)); - } - else if (ch == '#') { - tokens_add(&tokens, token_create(TOKEN_HASH, &state)); - } - else if (ch == '[') { - tokens_add(&tokens, token_create(TOKEN_LEFT_SQUARE, &state)); - } - else if (ch == ']') { - tokens_add(&tokens, token_create(TOKEN_RIGHT_SQUARE, &state)); - } - else if (ch == ';') { - tokens_add(&tokens, token_create(TOKEN_SEMICOLON, &state)); - } - else if (ch == '.') { - tokens_add(&tokens, token_create(TOKEN_DOT, &state)); - } - else if (ch == ':') { - tokens_add(&tokens, token_create(TOKEN_COLON, &state)); - } - else if (ch == ',') { - tokens_add(&tokens, token_create(TOKEN_COMMA, &state)); - } - else if (ch == '"' || ch == '\'') { - // mode = MODE_STRING; - // tokenizer_buffer_reset(&buffer, &state); - error(context, "Strings are not supported"); - } - else { - mode = MODE_IDENTIFIER; - tokenizer_buffer_reset(&buffer, &state); - tokenizer_buffer_add(&buffer, ch); - } - tokenizer_state_advance(&context, &state); - break; - } - case MODE_LINE_COMMENT: { - if (ch == '\n') { - mode = MODE_SELECT; - } - tokenizer_state_advance(&context, &state); - break; - } - case MODE_COMMENT: { - if (ch == '*') { - if (state.next_next >= 0) { - char chch = (char)state.next_next; - if (chch == '/') { - mode = MODE_SELECT; - tokenizer_state_advance(&context, &state); - } - } - } - tokenizer_state_advance(&context, &state); - break; - } - case MODE_NUMBER: { - if (is_num(ch, 0) || ch == '.') { - if (ch == '.') { - number_has_dot = true; - } - tokenizer_buffer_add(&buffer, ch); - tokenizer_state_advance(&context, &state); - } - else { - token token = token_create(number_has_dot ? TOKEN_FLOAT : TOKEN_INT, &state); - token.number = tokenizer_buffer_parse_number(&buffer); - tokens_add(&tokens, token); - mode = MODE_SELECT; - } - break; - } - case MODE_OPERATOR: { - char long_op[3]; - long_op[0] = 0; - if (buffer.current_size == 1) { - long_op[0] = buffer.buf[0]; - long_op[1] = ch; - long_op[2] = 0; - } - - if (strcmp(long_op, "==") == 0 || strcmp(long_op, "!=") == 0 || strcmp(long_op, "<=") == 0 || strcmp(long_op, ">=") == 0 || - strcmp(long_op, "||") == 0 || strcmp(long_op, "&&") == 0 || strcmp(long_op, "->") == 0 || strcmp(long_op, "-=") == 0 || - strcmp(long_op, "+=") == 0 || strcmp(long_op, "/=") == 0 || strcmp(long_op, "*=") == 0 || strcmp(long_op, "<<") == 0 || - strcmp(long_op, ">>") == 0) { - tokenizer_buffer_add(&buffer, ch); - tokenizer_state_advance(&context, &state); - } - - if (tokenizer_buffer_equals(&buffer, "==")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_EQUALS; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "!=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_NOT_EQUALS; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, ">")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_GREATER; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, ">=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_GREATER_EQUAL; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "<")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_LESS; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "<=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_LESS_EQUAL; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "-=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_MINUS_ASSIGN; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "+=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_PLUS_ASSIGN; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "/=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_DIVIDE_ASSIGN; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "*=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_MULTIPLY_ASSIGN; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "-")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_MINUS; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "+")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_PLUS; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "/")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_DIVIDE; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "*")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_MULTIPLY; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "!")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_NOT; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "||")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_OR; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "^")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_BITWISE_XOR; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "&")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_BITWISE_AND; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "|")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_BITWISE_OR; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "<<")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_LEFT_SHIFT; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, ">>")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_RIGHT_SHIFT; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "&&")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_AND; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "%")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_MOD; - tokens_add(&tokens, token); - } - else if (tokenizer_buffer_equals(&buffer, "=")) { - token token = token_create(TOKEN_OPERATOR, &state); - token.op = OPERATOR_ASSIGN; - tokens_add(&tokens, token); - } - else { - error(context, "Weird operator"); - } - - mode = MODE_SELECT; - break; - } - /*case MODE_STRING: { - if (ch == '"' || ch == '\'') { - token token = token_create(TOKEN_STRING, &state); - tokenizer_buffer_copy_to_string(&buffer, token.string); - token.column = buffer.column; - token.line = buffer.line; - tokens_add(&tokens, token); - - tokenizer_state_advance(&state); - mode = MODE_SELECT; - } - else { - tokenizer_buffer_add(&buffer, ch); - tokenizer_state_advance(&state); - } - break; - }*/ - case MODE_IDENTIFIER: { - if (is_whitespace(ch) || is_op(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '"' || ch == '\'' || - ch == ';' || ch == '.' || ch == ',' || ch == ':') { - tokens_add_identifier(&state, &tokens, &buffer); - mode = MODE_SELECT; - } - else { - tokenizer_buffer_add(&buffer, ch); - tokenizer_state_advance(&context, &state); - } - break; - } - } - } - } -} - -static type_ref find_local_var_type(block *b, name_id name) { - if (b == NULL) { - type_ref t; - init_type_ref(&t, NO_NAME); - return t; - } - - for (size_t i = 0; i < b->vars.size; ++i) { - if (b->vars.v[i].name == name) { - debug_context context = {0}; - check(b->vars.v[i].type.type != NO_TYPE, context, "Local var has no type"); - return b->vars.v[i].type; - } - } - - return find_local_var_type(b->parent, name); -} - -static void resolve_types_in_element(statement *parent_block, expression *element) { - resolve_types_in_expression(parent_block, element->element.of); - resolve_types_in_expression(parent_block, element->element.element_index); - - type_id of_type = element->element.of->type.type; - - assert(of_type != NO_TYPE); - - type *of = get_type(of_type); - - if (of->array_size > 0) { - element->type.type = of->base; - } - else { - debug_context context = {0}; - error(context, "Indexed non-array %s", _get_name(of->name)); - } -} - -static void resolve_types_in_member(statement *parent_block, expression *member) { - resolve_types_in_expression(parent_block, member->member.of); - - type_id of_type = member->member.of->type.type; - name_id member_name = member->member.member_name; - - assert(of_type != NO_TYPE); - - type *of_struct = get_type(of_type); - - for (size_t i = 0; i < of_struct->members.size; ++i) { - if (of_struct->members.m[i].name == member_name) { - member->type = of_struct->members.m[i].type; - return; - } - } - - debug_context context = {0}; - error(context, "Member %s not found", _get_name(member_name)); -} - -static bool types_compatible(type_id left, type_id right) { - if (left == right) { - return true; - } - if ((left == _int_id && right == _float_id) || (left == _float_id && right == _int_id)) { - return true; - } - if ((left == _uint_id && right == _float_id) || (left == _float_id && right == _uint_id)) { - return true; - } - if ((left == _uint_id && right == _int_id) || (left == _int_id && right == _uint_id)) { - return true; - } - return false; -} - -static type_ref upgrade_type(type_ref left_type, type_ref right_type) { - type_id left = left_type.type; - type_id right = right_type.type; - - if (left == right) { - return left_type; - } - - if (left == _int_id && right == _float_id) { - return right_type; - } - if (left == _float_id && right == _int_id) { - return left_type; - } - - if (left == _uint_id && right == _float_id) { - return right_type; - } - if (left == _float_id && right == _uint_id) { - return left_type; - } - - if (left == _uint_id && right == _int_id) { - return right_type; - } - if (left == _int_id && right == _uint_id) { - return left_type; - } - - kong_log(LOG_LEVEL_WARNING, "Suspicious type upgrade"); - return left_type; -} - -static void resolve_types_in_expression(statement *parent, expression *e) { - switch (e->kind) { - case EXPRESSION_BINARY: { - resolve_types_in_expression(parent, e->binary.left); - resolve_types_in_expression(parent, e->binary.right); - switch (e->binary.op) { - case OPERATOR_EQUALS: - case OPERATOR_NOT_EQUALS: - case OPERATOR_GREATER: - case OPERATOR_GREATER_EQUAL: - case OPERATOR_LESS: - case OPERATOR_LESS_EQUAL: - case OPERATOR_OR: - case OPERATOR_AND: { - e->type.type = _bool_id; - break; - } - case OPERATOR_BITWISE_XOR: - case OPERATOR_BITWISE_AND: - case OPERATOR_BITWISE_OR: - case OPERATOR_LEFT_SHIFT: - case OPERATOR_RIGHT_SHIFT: { - e->type = e->binary.left->type; - break; - } - case OPERATOR_MULTIPLY: - case OPERATOR_MULTIPLY_ASSIGN: { - type_id left_type = e->binary.left->type.type; - type_id right_type = e->binary.right->type.type; - if (types_compatible(left_type, right_type)) { - e->type = upgrade_type(e->binary.left->type, e->binary.right->type); - } - else { - debug_context context = {0}; - error(context, "Type mismatch %s vs %s", _get_name(get_type(left_type)->name), _get_name(get_type(right_type)->name)); +string_t_array_t *array_contents(string_t *type) { + string_t_array_t *contents = acontents->buffer[array_contents_depth]; + array_contents_depth++; + contents->length = 0; + string_t *content = ""; + while (true) { + pos++; + string_t *token = get_token(0); + if (string_equals(token, "]")) { + if (!string_equals(content, "")) { + any_array_push(contents, content); } break; } - case OPERATOR_MINUS: - case OPERATOR_PLUS: - case OPERATOR_DIVIDE: - case OPERATOR_MOD: { - type_id left_type = e->binary.left->type.type; - type_id right_type = e->binary.right->type.type; - if (!types_compatible(left_type, right_type)) { - debug_context context = {0}; - error(context, "Type mismatch %s vs %s", _get_name(get_type(left_type)->name), _get_name(get_type(right_type)->name)); - } - e->type = upgrade_type(e->binary.left->type, e->binary.right->type); - break; - } - case OPERATOR_ASSIGN: - case OPERATOR_DIVIDE_ASSIGN: - case OPERATOR_MINUS_ASSIGN: - case OPERATOR_PLUS_ASSIGN: { - type_id left_type = e->binary.left->type.type; - type_id right_type = e->binary.right->type.type; - if (!types_compatible(left_type, right_type)) { - debug_context context = {0}; - error(context, "Type mismatch %s vs %s", _get_name(get_type(left_type)->name), _get_name(get_type(right_type)->name)); - } - e->type = e->binary.left->type; - break; - } - case OPERATOR_NOT: { - debug_context context = {0}; - error(context, "Weird binary operator"); - break; - } - } - break; - } - case EXPRESSION_UNARY: { - resolve_types_in_expression(parent, e->unary.right); - switch (e->unary.op) { - case OPERATOR_MINUS: - case OPERATOR_PLUS: { - e->type = e->unary.right->type; - break; - } - case OPERATOR_NOT: { - e->type.type = _bool_id; - break; - } - case OPERATOR_EQUALS: - case OPERATOR_NOT_EQUALS: - case OPERATOR_GREATER: - case OPERATOR_GREATER_EQUAL: - case OPERATOR_LESS: - case OPERATOR_LESS_EQUAL: - case OPERATOR_DIVIDE: - case OPERATOR_MULTIPLY: - case OPERATOR_OR: - case OPERATOR_BITWISE_XOR: - case OPERATOR_BITWISE_AND: - case OPERATOR_BITWISE_OR: - case OPERATOR_LEFT_SHIFT: - case OPERATOR_RIGHT_SHIFT: - case OPERATOR_AND: - case OPERATOR_MOD: - case OPERATOR_ASSIGN: - default: { - debug_context context = {0}; - error(context, "Weird unary operator"); - break; - } - } - break; - } - case EXPRESSION_BOOLEAN: { - e->type.type = _bool_id; - break; - } - case EXPRESSION_FLOAT: { - e->type.type = _float_id; - break; - } - case EXPRESSION_INT: { - e->type.type = _int_id; - break; - } - case EXPRESSION_VARIABLE: { - global *g = find_global(e->variable); - if (g != NULL && g->type != NO_TYPE) { - e->type.type = g->type; - } - else { - type_ref type = find_local_var_type(&parent->block, e->variable); - if (type.type == NO_TYPE) { - type = find_local_var_type(&parent->block, e->variable); - debug_context context = {0}; - error(context, "Variable %s not found", _get_name(e->variable)); - } - e->type = type; - } - break; - } - case EXPRESSION_GROUPING: { - resolve_types_in_expression(parent, e->grouping); - e->type = e->grouping->type; - break; - } - case EXPRESSION_CALL: { - for (function_id i = 0; _get_function(i) != NULL; ++i) { - function *f = _get_function(i); - if (f->name == e->call.func_name) { - e->type = f->return_type; - break; - } - } - for (size_t i = 0; i < e->call.parameters.size; ++i) { - resolve_types_in_expression(parent, e->call.parameters.e[i]); - } - break; - } - case EXPRESSION_MEMBER: { - resolve_types_in_member(parent, e); - break; - } - case EXPRESSION_ELEMENT: { - resolve_types_in_element(parent, e); - break; - } - } - - if (e->type.type == NO_TYPE) { - debug_context context = {0}; - // const char *n = _get_name(e->call.func_name); - error(context, "Could not resolve type"); - } -} - -static void resolve_types_in_block(statement *parent, statement *block) { - debug_context context = {0}; - check(block->kind == STATEMENT_BLOCK, context, "Malformed block"); - - for (size_t i = 0; i < block->block.statements.size; ++i) { - statement *s = block->block.statements.s[i]; - switch (s->kind) { - case STATEMENT_EXPRESSION: { - resolve_types_in_expression(block, s->expression); - break; - } - case STATEMENT_RETURN_EXPRESSION: { - resolve_types_in_expression(block, s->expression); - break; - } - case STATEMENT_IF: { - resolve_types_in_expression(block, s->iffy.test); - resolve_types_in_block(block, s->iffy.if_block); - for (uint16_t i = 0; i < s->iffy.else_size; ++i) { - if (s->iffy.else_tests[i] != NULL) { - resolve_types_in_expression(block, s->iffy.else_tests[i]); - } - resolve_types_in_block(block, s->iffy.else_blocks[i]); - } - break; - } - case STATEMENT_WHILE: - case STATEMENT_DO_WHILE: { - resolve_types_in_expression(block, s->whiley.test); - resolve_types_in_block(block, s->whiley.while_block); - break; - } - case STATEMENT_BLOCK: { - resolve_types_in_block(block, s); - break; - } - case STATEMENT_LOCAL_VARIABLE: { - name_id var_name = s->local_variable.var.name; - name_id var_type_name = s->local_variable.var.type.unresolved.name; - - if (s->local_variable.var.type.type == NO_TYPE && var_type_name != NO_NAME) { - s->local_variable.var.type.type = find_type_by_ref(&s->local_variable.var.type); - } - - if (s->local_variable.var.type.type == NO_TYPE) { - debug_context context = {0}; - error(context, "Could not find type %s for %s", _get_name(var_type_name), _get_name(var_name)); - } - - if (s->local_variable.init != NULL) { - resolve_types_in_expression(block, s->local_variable.init); - } - - block->block.vars.v[block->block.vars.size].name = var_name; - block->block.vars.v[block->block.vars.size].type = s->local_variable.var.type; - ++block->block.vars.size; - break; - } - } - } -} - -void _resolve_types(void) { - for (type_id i = 0; get_type(i) != NULL; ++i) { - type *s = get_type(i); - for (size_t j = 0; j < s->members.size; ++j) { - if (s->members.m[j].type.type == NO_TYPE) { - name_id name = s->members.m[j].type.unresolved.name; - s->members.m[j].type.type = find_type_by_name(name); - if (s->members.m[j].type.type == NO_TYPE) { - debug_context context = {0}; - error(context, "Could not find type %s in %s", _get_name(name), _get_name(s->name)); - } - } - } - } - - for (function_id i = 0; _get_function(i) != NULL; ++i) { - function *f = _get_function(i); - - for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { - if (f->parameter_types[parameter_index].type == NO_TYPE) { - name_id parameter_type_name = f->parameter_types[parameter_index].unresolved.name; - f->parameter_types[parameter_index].type = find_type_by_name(parameter_type_name); - if (f->parameter_types[parameter_index].type == NO_TYPE) { - debug_context context = {0}; - error(context, "Could not find type %s for %s", _get_name(parameter_type_name), _get_name(f->name)); - } - } - } - - if (f->return_type.type == NO_TYPE) { - f->return_type.type = find_type_by_ref(&f->return_type); - - if (f->return_type.type == NO_TYPE) { - error_no_context("Could not find type %s for %s", _get_name(f->return_type.unresolved.name), _get_name(f->name)); - } - } - } - - for (function_id i = 0; _get_function(i) != NULL; ++i) { - function *f = _get_function(i); - - if (f->block == NULL) { - // built in + if (string_equals(token, ",")) { + any_array_push(contents, content); + content = ""; continue; } - - for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { - f->block->block.vars.v[f->block->block.vars.size].name = f->parameter_names[parameter_index]; - f->block->block.vars.v[f->block->block.vars.size].type = f->parameter_types[parameter_index]; - f->block->block.vars.v[f->block->block.vars.size].variable_id = 0; - ++f->block->block.vars.size; + if (string_equals(token, "{")) { + token = string_copy(struct_alloc(token, type)); + tabs++; } - - resolve_types_in_block(NULL, f->block); - } -} - -static void init_type_ref(type_ref *t, name_id name) { - t->type = NO_TYPE; - t->unresolved.name = name; - t->unresolved.array_size = 0; -} - -void _types_init(void) { - type *new_types = realloc(types, types_size * sizeof(type)); - debug_context context = {0}; - check(new_types != NULL, context, "Could not allocate types"); - types = new_types; - next_type_index = 0; - - _void_id = add_type(add_name("void")); - get_type(_void_id)->built_in = true; - - _bool_id = add_type(add_name("bool")); - get_type(_bool_id)->built_in = true; - _float_id = add_type(add_name("float")); - get_type(_float_id)->built_in = true; - _int_id = add_type(add_name("int")); - get_type(_int_id)->built_in = true; - _uint_id = add_type(add_name("uint")); - get_type(_uint_id)->built_in = true; - - { - function_type_id = add_type(add_name("fun")); - get_type(function_type_id)->built_in = true; - } -} - -static void grow_types_if_needed(uint64_t size) { - while (size >= types_size) { - types_size *= 2; - type *new_types = realloc(types, types_size * sizeof(type)); - debug_context context = {0}; - check(new_types != NULL, context, "Could not allocate types"); - types = new_types; - } -} - -static bool types_equal(type *a, type *b) { - return a->name == b->name && a->attributes.attributes_count == 0 && b->attributes.attributes_count == 0 && a->members.size == 0 && b->members.size == 0 && - a->built_in == b->built_in && a->array_size == b->array_size && a->base == b->base; -} - -static type_id add_type(name_id name) { - grow_types_if_needed(next_type_index + 1); - - type_id s = next_type_index; - ++next_type_index; - - types[s].name = name; - types[s].attributes.attributes_count = 0; - types[s].members.size = 0; - types[s].built_in = false; - types[s].array_size = 0; - types[s].base = NO_TYPE; - - return s; -} - -static type_id add_full_type(type *t) { - for (type_id type_index = 0; type_index < next_type_index; ++type_index) { - if (types_equal(&types[type_index], t)) { - return type_index; - } - } - - grow_types_if_needed(next_type_index + 1); - - type_id s = next_type_index; - ++next_type_index; - - types[s] = *t; - - return s; -} - -static type_id find_type_by_name(name_id name) { - debug_context context = {0}; - check(name != NO_NAME, context, "Attempted to find a no-name"); - for (type_id i = 0; i < next_type_index; ++i) { - if (types[i].name == name) { - return i; - } - } - - return NO_TYPE; -} - -static type_id find_type_by_ref(type_ref *t) { - if (t->type != NO_TYPE) { - return t->type; - } - - debug_context context = {0}; - check(t->unresolved.name != NO_NAME, context, "Attempted to find a no-name"); - - type_id base_type_id = NO_TYPE; - - for (type_id i = 0; i < next_type_index; ++i) { - if (types[i].name == t->unresolved.name) { - if (types[i].array_size == t->unresolved.array_size) { - return i; + if (string_equals(get_token(1), "(")) { + while (true) { + pos++; + token = string_join(token, get_token(0)); + token = string_copy(fill_default_params(token)); + if (ends_with(token, ")")) { + break; + } } - base_type_id = i; + } + if (string_equals(token, "/")) { + token = "/(float)"; + } + token = string_copy(struct_access(token)); + token = string_copy(string_ops(token)); + content = string_join(content, token); + } + array_contents_depth--; + return contents; +} + +string_t *member_name(string_t *name) { + i32 i = string_last_index_of(name, "."); + if (i > -1) { + name = string_copy(substring(name, i + 1, string_length(name))); + } + return name; +} + +string_t *array_create(string_t *token, string_t *name, string_t *content_type) { + if ((string_equals(get_token(-1), "=") && string_equals(token, "[")) || content_type != null) { + if (string_equals(name, "]")) { + name = string_copy(get_token(-6)); + } + string_t *member = member_name(name); + string_t *type = array_type(member); + if (content_type == null) { + name = string_copy(struct_access(name)); + content_type = string_copy(value_type(name)); + if (content_type != null) { + content_type = string_copy(substring(content_type, 0, string_length(content_type) - 10)); + } + } + string_t_array_t *contents = array_contents(content_type); + token = string_join(string_join(string_join(type, "_array_create_from_raw(("), type), "[]){"); + for (i32 i = 0; i < contents->length; ++i) { + string_t *e = contents->buffer[i]; + token = string_join(token, string_join(e, ",")); + } + i32 len = contents->length; + token = string_join(token, string_join(string_join("},", i32_to_string(len)), ")")); + } + return token; +} + +string_t *array_access(string_t *token) { + if (string_equals(token, "[") && !string_equals(get_token(-1), "=")) { + return "->buffer["; + } + return token; +} + +bool is_struct(string_t *type) { + return ends_with(type, "_t") && char_ptr_array_index_of(enums, type) == -1; +} + +string_t *strip(string_t *name, i32 len) { + return substring(name, 0, string_length(name) - len); +} + +string_t *strip_optional(string_t *name) { + if (ends_with(name, "?")) { + return strip(name, 1); + } + return name; +} + +i32 param_pos() { + return param_pos_stack->buffer[param_pos_stack->length - 1]; +} + +void param_pos_add() { + param_pos_stack->buffer[param_pos_stack->length - 1]++; +} + +string_t *fn_call() { + return fn_call_stack->buffer[fn_call_stack->length - 1]; +} + +string_t *fill_fn_params(string_t *token) { + if (string_equals(token, "(")) { + any_array_push(fn_call_stack, get_token(-1)); + i32_array_push(param_pos_stack, 0); + } + else if (string_equals(token, ",")) { + param_pos_add(); + } + else if (string_equals(token, ")")) { + if (!string_equals(get_token(-1), "(")) { + param_pos_add(); + } + string_t *res = ""; + while (true) { + i32 i = param_pos(); + string_t *fn = fn_call(); + string_t *param = any_map_get(fn_default_params, string_join(fn, i32_to_string(i))); + if (param == null) { + break; + } + if (i > 0) { + res = string_join(res, ","); + } + res = string_join(res, param); + param_pos_add(); + } + array_pop(fn_call_stack); + array_pop(param_pos_stack); + token = string_join(res, token); + } + return token; +} + +string_t *get_token_c() { + string_t *t = get_token(0); + t = string_copy(enum_access(t)); + t = string_copy(struct_access(t)); + t = string_copy(array_access(t)); + return t; +} + +string_t *fill_default_params(string_t *piece) { + if (string_equals(get_token(1), ")")) { + string_t *fn_name = ""; + i32 params = 0; + i32 i = 0; + i32 nested = 1; + while (true) { + string_t *ti = get_token(i); + if (string_equals(ti, ")")) { + nested++; + } + else if (string_equals(ti, "(")) { + if (string_equals(get_token(i - 1), ":")) { + return piece; + } + nested--; + if (nested == 0) { + fn_name = string_copy(get_token(i - 1)); + if (!string_equals(get_token(i + 1), ")")) { + params++; + } + break; + } + } + else if (string_equals(ti, ",")) { + params++; + } + i--; + } + while (true) { + string_t *param = any_map_get(fn_default_params, string_join(fn_name, i32_to_string(params))); + if (param == null) { + break; + } + if (params > 0) { + piece = string_join(piece, ","); + } + piece = string_join(piece, param); + params++; } } - - if (base_type_id != NO_TYPE) { - type_id new_type_id = add_type(t->unresolved.name); - type *new_type = get_type(new_type_id); - new_type->array_size = t->unresolved.array_size; - - type *base_type = get_type(base_type_id); - new_type->base = base_type_id; - new_type->built_in = base_type->built_in; - - return new_type_id; - } - - return NO_TYPE; + return piece; } -static type *get_type(type_id s) { - if (s >= next_type_index) { - return NULL; +void skip_piece(i32 nested) { + string_t *t1 = get_token(1); + if (string_equals(t1, "(") || string_equals(t1, "[")) { + nested++; + pos++; + skip_piece(nested); + return; + } + if (string_equals(t1, ")") || string_equals(t1, "]")) { + nested--; + if (nested < 0) { + return; + } + pos++; + skip_piece(nested); + return; + } + if (nested > 0) { + pos++; + skip_piece(nested); + return; + } + if (starts_with(t1, ".")) { + pos++; + skip_piece(0); + return; } - return &types[s]; +} + +string_t *read_piece(i32 nested) { + string_t *piece = get_token_c(); + piece = string_copy(string_len(piece)); + piece = string_copy(map_ops(piece)); + string_t *t1 = get_token(1); + if (string_equals(t1, "(") || string_equals(t1, "[")) { + nested++; + pos++; + return string_join(piece, read_piece(nested)); + } + if (string_equals(t1, ")") || string_equals(t1, "]")) { + nested--; + if (nested < 0) { + return piece; + } + piece = string_copy(fill_default_params(piece)); + pos++; + return string_join(piece, read_piece(nested)); + } + if (nested > 0) { + pos++; + return string_join(piece, read_piece(nested)); + } + if (starts_with(t1, ".")) { + pos++; + return string_join(piece, read_piece(0)); + } + return piece; +} + +string_t *string_len(string_t *token) { + if (!ends_with(token, "->length")) { + return token; + } + string_t *base = strip(token, 8); + string_t *type = value_type(base); + if (string_equals(type, "string_t *") || string_equals(type, "struct string *")) { + token = string_join(string_join("string_length(", base), ")"); + } + return token; +} + +string_t *value_type(string_t *value) { + i32 arrow = string_index_of(value, "->"); + if (arrow > -1) { + string_t *base = substring(value, 0, arrow); + string_t *type = any_map_get(value_types, base); + string_t *member = substring(value, arrow + 2, string_length(value)); + any_map_t *struct_value_types = any_map_get(struct_types, type); + if (struct_value_types != null) { + return any_map_get(struct_value_types, member); + } + } + return any_map_get(value_types, value); +} + +void set_fn_param_types() { + pos++; + while (true) { + pos++; + string_t *t = get_token(0); + if (string_equals(t, ")")) { + break; + } + if (string_equals(t, ",")) { + continue; + } + pos++; + string_t *type = read_type(); + any_map_set(value_types, t, type); + if (string_equals(get_token(1), "=")) { + pos += 2; + } + } +} + +string_t *number_to_string(string_t *token) { + string_t *type = value_type(token); + if (string_equals(type, "i32")) { + return string_join(string_join("i32_to_string(", token), ")"); + } + if (string_equals(type, "f32")) { + return string_join(string_join("f32_to_string(", token), ")"); + } + return token; +} + +bool token_is_string(string_t *token) { + bool is_string = starts_with(token, "\"") || string_equals(value_type(token), "string_t *"); + if (!is_string) { + i32 _pos = pos; + skip_piece(0); + string_t *t1 = get_token(1); + if (string_equals(t1, "+") || string_equals(t1, "+=") || string_equals(t1, "==") || string_equals(t1, "!=")) { + string_t *t2 = get_token(2); + if (starts_with(t2, "\"") || string_equals(value_type(t2), "string_t *")) { + is_string = true; + } + } + pos = _pos; + } + if (is_string && string_equals(get_token(2), "null")) { + is_string = false; + } + return is_string; +} + +string_t *string_add(string_t *token) { + token = string_join(string_join("string_join(", token), ","); + pos++; + string_t *token_b = read_piece(0); + token_b = string_copy(number_to_string(token_b)); + token = string_join(token, token_b); + token = string_join(token, ")"); + return token; +} + +string_t *string_ops(string_t *token) { + if (!token_is_string(token)) { + return token; + } + bool first = true; + while (string_equals(get_token_after_piece(), "+")) { + if (first) { + first = false; + token = string_copy(read_piece(0)); + token = string_copy(number_to_string(token)); + } + pos++; + token = string_copy(string_add(token)); + } + string_t *p1 = get_token_after_piece(); + if (string_equals(p1, "+=")) { + token = string_copy(read_piece(0)); + pos++; + token = string_join(string_join(string_join(token, "=string_join("), token), ","); + pos++; + if (string_equals(get_token_after_piece(), "+")) { + string_t *token_b = read_piece(0); + token_b = string_copy(number_to_string(token_b)); + while (string_equals(get_token_after_piece(), "+")) { + pos++; + token_b = string_copy(string_add(token_b)); + } + token = string_join(token, token_b); + } + else { + token = string_join(token, read_piece(0)); + } + token = string_join(token, ")"); + } + else if (string_equals(p1, "=")) { + i32 _pos = pos; + string_t *t1 = read_piece(0); + pos++; + pos++; + string_t *t2 = read_piece(0); + if (string_equals(get_token(1), ";") && !starts_with(t2, "\"")) { + token = string_join(string_join(string_join(t1, "=string_copy("), t2), ")"); + } + else { + pos = _pos; + } + } + else if (string_equals(p1, "==")) { + token = string_copy(read_piece(0)); + pos++; + token = string_join(string_join("string_equals(", token), ","); + pos++; + token = string_join(token, read_piece(0)); + token = string_join(token, ")"); + } + else if (string_equals(p1, "!=")) { + token = string_copy(read_piece(0)); + pos++; + token = string_join(string_join("!string_equals(", token), ","); + pos++; + token = string_join(token, read_piece(0)); + token = string_join(token, ")"); + } + return token; +} + +string_t *array_ops(string_t *token) { + if (string_equals(token, "array_push")) { + string_t *value = get_token(2); + if (string_equals(get_token(3), "[")) { + string_t *t6 = get_token(6); + value = string_copy(substring(t6, 1, string_length(t6))); + } + if (string_last_index_of(value, ".") > -1) { + value = string_copy(substring(value, string_last_index_of(value, ".") + 1, string_length(value))); + } + string_t *type = array_type(value); + token = string_join(type, "_array_push"); + } + else if (string_equals(token, "array_remove")) { + string_t *value = get_token(2); + value = string_copy(struct_access(value)); + string_t *type = value_type(value); + if (type != null && starts_with(type, "struct ")) { + type = string_join(substring(type, 7, string_length(type) - 2), "_t *"); + } + if (string_equals(type, "i32_array_t *")) { + token = "i32_array_remove"; + } + else if (string_equals(type, "string_t_array_t *")) { + token = "char_ptr_array_remove"; + } + } + else if (string_equals(token, "array_index_of")) { + string_t *value = get_token(2); + value = string_copy(struct_access(value)); + string_t *type = value_type(value); + if (type != null && starts_with(type, "struct ")) { + type = string_join(substring(type, 7, string_length(type) - 2), "_t *"); + } + if (string_equals(type, "i32_array_t *")) { + token = "i32_array_index_of"; + } + else if (string_equals(type, "string_t_array_t *")) { + token = "char_ptr_array_index_of"; + } + else { + string_t *fn = any_map_get(fn_declarations, value); + if (fn != null && starts_with(fn, "string_t_array_t *")) { + token = "char_ptr_array_index_of"; + } + } + } + return token; +} + +string_t *map_ops(string_t *token) { + if (string_equals(token, "map_create")) { + string_t *t = value_type(get_token(-2)); + if (string_equals(t, "i32_map_t *")) { + token = "i32_map_create"; + } + else if (string_equals(t, "i32_imap_t *")) { + token = "i32_imap_create"; + } + else if (string_equals(t, "any_imap_t *")) { + token = "any_imap_create"; + } + else { + token = "any_map_create"; + } + } + else if (string_equals(token, "map_set")) { + string_t *t = value_type(get_token(2)); + if (string_equals(t, "i32_map_t *")) { + token = "i32_map_set"; + } + else if (string_equals(t, "i32_imap_t *")) { + token = "i32_imap_set"; + } + else if (string_equals(t, "any_imap_t *")) { + token = "any_imap_set"; + } + else { + token = "any_map_set"; + } + } + else if (string_equals(token, "map_get")) { + string_t *t = value_type(get_token(2)); + if (string_equals(t, "i32_map_t *")) { + token = "i32_map_get"; + } + else if (string_equals(t, "i32_imap_t *")) { + token = "i32_imap_get"; + } + else if (string_equals(t, "any_imap_t *")) { + token = "any_imap_get"; + } + else { + token = "any_map_get"; + } + } + else if (string_equals(token, "map_delete")) { + string_t *t = value_type(get_token(2)); + if (string_equals(t, "any_imap_t *")) { + token = "imap_delete"; + } + } + return token; +} + +string_t *_t_to_struct(string_t *type) { + if (ends_with(type, "_t *") && !string_equals(type, "string_t *")) { + string_t *type_short = strip(type, 4); + if (ends_with(type_short, "_array")) { + for (i32 i = 0; i < enums->length; ++i) { + string_t *e = enums->buffer[i]; + if (starts_with(type_short, e)) { + type_short = "i32_array"; + break; + } + } + } + type = string_join(string_join("struct ", type_short), " *"); + } + return type; +} + +void stream_write(string_t *token) { + fwrite(token, 1, string_length(token), fhandle); +} + +void string_write(string_t *token) { + strings->buffer[strings->length - 1] = string_join(strings->buffer[strings->length - 1], token); +} + +void null_write(string_t *token) { + return; +} + +void write_enums() { + for (pos = 0; pos < tokens->length; ++pos) { + string_t *token = get_token(0); + if (string_equals(token, "enum")) { + gc_unroot(out); + out = string_equals(get_token(-1), "declare") ? &null_write : &stream_write; + gc_root(out); + pos++; + string_t *enum_name = get_token(0); + any_array_push(enums, enum_name); + out("typedef enum{\n"); + pos++; + while (true) { + pos++; + token = string_copy(get_token(0)); + if (string_equals(token, "}")) { + out(string_join(string_join("}", enum_name), ";\n")); + break; + } + string_t *enum_base = strip(enum_name, 2); + enum_base = string_copy(to_upper_case(enum_base)); + out(string_join(string_join(string_join("\t", enum_base), "_"), token)); + pos++; + token = string_copy(get_token(0)); + if (string_equals(token, "=")) { + pos++; + token = string_copy(get_token(0)); + out(string_join("=", token)); + pos++; + } + out(",\n"); + } + out("\n"); + continue; + } + } + gc_unroot(out); + out = &stream_write; + gc_root(out); +} + +void write_types() { + for (pos = 0; pos < tokens->length; ++pos) { + string_t *token = get_token(0); + if (string_equals(token, "type")) { + gc_unroot(out); + out = string_equals(get_token(-1), "declare") ? &null_write : &stream_write; + gc_root(out); + pos++; + string_t *struct_name = get_token(0); + string_t *stuct_name_short = strip(struct_name, 2); + pos++; + token = string_copy(get_token(0)); + if (!string_equals(token, "=")) { + continue; + } + pos++; + token = string_copy(get_token(0)); + if (!string_equals(token, "{")) { + pos--; + string_t *type = read_type(); + type = string_copy(_t_to_struct(type)); + out(string_join(string_join(string_join(string_join("typedef ", type), " "), struct_name), ";\n\n")); + skip_until(";"); + continue; + } + out(string_join(string_join("typedef struct ", stuct_name_short), "{\n")); + any_map_t *struct_value_types = any_map_create(); + any_array_resize(struct_value_types->keys, 512 * 2); + any_array_resize(struct_value_types->values, 512 * 2); + any_map_set(struct_types, string_join(struct_name, " *"), struct_value_types); + while (true) { + pos++; + string_t *name = get_token(0); + if (string_equals(name, "}")) { + out(string_join(string_join("}", struct_name), ";\n")); + break; + } + name = string_copy(strip_optional(name)); + pos++; + string_t *type = read_type(); + type = string_copy(_t_to_struct(type)); + if (string_index_of(type, "(*NAME)") > -1) { + string_t *args_str = substring(type, string_index_of(type, ")(") + 2, string_last_index_of(type, ")")); + string_t_array_t *args = string_split(args_str, ","); + type = string_copy(substring(type, 0, string_index_of(type, "(*NAME)"))); + type = string_copy(_t_to_struct(type)); + type = string_join(type, "(*NAME)("); + for (i32 i = 0; i < args->length; ++i) { + string_t *arg = args->buffer[i]; + arg = string_copy(_t_to_struct(arg)); + if (i > 0) { + type = string_join(type, ","); + } + type = string_join(type, arg); + } + type = string_join(type, ")"); + } + skip_until(";"); + out(string_join(string_join("\t", join_type_name(type, name)), ";\n")); + any_map_set(struct_value_types, name, type); + } + out("\n"); + continue; + } + } + gc_unroot(out); + out = &stream_write; + gc_root(out); +} + +void write_array_types() { + any_map_t *array_structs = any_map_create(); + any_array_resize(array_structs->keys, 256 * 2); + any_array_resize(array_structs->values, 256 * 2); + for (pos = 0; pos < tokens->length; ++pos) { + string_t *token = get_token(0); + if (string_equals(get_token(1), "[")) { + string_t *type = token; + if (string_equals(type, "string")) { + type = "string_t"; + } + if (is_struct(type)) { + if (any_map_get(array_structs, type) == null) { + string_t *as = string_join(string_join(string_join(string_join(string_join(string_join("typedef struct ", type), "_array{"), type), + "**buffer;int length;int capacity;}"), + type), + "_array_t;"); + any_map_set(array_structs, type, as); + } + } + pos += 2; + } + } + string_t_array_t *keys = map_keys(array_structs); + for (i32 i = 0; i < keys->length; ++i) { + string_t *as = any_map_get(array_structs, keys->buffer[i]); + out(as); + out("\n"); + } + out("\n"); +} + +void write_fn_declarations() { + gc_unroot(fn_declarations); + fn_declarations = any_map_create(); + gc_root(fn_declarations); + any_array_resize(fn_declarations->keys, 4096 * 2); + any_array_resize(fn_declarations->values, 4096 * 2); + gc_unroot(fn_default_params); + fn_default_params = any_map_create(); + gc_root(fn_default_params); + any_array_resize(fn_default_params->keys, 1024 * 2); + any_array_resize(fn_default_params->values, 1024 * 2); + string_t *last_fn_name = ""; + for (pos = 0; pos < tokens->length; ++pos) { + string_t *token = get_token(0); + if (string_equals(token, "function")) { + gc_unroot(out); + out = string_equals(get_token(-1), "declare") ? &null_write : &stream_write; + gc_root(out); + pos++; + string_t *fn_name = get_token(0); + string_t *ret = function_return_type(); + if (string_equals(fn_name, "(")) { + pos--; + fn_name = string_join(string_join(last_fn_name, "_"), i32_to_string(pos)); + } + else { + if (string_equals(fn_name, "main")) { + fn_name = "_main"; + } + last_fn_name = string_copy(fn_name); + } + i32 _param_pos = 0; + string_t *params = "("; + pos++; + while (true) { + pos++; + token = string_copy(get_token(0)); + if (string_equals(token, ")")) { + break; + } + if (string_equals(token, ",")) { + params = string_join(params, ","); + _param_pos++; + continue; + } + pos++; + string_t *type = read_type(); + params = string_join(params, join_type_name(type, token)); + if (string_equals(get_token(1), "=")) { + string_t *param = get_token(2); + param = string_copy(enum_access(param)); + any_map_set(fn_default_params, string_join(fn_name, i32_to_string(_param_pos)), param); + pos += 2; + } + } + params = string_join(params, ")"); + string_t *fn_decl = string_join(string_join(string_join(ret, " "), fn_name), params); + out(string_join(fn_decl, ";\n")); + any_map_set(fn_declarations, fn_name, fn_decl); + } + } + out("\n"); + gc_unroot(out); + out = &stream_write; + gc_root(out); +} + +void write_globals() { + for (pos = 0; pos < tokens->length; ++pos) { + string_t *token = get_token(0); + if (string_equals(token, "let")) { + gc_unroot(out); + out = string_equals(get_token(-1), "declare") ? &null_write : &stream_write; + gc_root(out); + pos++; + string_t *name = get_token(0); + pos++; + string_t *type = read_type(); + if (char_ptr_array_index_of(basic_types, type) == -1 && char_ptr_array_index_of(pass_by_value_types, type) == -1 && + char_ptr_array_index_of(enums, type) == -1) { + any_array_push(global_ptrs, name); + } + out(string_join(join_type_name(type, name), ";")); + bool is_initialized = string_equals(get_token(1), "="); + if (is_initialized) { + string_t *init = name; + tabs = 1; + while (true) { + pos++; + token = string_copy(get_token(0)); + token = string_copy(enum_access(token)); + token = string_copy(array_access(token)); + token = string_copy(struct_alloc(token, null)); + if (string_equals(token, ";")) { + break; + } + token = string_copy(fill_fn_params(token)); + token = string_copy(array_create(token, name, null)); + if (string_equals(token, "map_create")) { + string_t *t = value_type(name); + if (string_equals(t, "i32_map_t *")) { + token = "i32_map_create"; + } + else if (string_equals(t, "i32_imap_t *")) { + token = "i32_imap_create"; + } + else if (string_equals(t, "any_imap_t *")) { + token = "any_imap_create"; + } + else { + token = "any_map_create"; + } + } + init = string_join(init, token); + } + any_array_push(global_inits, init); + } + out("\n"); + } + if (string_equals(token, "function") && !string_equals(get_token(-1), "declare")) { + skip_until("{"); + skip_block(); + } + } + gc_unroot(out); + out = &stream_write; + gc_root(out); +} + +void write_kickstart() { + out("\nvoid _kickstart() {\n"); + for (i32 i = 0; i < global_inits->length; ++i) { + string_t *val = global_inits->buffer[i]; + out("\t"); + string_t *name = string_split(val, "=")->buffer[0]; + bool global_alloc = char_ptr_array_index_of(global_ptrs, name) > -1 && !ends_with(val, "=null") && !ends_with(val, "\""); + if (global_alloc) { + out(string_join(string_join("gc_unroot(", name), ");")); + } + out(string_join(val, ";")); + if (global_alloc) { + out(string_join(string_join("gc_root(", name), ");")); + } + out("\n"); + } + out("\t_main();\n"); + out("\t#ifndef NO_IRON_START\n"); + out("\tiron_start();\n"); + out("\t#endif\n"); + out("}\n\n"); +} + +void write_function() { + string_t *fn_name = get_token(0); + if (string_equals(fn_name, "main")) { + fn_name = "_main"; + } + string_t *fn_decl = any_map_get(fn_declarations, fn_name); + out(string_join(fn_decl, "{\n")); + set_fn_param_types(); + skip_until("{"); + tabs = 1; + new_line = true; + string_t *mark_as_root = null; + fnested->length = 0; + while (true) { + pos++; + string_t *token = get_token(0); + if (string_equals(token, "function")) { + string_t *anon_fn = string_join(string_join(fn_name, "_"), i32_to_string(pos)); + out(string_join("&", anon_fn)); + if (string_equals(get_token(-1), "=")) { + out(";\n"); + } + skip_until("{"); + gc_unroot(out); + out = &string_write; + gc_root(out); + any_array_push(strings, ""); + string_t *fn_decl = any_map_get(fn_declarations, anon_fn); + out(string_join(fn_decl, "{\n")); + string_t *find = substring(fn_decl, 0, string_index_of(fn_decl, "(")); + i32 fn_pos = parse_int(substring(find, string_last_index_of(find, "_") + 1, string_length(find))); + i32 _pos = pos; + pos = fn_pos; + set_fn_param_types(); + pos = _pos; + i32_array_push(fnested, 1); + continue; + } + if (fnested->length > 0) { + if (string_equals(token, "{")) { + fnested->buffer[fnested->length - 1]++; + } + else if (string_equals(token, "}")) { + fnested->buffer[fnested->length - 1]--; + if (fnested->buffer[fnested->length - 1] == 0) { + array_pop(fnested); + out("}\n\n"); + if (strings->length > 1) { + string_t *s = array_pop(strings); + strings->buffer[strings->length - 1] = string_join(s, strings->buffer[strings->length - 1]); + } + if (fnested->length == 0) { + gc_unroot(out); + out = &stream_write; + gc_root(out); + } + continue; + } + } + } + if (string_equals(token, "}") && tabs == 1) { + out("}\n\n"); + break; + } + handle_tabs(token); + if (string_equals(token, "for")) { + is_for_loop = true; + } + else if (string_equals(token, "{")) { + is_for_loop = false; + } + else if (string_equals(token, "let")) { + pos++; + string_t *name = get_token(0); + pos++; + string_t *type = read_type(); + out(join_type_name(type, name)); + pos++; + token = string_copy(get_token(0)); + } + token = string_copy(enum_access(token)); + token = string_copy(struct_access(token)); + token = string_copy(array_access(token)); + bool is_assign = string_equals(get_token(1), "=") || string_equals(get_token(1), "+="); + if (is_assign && !string_equals(token, ":")) { + if (char_ptr_array_index_of(global_ptrs, token) > -1) { + out(string_join(string_join("gc_unroot(", token), ");")); + if (!string_equals(get_token(2), "null")) { + mark_as_root = string_copy(token); + } + } + } + if (string_equals(token, ";") && mark_as_root != null) { + out(string_join(string_join(";gc_root(", mark_as_root), ")")); + mark_as_root = null; + } + token = string_copy(struct_alloc(token, null)); + token = string_copy(array_create(token, get_token(-2), null)); + token = string_copy(array_ops(token)); + token = string_copy(map_ops(token)); + token = string_copy(string_ops(token)); + token = string_copy(string_len(token)); + if (string_equals(token, "/")) { + token = "/(float)"; + } + token = string_copy(fill_fn_params(token)); + out(token); + handle_spaces(token); + handle_new_line(token); + } +} + +void write_functions() { + for (pos = 0; pos < tokens->length; ++pos) { + string_t *token = get_token(0); + if (string_equals(token, "function")) { + pos++; + if (string_equals(get_token(-2), "declare")) { + continue; + } + write_function(); + } + while (strings->length > 0) { + string_t *s = array_pop(strings); + out(s); + } + } +} + +void write_iron_c() { + out("#include \n\n"); + out(header); + write_enums(); + write_types(); + write_array_types(); + write_fn_declarations(); + write_globals(); + write_kickstart(); + write_functions(); +} + +void alang(string_t *_alang_source, string_t *_alang_output) { + kickstart(); + gc_unroot(alang_source); + alang_source = (_alang_source); + gc_root(alang_source); + alang_source_length = string_length(alang_source); + gc_unroot(alang_output); + alang_output = (_alang_output); + gc_root(alang_output); + any_array_resize(tokens, 512000); + any_array_resize(strings, 32); + any_array_resize(enums, 512); + any_array_resize(fn_call_stack, 32); + i32_array_resize(param_pos_stack, 32); + any_array_resize(global_inits, 1024); + any_array_resize(global_ptrs, 1024); + any_array_resize(acontents, 2); + acontents->buffer[0] = any_array_create_from_raw((any[]){}, 0); + acontents->buffer[1] = any_array_create_from_raw((any[]){}, 0); + any_array_resize(acontents->buffer[0], 4096); + any_array_resize(acontents->buffer[1], 4096); + i32_array_resize(fnested, 32); + any_array_resize(value_types->keys, 4096 * 2); + any_array_resize(value_types->values, 4096 * 2); + any_array_resize(struct_types->keys, 512 * 2); + any_array_resize(struct_types->values, 512 * 2); + alang_parse(); + gc_unroot(fhandle); + fhandle = fopen(alang_output, "wb"); + gc_root(fhandle); + write_iron_c(); + fclose(fhandle); } diff --git a/base/tools/amake/alang.js b/base/tools/amake/alang.js deleted file mode 100644 index 8abae8e4..00000000 --- a/base/tools/amake/alang.js +++ /dev/null @@ -1,1680 +0,0 @@ - -let flags = globalThis.flags; -if (flags == null) { - flags = {}; - flags.alang_source = null; - flags.alang_output = "./test.c"; -} - -// ██████╗ █████╗ ██████╗ ███████╗ ███████╗ -// ██╔══██╗ ██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝ -// ██████╔╝ ███████║ ██████╔╝ ███████╗ █████╗ -// ██╔═══╝ ██╔══██║ ██╔══██╗ ╚════██║ ██╔══╝ -// ██║ ██║ ██║ ██║ ██║ ███████║ ███████╗ -// ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ - -let specials = [ ":", ";", ",", "(", ")", "[", "]", "{", "}", "<", ">", "!" ]; -let is_comment = false; -let is_string = false; -let pos = 0; -let tokens = []; -let header = ""; - -function is_alpha_numeric(code) { - return (code > 47 && code < 58) || // 0-9 - (code === 45) || // - - (code === 43) || // + - (code === 95) || // _ - (code === 46) || // . - (code > 64 && code < 91) || // A-Z - (code > 96 && code < 123); // a-z -} - -function is_alpha(code) { - return (code > 96 && code < 123) || // a-z - (code > 64 && code < 91) || // A-Z - (code === 95); // _ -} - -function is_numeric(code) { - return (code > 47 && code < 58); // 0-9 -} - -function is_white_space(code) { - return code === 32 || // " " - code === 9 || // "\t" - code === 13 || // "\r" - code === 10; // "\n" -} - -function read_token() { - // Skip white space - while (is_white_space(flags.alang_source.charCodeAt(pos))) { - pos++; - } - - let token = ""; - let first = true; - let is_anum = false; - - while (pos < flags.alang_source.length) { - let c = flags.alang_source.charAt(pos); - - // Comment start - if (token === "//") { - is_comment = true; - } - - if (is_comment) { - token += c; - pos++; - - // Comment end - if (c === "\n") { - is_comment = false; - if (token.startsWith("/// include") || token.startsWith("/// define")) { - header += "#" + token.substring(4, token.length); - } - // Remove comments - return null; - } - - // Prevent parsing of comments - continue; - } - - // String start / end - if (c === "\"") { - // Escaped \" - let last = token.length > 0 ? token.charAt(token.length - 1) : ""; - let last_last = token.length > 1 ? token.charAt(token.length - 2) : ""; - let is_escaped = last === "\\" && last_last != "\\"; - - if (!is_escaped) { - is_string = !is_string; - } - - // Token end - string end - if (!is_string) { - token += c; - pos++; - break; - } - } - - if (is_string) { - if (c == "\r") { - pos++; - continue; - } - - token += c; - pos++; - - // Prevent parsing of strings - continue; - } - - // Token end - if (is_white_space(flags.alang_source.charCodeAt(pos))) { - break; - } - - // Parsing an alphanumeric token - if (first) { - first = false; - is_anum = is_alpha_numeric(c.charCodeAt(0)); - } - - // Token end - let is_special = specials.indexOf(c) > -1; - if (is_anum && is_special) { - break; - } - - // Add char to token and advance pos - token += c; - pos++; - - // Token end, got special - if (is_special) { - break; - } - } - - return token; -} - -function alang_parse() { - tokens = []; - pos = 0; - - while (true) { - let token = read_token(); - if (token === "") { // No more tokens - break; - } - if (token === "=" && tokens[tokens.length - 1] === "!") { // Merge "!" and "=" into "!=" token - tokens[tokens.length - 1] = "!="; - continue; - } - if (token == null) { // Throw away this token - continue; - } - tokens.push(token); - } -} - -// ██╗ ██╗ ██████╗ -// ██║ ██║ ██╔══██╗ -// ██║ ██║ ██████╔╝ -// ██║ ██║ ██╔══██╗ -// ███████╗ ██║ ██████╔╝ -// ╚══════╝ ╚═╝ ╚═════╝ - -let fhandle; -let strings = []; -let tabs = 0; -let new_line = false; -let basic_types = [ "i8", "u8", "i16", "u16", "i32", "u32", "f32", "i64", "u64", "f64", "bool" ]; -let pass_by_value_types = [ "vec4_t", "vec3_t", "vec2_t", "quat_t", "mat4_t", "mat3_t" ]; -let enums = []; -let value_types = new Map(); -let struct_types = new Map(); -let fn_declarations = new Map(); -let fn_default_params = new Map(); -let fn_call_stack = []; -let param_pos_stack = []; -let is_for_loop = false; -let global_inits = []; -let global_ptrs = []; - -function handle_tabs(token) { - // Entering block, add tab - if (token === "{") { - tabs++; - } - else if (token === "}") { - tabs--; - } - - if (is_for_loop) { - return; - } - - // New line, add tabs - if (new_line) { - for (let i = 0; i < tabs; ++i) { - out("\t"); - } - } -} - -function handle_new_line(token) { - if (is_for_loop) { - return; - } - - // Insert new line - new_line = token === ";" || token === "{" || token === "}"; - if (new_line) { - out("\n"); - } -} - -let add_space_keywords = [ "return", "else" ]; - -function handle_spaces(token) { - // Add space to separate keywords - if (add_space_keywords.indexOf(token) > -1) { - out(" "); - } -} - -function get_token(off = 0) { - // if (pos + off < tokens.length) { - return tokens[pos + off]; - // } - // return ""; -} - -function get_token_after_piece() { - let _pos = pos; - skip_piece(); - let t = get_token(1); - pos = _pos; - return t; -} - -function skip_until(s) { - while (true) { - let token = get_token(); - if (token === s) { - break; - } - pos++; - } -} - -function skip_block() { // { ... } - pos++; // { - let nested = 1; - while (true) { - let token = get_token(); - if (token === "}") { - nested--; - if (nested === 0) { - break; - } - } - else if (token === "{") { - nested++; - } - pos++; - } -} - -function function_return_type() { - let _pos = pos; - skip_until("{"); - let t = get_token(-1); - if (t === "]") { // ): i32[] - pos -= 2; - } - else if (t === ">") { // ): map_t - pos -= 5; - } - pos -= 2; // ): i32 { - let result = get_token() === ":" ? read_type() : "void"; - pos = _pos; - return result; -} - -function join_type_name(type, name) { - value_types.set(name, type); - if (type.indexOf("(*NAME)(") > 0) { // Function pointer - return type.replace("NAME", name); - } - return type + " " + name; -} - -function read_type() { // Cursor at ":" - pos++; - let type = get_token(); - - if (type === "(" && get_token(1) === "(") { // (()=>void)[] - pos++; - } - - if (get_token(1) === ")" && get_token(2) === "[") { // (()=>void)[] - pos++; - } - - if (type === "(") { // ()=>void - let params = "("; - - if (get_token(1) != ")") { // Has params - while (true) { - skip_until(":"); - params += read_type(); - - pos++; - if (get_token() === ")") { // End of params - break; - } - - params += ","; - } - } - else { - params += "void"; - } - - params += ")"; - skip_until("=>"); - let ret = read_type(); - type = ret + "(*NAME)" + params; - } - - if (type === "color_t") { - type = "i32"; - } - else if (type === "string") { - type = "string_t"; - } - - if (get_token(1) === "[") { // Array - if (is_struct(type)) { - type = type + "_array_t"; - } - else if (type === "bool") { - type = "u8_array_t"; - } - else { - type = type + "_array_t"; - } - pos += 2; // Skip "[]" - } - - if (is_struct(type) && pass_by_value_types.indexOf(type) === -1) { - type += " *"; - } - - if (type === "map_t *" && get_token(1) === "<") { // Map - let mv = get_token(4); - if (mv === "f32") { - type = "f32_" + type; - } - else if (basic_types.indexOf(mv) > -1) { - let mk = get_token(2); - if (mk === "i32") { - type = "i32_i" + type; - } - else { - type = "i32_" + type; - } - } - else { - let mk = get_token(2); - if (mk === "i32") { - type = "any_i" + type; - } - else { - type = "any_" + type; - } - } - skip_until(">"); // Skip - } - - return type; -} - -function enum_access(s) { - // Turn enum_t.VALUE into ENUM_VALUE - if (s.indexOf("_t.") > -1) { - for (let e of enums) { - if (s.indexOf(e) > -1) { - s = s.replace("_t.", "_"); - s = s.toUpperCase(); - break; - } - } - } - return s; -} - -function struct_access(s) { - // Turn a.b into a->b - let dot = s.indexOf("."); - if (dot === -1) { - return s; - } - if (is_numeric(s.charCodeAt(dot + 1))) { - return s; - } - if (s.indexOf("\"") > -1) { - return s; - } - if (s.startsWith("GC_ALLOC_INIT")) { - return s; - } - - // Accessing pass_by_value_types struct like vec4.x - let has_minus = s.startsWith("-"); - let base = s.substring(has_minus ? 1 : 0, dot); - let type = value_types.get(base); - if (type != null) { - let dot_last = s.lastIndexOf("."); - if (dot != dot_last) { // a.vec4.x - let parts = s.split("."); - for (let i = 1; i < parts.length - 1; ++i) { - let struct_value_types = struct_types.get(type); - if (struct_value_types != null) { - type = struct_value_types.get(parts[i]); - - // struct my_struct -> my_struct_t - // my_struct * -> my_struct - if (type.startsWith("struct ") && type.endsWith(" *")) { - type = type.substring(0, type.length - 2); - type = type.substring(7, type.length) + "_t *"; - } - } - } - - if (!type.endsWith(" *")) { // vec4_t - let first = s.substring(0, dot_last).replaceAll(".", "->"); - let last = s.substring(dot_last, s.length); - return first + last; // a->vec4.x - } - } - else if (!type.endsWith(" *")) { // vec4.x - return s; - } - } - - return s.replaceAll(".", "->"); -} - -function struct_alloc(token, type = null) { - // "= { a: b, ... }" -> GC_ALLOC_INIT - if ((get_token(-1) === "=" && token === "{" && get_token(-3) != "type") || type != null) { - if (type == null) { - // let a: b = {, a = {, a.b = { - let i = get_token(-3) === ":" ? -4 : -2; - let t = struct_access(get_token(i)); - type = value_type(t); - if (type.endsWith(" *")) { // my_struct * -> my_struct - type = type.substring(0, type.length - 2); - } - if (type.startsWith("struct ")) { // struct my_struct -> my_struct_t - type = type.substring(7, type.length) + "_t"; - } - } - - token = "GC_ALLOC_INIT(" + type + ", {"; - pos++; // { - let ternary = 0; - while (true) { - let t = get_token(); - if (t == "}") { - break; - } - - let tc = get_token_c(); - tc = string_ops(tc); - if (get_token(1) === ":" && !ternary) { - tc = "." + tc; // a: b -> .a = b - } - if (t === ":") { - if (ternary > 0) { - ternary--; - } - else { - tc = "="; - } - } - else if (t === "?") { - ternary++; - } - else if (t === "[" && get_token(-1) === ":") { - let member = get_token(-2); - let types = struct_types.get(type + " *"); - let content_type = types.get(member); - content_type = content_type.substring(7, content_type.length - 8); // struct my_struct_array_t * -> my_struct - tc = array_create("[", "", content_type); - } - token += tc; - pos++; - } - - // "= {}" -> "= {0}", otherwise msvc refuses to init members to zero - if (get_token(-1) === "{") { - token += "0"; - } - - token += get_token(); // "}" - token += ")"; - tabs--; - } - return token; -} - -function array_type(name) { - let type = value_type(name); - if (type == null) { - return "any"; - } - if (type.startsWith("struct ")) { // struct u8_array * -> u8_array_t * - type = type.substring(7, type.length - 2) + "_t *"; - } - type = strip(type, 10); // Strip _array_t * - if (basic_types.indexOf(type) > -1) { // u8 - return type; - } - return "any"; -} - -function array_contents(type) { - // [1, 2, ..] or [{a:b}, {a:b}, ..] or [a(), b(), ..] - let contents = []; - let content = ""; - while (true) { - pos++; - let token = get_token(); - if (token === "]") { - if (content != "") { - contents.push(content); - } - break; - } - if (token === ",") { - contents.push(content); - content = ""; - continue; - } - if (token === "{") { - token = struct_alloc(token, type); - tabs++; // Undo tabs-- in struct_alloc - } - if (get_token(1) === "(") { - // Function call - while (true) { - pos++; - token += get_token(); - token = fill_default_params(token); - if (token.endsWith(")")) { - break; - } - } - } - // a / b - > a / (float)b - if (token === "/") { - token = "/(float)"; - } - token = struct_access(token); - token = string_ops(token); - content += token; - } - return contents; -} - -function member_name(name) { - let i = name.lastIndexOf("."); - if (i > -1) { - name = name.substring(i + 1, name.length); - } - return name; -} - -function array_create(token, name, content_type = null) { - if ((get_token(-1) === "=" && token === "[") || content_type != null) { - if (name === "]") { - name = get_token(-6); // ar: i32[] = [ - } - let member = member_name(name); - let type = array_type(member); - - // = [], = [1, 2, ..] -> any/i32/.._array_create_from_raw - if (content_type == null) { - name = struct_access(name); - content_type = value_type(name); - if (content_type != null) { - content_type = content_type.substring(0, content_type.length - 10); - } - } - let contents = array_contents(content_type); - token = type + "_array_create_from_raw((" + type + "[]){"; - for (let e of contents) { - token += e + ","; - } - token += "}," + contents.length + ")"; - } - return token; -} - -function array_access(token) { - // array[0] -> array->buffer[0] - if (token === "[" && get_token(-1) != "=") { - return "->buffer["; - } - return token; -} - -function is_struct(type) { - // Ends with _t and is not an enum - return type.endsWith("_t") && enums.indexOf(type) === -1; -} - -function strip(name, len) { - return name.substring(0, name.length - len); -} - -function strip_optional(name) { - if (name.endsWith("?")) { - return strip(name, 1); // :val? -> :val - } - return name; -} - -function param_pos() { - return param_pos_stack[param_pos_stack.length - 1]; -} - -function param_pos_add() { - param_pos_stack[param_pos_stack.length - 1]++; -} - -function fn_call() { - return fn_call_stack[fn_call_stack.length - 1]; -} - -function fill_fn_params(token) { - - if (token === "(") { - // Function is being called to init this variable - fn_call_stack.push(get_token(-1)); - param_pos_stack.push(0); - } - - else if (token === ",") { - // Param has beed passed manually - param_pos_add(); - } - - else if (token === ")") { - // Fill in default parameters if needed - if (get_token(-1) != "(") { - // Param has beed passed manually - param_pos_add(); - } - - // If default param exists, fill it - let res = ""; - while (fn_default_params.has(fn_call() + param_pos())) { - if (param_pos() > 0) { - res += ","; - } - res += fn_default_params.get(fn_call() + param_pos()); - param_pos_add(); - } - - fn_call_stack.pop(); - param_pos_stack.pop(); - token = res + token; - } - - return token; -} - -function get_token_c() { - let t = get_token(); - t = enum_access(t); - t = struct_access(t); - t = array_access(t); - return t; -} - -function fill_default_params(piece) { - // fn(a, 1, ..) - if (get_token(1) === ")") { - let fn_name = ""; - let params = 0; - let i = 0; - let nested = 1; - while (true) { - let ti = get_token(i); - if (ti === ")") { - nested++; - } - else if (ti === "(") { - if (get_token(i - 1) === ":") { // : ()=>void - return piece; - } - nested--; - if (nested === 0) { - fn_name = get_token(i - 1); - if (get_token(i + 1) != ")") { - params++; - } - break; - } - } - else if (ti === ",") { - params++; - } - i--; - } - while (fn_default_params.has(fn_name + params)) { - if (params > 0) { - piece += ","; - } - piece += fn_default_params.get(fn_name + params); - params++; - } - } - return piece; -} - -function skip_piece(nested = 0) { - let t1 = get_token(1); - if (t1 === "(" || t1 === "[") { - nested++; - pos++; - skip_piece(nested); - return; - } - - if (t1 === ")" || t1 === "]") { - nested--; - if (nested < 0) { - return; - } - pos++; - skip_piece(nested); - return; - } - - if (nested > 0) { - pos++; - skip_piece(nested); - return; - } - - if (t1.startsWith(".")) { - pos++; - skip_piece(); - return; - } -} - -function read_piece(nested = 0) { - // call(a, b, c), a[b + c] - let piece = get_token_c(); - piece = string_length(piece); - piece = map_ops(piece); - - let t1 = get_token(1); - if (t1 === "(" || t1 === "[") { - nested++; - pos++; - return piece + read_piece(nested); - } - - if (t1 === ")" || t1 === "]") { - nested--; - if (nested < 0) { - return piece; - } - piece = fill_default_params(piece); - pos++; - return piece + read_piece(nested); - } - - if (nested > 0) { - pos++; - return piece + read_piece(nested); - } - - if (t1.startsWith(".")) { - pos++; - return piece + read_piece(); - } - - return piece; -} - -function string_length(token) { - // "str->length" -> "string_length(str)" - if (!token.endsWith("->length")) { - return token; - } - let base = strip(token, 8); // ->length - let type = value_type(base); - if (type === "string_t *" || type === "struct string *") { - token = "string_length(" + base + ")"; - } - return token; -} - -function value_type(value) { - let arrow = value.indexOf("->"); - if (arrow > -1) { - let base = value.substring(0, arrow); - let type = value_types.get(base); - let member = value.substring(arrow + 2, value.length); - let struct_value_types = struct_types.get(type); - if (struct_value_types != null) { - return struct_value_types.get(member); - } - } - return value_types.get(value); -} - -function set_fn_param_types() { - pos++; // ( - while (true) { - pos++; - let t = get_token(); // Param name, ) or , - if (t === ")") { // Params end - break; - } - if (t === ",") { // Next param - continue; - } - - pos++; // : - let type = read_type(); - value_types.set(t, type); - - if (get_token(1) === "=") { // Skip default value - pos += 2; - } - } -} - -function number_to_string(token) { - let type = value_type(token); - if (type === "i32") { - return "i32_to_string(" + token + ")"; - } - if (type === "f32") { - return "f32_to_string(" + token + ")"; - } - return token; -} - -function token_is_string(token) { - let is_string = token.startsWith("\"") || value_type(token) === "string_t *"; - - if (!is_string) { - let _pos = pos; - skip_piece(); - let t1 = get_token(1); - if (t1 === "+" || t1 === "+=" || t1 === "==" || t1 === "!=") { - let t2 = get_token(2); - if (t2.startsWith("\"") || value_type(t2) === "string_t *") { - is_string = true; - } - } - pos = _pos; - } - - if (is_string && get_token(2) === "null") { - is_string = false; - } - - return is_string; -} - -function string_add(token) { - token = "string_join(" + token + ","; - pos++; - - let token_b = read_piece(); - token_b = number_to_string(token_b); - token += token_b; - token += ")"; - return token; -} - -function string_ops(token) { - // "str" + str + 1 + ... - - if (!token_is_string(token)) { - return token; - } - - let first = true; - while (get_token_after_piece() === "+") { - if (first) { - first = false; - token = read_piece(); - token = number_to_string(token); - } - pos++; - token = string_add(token); - } - - // "str" += str + str2 - let p1 = get_token_after_piece(); - if (p1 === "+=") { - token = read_piece(); - pos++; - token = token + "=string_join(" + token + ","; - pos++; - if (get_token_after_piece() === "+") { - let token_b = read_piece(); - token_b = number_to_string(token_b); - while (get_token_after_piece() === "+") { - pos++; - token_b = string_add(token_b); - } - token += token_b; - } - else { - token += read_piece(); - } - token += ")"; - } - - // str = str - else if (p1 === "=") { - let _pos = pos; - let t1 = read_piece(); - pos++; - pos++; // = - let t2 = read_piece(); - if (get_token(1) === ";" && !t2.startsWith("\"")) { // str = str; - token = t1 + "=string_copy(" + t2 + ")"; // Copy string - } - else { - pos = _pos; - } - } - - // "str" === str - else if (p1 === "==") { - token = read_piece(); - pos++; - - token = "string_equals(" + token + ","; - pos++; - token += read_piece(); - token += ")"; - } - - // "str" != str - else if (p1 === "!=") { - token = read_piece(); - pos++; - - token = "!string_equals(" + token + ","; - pos++; - token += read_piece(); - token += ")"; - } - - return token; -} - -function array_ops(token) { - // array_push -> i32_array_push/any_array_push - if (token === "array_push") { - let value = get_token(2); - - if (get_token(3) === "[") { // raws[i].value - value = get_token(6).substring(1); // .value - } - - if (value.lastIndexOf(".") > -1) { - value = value.substring(value.lastIndexOf(".") + 1, value.length); - } - let type = array_type(value); - token = type + "_array_push"; - } - - // array_remove -> i32_array_remove / char_ptr_array_remove - else if (token === "array_remove") { - let value = get_token(2); - value = struct_access(value); - let type = value_type(value); - if (type != null && type.startsWith("struct ")) { // struct u8_array * -> u8_array_t * - type = type.substring(7, type.length - 2) + "_t *"; - } - - if (type === "i32_array_t *") { - token = "i32_array_remove"; - } - else if (type === "string_t_array_t *") { - token = "char_ptr_array_remove"; - } - } - - // array_index_of -> i32_array_index_of / char_ptr_array_index_of - else if (token === "array_index_of") { - let value = get_token(2); - value = struct_access(value); - let type = value_type(value); - if (type != null && type.startsWith("struct ")) { // struct u8_array * -> u8_array_t * - type = type.substring(7, type.length - 2) + "_t *"; - } - - if (type === "i32_array_t *") { - token = "i32_array_index_of"; - } - else if (type === "string_t_array_t *") { - token = "char_ptr_array_index_of"; - } - else { - let fn = fn_declarations.get(value); - if (fn != null && fn.startsWith("string_t_array_t *")) { - token = "char_ptr_array_index_of"; - } - } - } - - return token; -} - -function map_ops(token) { - if (token === "map_create") { - let t = value_type(get_token(-2)); - if (t === "i32_map_t *") { - token = "i32_map_create"; - } - else if (t === "i32_imap_t *") { - token = "i32_imap_create"; - } - else if (t === "any_imap_t *") { - token = "any_imap_create"; - } - else { - token = "any_map_create"; - } - } - - else if (token === "map_set") { - let t = value_type(get_token(2)); - if (t === "i32_map_t *") { - token = "i32_map_set"; - } - else if (t === "i32_imap_t *") { - token = "i32_imap_set"; - } - else if (t === "any_imap_t *") { - token = "any_imap_set"; - } - else { - token = "any_map_set"; - } - } - - else if (token === "map_get") { - let t = value_type(get_token(2)); - if (t === "i32_map_t *") { - token = "i32_map_get"; - } - else if (t === "i32_imap_t *") { - token = "i32_imap_get"; - } - else if (t === "any_imap_t *") { - token = "any_imap_get"; - } - else { - token = "any_map_get"; - } - } - - else if (token === "map_delete") { - let t = value_type(get_token(2)); - if (t === "any_imap_t *") { - token = "imap_delete"; - } - } - - return token; -} - -function _t_to_struct(type) { - // type_t * -> struct type * - if (type.endsWith("_t *") && type != "string_t *") { - let type_short = strip(type, 4); // _t * - if (type_short.endsWith("_array")) { // gpu_texture_format_t_array -> i32_array - for (let e of enums) { - if (type_short.startsWith(e)) { - type_short = "i32_array"; - break; - } - } - } - type = "struct " + type_short + " *"; - } - return type; -} - -// ██╗ ██╗ ██████╗ ██╗ ████████╗ ███████╗ ██████╗ -// ██║ ██║ ██╔══██╗ ██║ ╚══██╔══╝ ██╔════╝ ██╔════╝ -// ██║ █╗ ██║ ██████╔╝ ██║ ██║ █████╗ ██║ -// ██║███╗██║ ██╔══██╗ ██║ ██║ ██╔══╝ ██║ -// ╚███╔███╔╝ ██║ ██║ ██║ ██║ ███████╗ ╚██████╗ -// ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝ - -function stream_write(token) { - fhandle.puts(token); -} - -function string_write(token) { - strings[strings.length - 1] += token; -} - -function null_write(token) { - return; -} - -let out = stream_write; - -function write_enums() { - enums = []; - for (pos = 0; pos < tokens.length; ++pos) { - let token = get_token(); - - // Turn "enum name {}" into "typedef enum {} name;" - if (token === "enum") { - - out = get_token(-1) === "declare" ? null_write : stream_write; - - pos++; - let enum_name = get_token(); - enums.push(enum_name); - - out("typedef enum{\n"); - pos++; // { - - while (true) { - // Enum contents - pos++; - token = get_token(); // Item name - - if (token === "}") { // Enum end - out("}" + enum_name + ";\n"); - break; - } - - let enum_base = strip(enum_name, 2); // _t - enum_base = enum_base.toUpperCase(); - out("\t" + enum_base + "_" + token); - - pos++; // = or , - token = get_token(); - - if (token === "=") { // Enum value - pos++; // n - token = get_token(); - out("=" + token); - pos++; // , - } - - out(",\n"); - } - - out("\n"); - continue; - } - } - - out = stream_write; -} - -function write_types() { - for (pos = 0; pos < tokens.length; ++pos) { - let token = get_token(); - - // Turn "type x = {};" into "typedef struct {} x;" - // Turn "type x = y;" into "typedef x y;" - if (token === "type") { - - out = get_token(-1) === "declare" ? null_write : stream_write; - - pos++; - let struct_name = get_token(); - let stuct_name_short = strip(struct_name, 2); // _t - - pos++; - token = get_token(); // = - if (token != "=") { - continue; - } - - pos++; - token = get_token(); - - // "type x = y;" - if (token != "{") { - pos--; - let type = read_type(); - type = _t_to_struct(type); - - out("typedef " + type + " " + struct_name + ";\n\n"); - skip_until(";"); - continue; - } - - // "type x = {};" - out("typedef struct " + stuct_name_short + "{\n"); - - let struct_value_types = new Map(); - struct_types.set(struct_name + " *", struct_value_types); - - while (true) { - // Struct contents - pos++; - let name = get_token(); - - if (name === "}") { // Struct end - out("}" + struct_name + ";\n"); - break; - } - - // val?: i32 -> val: i32 - name = strip_optional(name); - - pos++; - // : - let type = read_type(); - - // type_t * -> struct type * - type = _t_to_struct(type); - - // my_struct_t*(*NAME)(my_struct_t *) -> struct my_struct*(*NAME)(struct my_struct*) - if (type.indexOf("(*NAME)") > -1) { - let args = type.substring(type.indexOf(")(") + 2, type.lastIndexOf(")")); - args = args.split(","); - - type = type.substring(0, type.indexOf("(*NAME)")); - type = _t_to_struct(type); - type += "(*NAME)("; - - for (let i = 0; i < args.length; ++i) { - let arg = args[i]; - arg = _t_to_struct(arg); - if (i > 0) { - type += ","; - } - type += arg; - } - type += ")"; - } - - skip_until(";"); - - out("\t" + join_type_name(type, name) + ";\n"); - struct_value_types.set(name, type); - } - - out("\n"); - continue; - } - } - - out = stream_write; -} - -function write_array_types() { - // Array structs (any_array_t -> scene_t_array_t) - let array_structs = new Map(); - for (pos = 0; pos < tokens.length; ++pos) { - let token = get_token(); - if (get_token(1) === "[") { - let type = token; - if (type === "string") { - type = "string_t"; - } - if (is_struct(type)) { - if (!array_structs.has(type)) { - let as = "typedef struct " + type + "_array{" + type + "**buffer;int length;int capacity;}" + type + "_array_t;"; - array_structs.set(type, as); - } - } - pos += 2; // Skip "[]" - } - } - - for (let as of array_structs.values()) { - out(as); - out("\n"); - } - out("\n"); -} - -function write_fn_declarations() { - fn_declarations = new Map(); - fn_default_params = new Map(); - let last_fn_name = ""; - for (pos = 0; pos < tokens.length; ++pos) { - let token = get_token(); - - if (token === "function") { - - out = get_token(-1) === "declare" ? null_write : stream_write; - - // Return type + name - pos++; - let fn_name = get_token(); - let ret = function_return_type(); - - if (fn_name === "(") { // Anonymous function - fn_name = last_fn_name + "_" + (pos - 1); - pos--; - } - else { - if (fn_name === "main") { - fn_name = "_main"; - } - last_fn_name = fn_name; - } - - // Params - let _param_pos = 0; - let params = "("; - pos++; // ( - while (true) { - pos++; - token = get_token(); // Param name, ) or , - - if (token === ")") { // Params end - break; - } - - if (token === ",") { // Next param - params += ","; - _param_pos++; - continue; - } - - pos++; // : - let type = read_type(); - params += join_type_name(type, token); - - // Store param default - if (get_token(1) === "=") { - let param = get_token(2); - param = enum_access(param); - fn_default_params.set(fn_name + _param_pos, param); - pos += 2; - } - } - params += ")"; - - let fn_decl = ret + " " + fn_name + params; - out(fn_decl + ";\n"); - - fn_declarations.set(fn_name, fn_decl); - } - } - out("\n"); - - out = stream_write; -} - -function write_globals() { - global_inits = []; - global_ptrs = []; - for (pos = 0; pos < tokens.length; ++pos) { - let token = get_token(); - - if (token === "let") { - - out = get_token(-1) === "declare" ? null_write : stream_write; - - pos++; - let name = get_token(); - - pos++; // : - let type = read_type(); - - if (basic_types.indexOf(type) === -1 && pass_by_value_types.indexOf(type) === -1 && enums.indexOf(type) === -1) { - global_ptrs.push(name); - } - - out(join_type_name(type, name) + ";"); - - // Init this var in _kickstart() - let is_initialized = get_token(1) === "="; - if (is_initialized) { - let init = name; - tabs = 1; - while (true) { - pos++; - token = get_token(); - - token = enum_access(token); - token = array_access(token); - token = struct_alloc(token); - - if (token === ";") { - break; - } - - token = fill_fn_params(token); - - // [] -> _array_create - token = array_create(token, name); - - if (token === "map_create") { - let t = value_type(name); - if (t === "i32_map_t *") { - token = "i32_map_create"; - } - else if (t === "i32_imap_t *") { - token = "i32_imap_create"; - } - else if (t === "any_imap_t *") { - token = "any_imap_create"; - } - else { - token = "any_map_create"; - } - } - - init += token; - } - global_inits.push(init); - } - - out("\n"); - } - - // Skip function blocks - if (token === "function" && get_token(-1) != "declare") { - skip_until("{"); - skip_block(); - } - } - - out = stream_write; -} - -function write_kickstart() { - // Start function - out("\nvoid _kickstart() {\n"); - // Init globals - for (let val of global_inits) { - out("\t"); - let name = val.split("=")[0]; - let global_alloc = global_ptrs.indexOf(name) > -1 && !val.endsWith("=null") && !val.endsWith("\""); - if (global_alloc) { - out("gc_unroot(" + name + ");"); - } - out(val + ";"); - if (global_alloc) { - out("gc_root(" + name + ");"); - } - out("\n"); - } - out("\t_main();\n"); - out("\t#ifndef NO_IRON_START\n"); - out("\tiron_start();\n"); - out("\t#endif\n"); - out("}\n\n"); -} - -function write_function() { - // Function declaration - let fn_name = get_token(); - - if (fn_name === "main") { - fn_name = "_main"; - } - - let fn_decl = fn_declarations.get(fn_name); - out(fn_decl + "{\n"); - - // Function body - // Re-set function param types into value_types map - set_fn_param_types(); - skip_until("{"); - - tabs = 1; - new_line = true; - let mark_as_root = null; - let nested = []; - - while (true) { - pos++; - let token = get_token(); - - if (token === "function") { // Begin nested function - let anon_fn = fn_name + "_" + pos; - out("&" + anon_fn); - if (get_token(-1) === "=") { - out(";\n"); - } - - skip_until("{"); - out = string_write; - strings.push(""); - let fn_decl = fn_declarations.get(anon_fn); - out(fn_decl + "{\n"); - - let find = fn_decl.substring(0, fn_decl.indexOf("(")); - let fn_pos = parseInt(find.substring(find.lastIndexOf("_") + 1, find.length)); - let _pos = pos; - pos = fn_pos; - set_fn_param_types(); - pos = _pos; - - nested.push(1); - continue; - } - - if (nested.length > 0) { - if (token === "{") { - nested[nested.length - 1]++; - } - else if (token === "}") { // End nested function - nested[nested.length - 1]--; - if (nested[nested.length - 1] === 0) { - nested.pop(); - out("}\n\n"); - if (strings.length > 1) { - let s = strings.pop(); - strings[strings.length - 1] = s + strings[strings.length - 1]; - } - - if (nested.length === 0) { - out = stream_write; - } - continue; - } - } - } - - // Function end - if (token === "}" && tabs === 1) { - out("}\n\n"); - break; - } - - handle_tabs(token); - - if (token === "for") { // Skip new lines in for (;;) loop - is_for_loop = true; - } - else if (token === "{") { - is_for_loop = false; - } - // Write type and name - else if (token === "let") { - pos++; - let name = get_token(); - pos++; // : - let type = read_type(); - out(join_type_name(type, name)); - // = or ; - pos++; - token = get_token(); - } - - // Turn val.a into val_a or val->a - token = enum_access(token); - - token = struct_access(token); - - // array[0] -> array->buffer[0] - token = array_access(token); - - // Use static alloc for global pointers - let is_assign = get_token(1) === "=" || get_token(1) === "+="; // += for string_join - if (is_assign && token != ":") { - if (global_ptrs.indexOf(token) > -1) { - out("gc_unroot(" + token + ");"); - if (get_token(2) != "null") { - mark_as_root = token; - } - } - } - if (token === ";" && mark_as_root != null) { - out(";gc_root(" + mark_as_root + ")"); - mark_as_root = null; - } - - // "= { ... }" -> GC_ALLOC_INIT - token = struct_alloc(token); - - // [] -> _array_create - token = array_create(token, get_token(-2)); - token = array_ops(token); - - // Maps - token = map_ops(token); - - // Strings - token = string_ops(token); - - // "str->length" -> "string_length(str)" - token = string_length(token); - - // a / b - > a / (float)b - if (token === "/") { - token = "/(float)"; - } - - // a(1) -> a(1, 2) // a(x: i32, y: i32 = 2) - token = fill_fn_params(token); - - // Write token - out(token); - - handle_spaces(token); - handle_new_line(token); - } -} - -function write_functions() { - for (pos = 0; pos < tokens.length; ++pos) { - let token = get_token(); - if (token === "function") { - pos++; - if (get_token(-2) === "declare") { - continue; - } - write_function(); - } - - // Write anonymous function body - while (strings.length > 0) { - let s = strings.pop(); - out(s); - } - } -} - -function write_iron_c() { - out("#include \n\n"); - out(header); - write_enums(); - write_types(); - write_array_types(); - write_fn_declarations(); - write_globals(); - write_kickstart(); - write_functions(); -} - -// ██╗ ██╗ ██╗ ██████╗ ██╗ ██╗ ███████╗ ████████╗ █████╗ ██████╗ ████████╗ -// ██║ ██╔╝ ██║ ██╔════╝ ██║ ██╔╝ ██╔════╝ ╚══██╔══╝ ██╔══██╗ ██╔══██╗ ╚══██╔══╝ -// █████╔╝ ██║ ██║ █████╔╝ ███████╗ ██║ ███████║ ██████╔╝ ██║ -// ██╔═██╗ ██║ ██║ ██╔═██╗ ╚════██║ ██║ ██╔══██║ ██╔══██╗ ██║ -// ██║ ██╗ ██║ ╚██████╗ ██║ ██╗ ███████║ ██║ ██║ ██║ ██║ ██║ ██║ -// ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ - -function alang() { - alang_parse(); - fhandle = std.open(flags.alang_output, "w"); - write_iron_c(); - fhandle.close(); -} - -let t = Date.now(); -alang(); -console.log("alang took " + (Date.now() - t) + "ms."); diff --git a/base/tools/amake/alang.ts b/base/tools/amake/alang.ts deleted file mode 100644 index 7b947574..00000000 --- a/base/tools/amake/alang.ts +++ /dev/null @@ -1,1740 +0,0 @@ - -/// include - -let alang_output: string = null; -let alang_source: string = null; -let alang_source_length: i32; - -// ██████╗ █████╗ ██████╗ ███████╗ ███████╗ -// ██╔══██╗ ██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝ -// ██████╔╝ ███████║ ██████╔╝ ███████╗ █████╗ -// ██╔═══╝ ██╔══██║ ██╔══██╗ ╚════██║ ██╔══╝ -// ██║ ██║ ██║ ██║ ██║ ███████║ ███████╗ -// ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ - -let specials: string[] = [ ":", ";", ",", "(", ")", "[", "]", "{", "}", "<", ">", "!" ]; -let is_comment: bool = false; -let is_string: bool = false; -let pos: i32 = 0; -let tokens: string[] = []; -let header: string = ""; - -function is_alpha_numeric(code: i32): bool { - return (code > 47 && code < 58) || // 0-9 - (code == 45) || // - - (code == 43) || // + - (code == 95) || // _ - (code == 46) || // . - (code > 64 && code < 91) || // A-Z - (code > 96 && code < 123); // a-z -} - -function is_alpha(code: i32): bool { - return (code > 96 && code < 123) || // a-z - (code > 64 && code < 91) || // A-Z - (code == 95); // _ -} - -function is_numeric(code: i32): bool { - return (code > 47 && code < 58); // 0-9 -} - -function is_white_space(code: i32): bool { - return code == 32 || // " " - code == 9 || // "\t" - code == 13 || // "\r" - code == 10; // "\n" -} - -function read_token(): string { - // Skip white space - while (is_white_space(char_code_at(alang_source, pos))) { - pos++; - } - - let token: string = ""; - let first: bool = true; - let is_anum: bool = false; - - while (pos < alang_source_length) { - let c: string = char_at(alang_source, pos); - - // Comment start - if (token == "//") { - is_comment = true; - } - - if (is_comment) { - token += c; - pos++; - - // Comment end - if (c == "\n") { - is_comment = false; - if (starts_with(token, "/// include") || starts_with(token, "/// define")) { - header += "#" + substring(token, 4, token.length); - } - // Remove comments - return read_token(); - } - - // Prevent parsing of comments - continue; - } - - // String start / end - if (c == "\"") { - // Escaped \" - let last: string = token.length > 0 ? char_at(token, token.length - 1) : ""; - let last_last: string = token.length > 1 ? char_at(token, token.length - 2) : ""; - let is_escaped: bool = last == "\\" && last_last != "\\"; - - if (!is_escaped) { - is_string = !is_string; - } - - // Token end - string end - if (!is_string) { - token += c; - pos++; - break; - } - } - - if (is_string) { - if (c == "\r") { - pos++; - continue; - } - - token += c; - pos++; - - // Prevent parsing of strings - continue; - } - - // Token end - if (is_white_space(char_code_at(alang_source, pos))) { - break; - } - - // Parsing an alphanumeric token - if (first) { - first = false; - is_anum = is_alpha_numeric(char_code_at(c, 0)); - } - - // Token end - let is_special: bool = array_index_of(specials, c) > -1; - if (is_anum && is_special) { - break; - } - - // Add char to token and advance pos - token += c; - pos++; - - // Token end, got special - if (is_special) { - break; - } - } - - return token; -} - -function alang_parse() { - pos = 0; - - while (true) { - let token: string = read_token(); - - if (token == "=" && tokens[tokens.length - 1] == "!") { // Merge "!" and "=" into "!=" token - tokens[tokens.length - 1] = "!="; - continue; - } - if (token == "") { // No more tokens - break; - } - array_push(tokens, token); - } -} - -// ██╗ ██╗ ██████╗ -// ██║ ██║ ██╔══██╗ -// ██║ ██║ ██████╔╝ -// ██║ ██║ ██╔══██╗ -// ███████╗ ██║ ██████╔╝ -// ╚══════╝ ╚═╝ ╚═════╝ - -let fhandle: any; -let strings: string[] = []; -let tabs: i32 = 0; -let new_line: bool = false; -let basic_types: string[] = [ "i8", "u8", "i16", "u16", "i32", "u32", "f32", "i64", "u64", "f64", "bool" ]; -let pass_by_value_types: string[] = [ "vec4_t", "vec3_t", "vec2_t", "quat_t", "mat4_t", "mat3_t" ]; -let enums: string[] = []; -let value_types: map_t = map_create(); -type string_map_t = map_t; -let struct_types: map_t = map_create(); -let fn_declarations: map_t; -let fn_default_params: map_t; -let fn_call_stack: string[] = []; -let param_pos_stack: i32[] = []; -let is_for_loop: bool = false; -let global_inits: string[] = []; -let global_ptrs: string[] = []; -type string_array_t = string[]; -let acontents: string_array_t[] = []; -let fnested: i32[] = []; -let add_space_keywords: string[] = [ "return", "else" ]; -let array_contents_depth: i32 = 0; - -function handle_tabs(token: string) { - // Entering block, add tab - if (token == "{") { - tabs++; - } - else if (token == "}") { - tabs--; - } - - if (is_for_loop) { - return; - } - - // New line, add tabs - if (new_line) { - for (let i: i32 = 0; i < tabs; ++i) { - out("\t"); - } - } -} - -function handle_new_line(token: string) { - if (is_for_loop) { - return; - } - - // Insert new line - new_line = token == ";" || token == "{" || token == "}"; - if (new_line) { - out("\n"); - } -} - -function handle_spaces(token: string) { - // Add space to separate keywords - if (array_index_of(add_space_keywords, token) > -1) { - out(" "); - } -} - -function get_token(off: i32 = 0): string { - if (pos + off >= 0 && pos + off < tokens.length) { - return tokens[pos + off]; - } - return ""; -} - -function get_token_after_piece(): string { - let _pos: i32 = pos; - skip_piece(); - let t: string = get_token(1); - pos = _pos; - return t; -} - -function skip_until(s: string) { - while (true) { - let token: string = get_token(); - if (token == s) { - break; - } - pos++; - } -} - -function skip_block() { // { ... } - pos++; // { - let nested: i32 = 1; - while (true) { - let token: string = get_token(); - if (token == "}") { - nested--; - if (nested == 0) { - break; - } - } - else if (token == "{") { - nested++; - } - pos++; - } -} - -function function_return_type(): string { - let _pos: i32 = pos; - skip_until("{"); - let t: string = get_token(-1); - if (t == "]") { // ): i32[] - pos -= 2; - } - else if (t == ">") { // ): map_t - pos -= 5; - } - pos -= 2; // ): i32 { - let result: string = get_token() == ":" ? read_type() : "void"; - pos = _pos; - return result; -} - -function join_type_name(type: string, name: string): string { - map_set(value_types, name, type); - if (string_index_of(type, "(*NAME)(") > 0) { // Function pointer - return string_replace_all(type, "NAME", name); - } - return type + " " + name; -} - -function read_type(): string { // Cursor at ":" - pos++; - let type: string = get_token(); - - if (type == "(" && get_token(1) == "(") { // (()=>void)[] - pos++; - } - - if (get_token(1) == ")" && get_token(2) == "[") { // (()=>void)[] - pos++; - } - - if (type == "(") { // ()=>void - let params: string = "("; - - if (get_token(1) != ")") { // Has params - while (true) { - skip_until(":"); - params += read_type(); - - pos++; - if (get_token() == ")") { // End of params - break; - } - - params += ","; - } - } - else { - params += "void"; - } - - params += ")"; - skip_until("=>"); - let ret: string = read_type(); - type = ret + "(*NAME)" + params; - } - - if (type == "color_t") { - type = "i32"; - } - else if (type == "string") { - type = "string_t"; - } - - if (get_token(1) == "[") { // Array - if (is_struct(type)) { - type = type + "_array_t"; - } - else if (type == "bool") { - type = "u8_array_t"; - } - else { - type = type + "_array_t"; - } - pos += 2; // Skip "[]" - } - - if (is_struct(type) && array_index_of(pass_by_value_types, type) == -1) { - type += " *"; - } - - if (type == "map_t *" && get_token(1) == "<") { // Map - let mv: string = get_token(4); - if (mv == "f32") { - type = "f32_" + type; - } - else if (array_index_of(basic_types, mv) > -1) { - let mk: string = get_token(2); - if (mk == "i32") { - type = "i32_i" + type; - } - else { - type = "i32_" + type; - } - } - else { - let mk: string = get_token(2); - if (mk == "i32") { - type = "any_i" + type; - } - else { - type = "any_" + type; - } - } - skip_until(">"); // Skip - } - - return type; -} - -function enum_access(s: string): string { - // Turn enum_t.VALUE into ENUM_VALUE - if (string_index_of(s, "_t.") > -1) { - for (let i: i32 = 0; i < enums.length; ++i) { - let e: string = enums[i]; - if (string_index_of(s, e) > -1) { - s = string_replace_all(s, "_t.", "_"); - s = to_upper_case(s); - break; - } - } - } - return s; -} - -function struct_access(s: string): string { - // Turn a.b into a->b - let dot: i32 = string_index_of(s, "."); - if (dot == -1) { - return s; - } - if (is_numeric(char_code_at(s, dot + 1))) { - return s; - } - if (string_index_of(s, "\"") > -1) { - return s; - } - if (starts_with(s, "GC_ALLOC_INIT")) { - return s; - } - - // Accessing pass_by_value_types struct like vec4.x - let has_minus: bool = starts_with(s, "-"); - let base: string = substring(s, has_minus ? 1 : 0, dot); - let type: string = map_get(value_types, base); - if (type != null) { - let dot_last: i32 = string_last_index_of(s, "."); - if (dot != dot_last) { // a.vec4.x - let parts: string[] = string_split(s, "."); - for (let i: i32 = 1; i < parts.length - 1; ++i) { - let struct_value_types: map_t = map_get(struct_types, type); - if (struct_value_types != null) { - type = map_get(struct_value_types, parts[i]); - - // struct my_struct -> my_struct_t - // my_struct * -> my_struct - if (starts_with(type, "struct ") && ends_with(type, " *")) { - type = substring(type, 0, type.length - 2); - type = substring(type, 7, type.length) + "_t *"; - } - } - } - if (!ends_with(type, " *")) { // vec4_t - let first: string = string_replace_all(substring(s, 0, dot_last), ".", "->"); - let last: string = substring(s, dot_last, s.length); - return first + last; // a->vec4.x - } - } - else if (!ends_with(type, " *")) { // vec4.x - return s; - } - } - - return string_replace_all(s, ".", "->"); -} - -function struct_alloc(token: string, type: string = null): string { - // "= { a: b, ... }" -> GC_ALLOC_INIT - if ((get_token(-1) == "=" && token == "{" && get_token(-3) != "type") || type != null) { - if (type == null) { - // let a: b = {, a = {, a.b = { - let i: i32 = get_token(-3) == ":" ? -4 : -2; - let t: string = struct_access(get_token(i)); - type = value_type(t); - if (ends_with(type, " *")) { // my_struct * -> my_struct - type = substring(type, 0, type.length - 2); - } - if (starts_with(type, "struct ")) { // struct my_struct -> my_struct_t - type = substring(type, 7, type.length) + "_t"; - } - } - - token = "GC_ALLOC_INIT(" + type + ", {"; - pos++; // { - let ternary: i32 = 0; - while (true) { - let t: string = get_token(); - if (t == "}") { - break; - } - - let tc: string = get_token_c(); - tc = string_ops(tc); - if (get_token(1) == ":" && !ternary) { - tc = "." + tc; // a: b -> .a = b - } - if (t == ":") { - if (ternary > 0) { - ternary--; - } - else { - tc = "="; - } - } - else if (t == "?") { - ternary++; - } - else if (t == "[" && get_token(-1) == ":") { - let member: string = get_token(-2); - let types: map_t = map_get(struct_types, type + " *"); - let content_type: string = map_get(types, member); - content_type = substring(content_type, 7, content_type.length - 8); // struct my_struct_array_t * -> my_struct - tc = array_create("[", "", content_type); - } - token += tc; - pos++; - } - - // "= {}" -> "= {0}", otherwise msvc refuses to init members to zero - if (get_token(-1) == "{") { - token += "0"; - } - - token += get_token(); // "}" - token += ")"; - tabs--; - } - return token; -} - -function array_type(name: string): string { - let type: string = value_type(name); - if (type == null) { - return "any"; - } - if (starts_with(type, "struct ")) { // struct u8_array * -> u8_array_t * - type = substring(type, 7, type.length - 2) + "_t *"; - } - type = strip(type, 10); // Strip _array_t * - if (array_index_of(basic_types, type) > -1) { // u8 - return type; - } - return "any"; -} - -function array_contents(type: string): string[] { - - // [1, 2, ..] or [{a:b}, {a:b}, ..] or [a(), b(), ..] - let contents: string[] = acontents[array_contents_depth]; - array_contents_depth++; - contents.length = 0; - - let content: string = ""; - while (true) { - pos++; - let token: string = get_token(); - if (token == "]") { - if (content != "") { - array_push(contents, content); - } - break; - } - if (token == ",") { - array_push(contents, content); - content = ""; - continue; - } - if (token == "{") { - token = struct_alloc(token, type); - tabs++; // Undo tabs-- in struct_alloc - } - if (get_token(1) == "(") { - // Function call - while (true) { - pos++; - token += get_token(); - token = fill_default_params(token); - if (ends_with(token, ")")) { - break; - } - } - } - // a / b - > a / (float)b - if (token == "/") { - token = "/(float)"; - } - token = struct_access(token); - token = string_ops(token); - content += token; - } - - array_contents_depth--; - - return contents; -} - -function member_name(name: string): string { - let i: i32 = string_last_index_of(name, "."); - if (i > -1) { - name = substring(name, i + 1, name.length); - } - return name; -} - -function array_create(token: string, name: string, content_type: string = null): string { - if ((get_token(-1) == "=" && token == "[") || content_type != null) { - if (name == "]") { - name = get_token(-6); // ar: i32[] = [ - } - let member: string = member_name(name); - let type: string = array_type(member); - - // = [], = [1, 2, ..] -> any/i32/.._array_create_from_raw - if (content_type == null) { - name = struct_access(name); - content_type = value_type(name); - if (content_type != null) { - content_type = substring(content_type, 0, content_type.length - 10); - } - } - let contents: string[] = array_contents(content_type); - token = type + "_array_create_from_raw((" + type + "[]){"; - for (let i: i32 = 0; i < contents.length; ++i) { - let e: string = contents[i]; - token += e + ","; - } - let len: i32 = contents.length; - token += "}," + len + ")"; - } - return token; -} - -function array_access(token: string): string { - // array[0] -> array->buffer[0] - if (token == "[" && get_token(-1) != "=") { - return "->buffer["; - } - return token; -} - -function is_struct(type: string): bool { - // Ends with _t and is not an enum - return ends_with(type, "_t") && array_index_of(enums, type) == -1; -} - -function strip(name: string, len: i32): string { - return substring(name, 0, name.length - len); -} - -function strip_optional(name: string): string { - if (ends_with(name, "?")) { - return strip(name, 1); // :val? -> :val - } - return name; -} - -function param_pos(): i32 { - return param_pos_stack[param_pos_stack.length - 1]; -} - -function param_pos_add() { - param_pos_stack[param_pos_stack.length - 1]++; -} - -function fn_call(): string { - return fn_call_stack[fn_call_stack.length - 1]; -} - -function fill_fn_params(token: string): string { - - if (token == "(") { - // Function is being called to init this variable - array_push(fn_call_stack, get_token(-1)); - array_push(param_pos_stack, 0); - } - - else if (token == ",") { - // Param has beed passed manually - param_pos_add(); - } - - else if (token == ")") { - // Fill in default parameters if needed - if (get_token(-1) != "(") { - // Param has beed passed manually - param_pos_add(); - } - - // If default param exists, fill it - let res: string = ""; - while (true) { - let i: i32 = param_pos(); - let fn: string = fn_call(); - let param: string = map_get(fn_default_params, fn + i); - if (param == null) { - break; - } - if (i > 0) { - res += ","; - } - res += param; - param_pos_add(); - } - - array_pop(fn_call_stack); - array_pop(param_pos_stack); - - token = res + token; - } - - return token; -} - -function get_token_c(): string { - let t: string = get_token(); - t = enum_access(t); - t = struct_access(t); - t = array_access(t); - return t; -} - -function fill_default_params(piece: string): string { - // fn(a, 1, ..) - if (get_token(1) == ")") { - let fn_name: string = ""; - let params: i32 = 0; - let i: i32 = 0; - let nested: i32 = 1; - while (true) { - let ti: string = get_token(i); - if (ti == ")") { - nested++; - } - else if (ti == "(") { - if (get_token(i - 1) == ":") { // : ()=>void - return piece; - } - nested--; - if (nested == 0) { - fn_name = get_token(i - 1); - if (get_token(i + 1) != ")") { - params++; - } - break; - } - } - else if (ti == ",") { - params++; - } - i--; - } - while (true) { - let param: string = map_get(fn_default_params, fn_name + params); - if (param == null) { - break; - } - if (params > 0) { - piece += ","; - } - piece += param; - params++; - } - } - return piece; -} - -function skip_piece(nested: i32 = 0) { - let t1: string = get_token(1); - if (t1 == "(" || t1 == "[") { - nested++; - pos++; - skip_piece(nested); - return; - } - - if (t1 == ")" || t1 == "]") { - nested--; - if (nested < 0) { - return; - } - pos++; - skip_piece(nested); - return; - } - - if (nested > 0) { - pos++; - skip_piece(nested); - return; - } - - if (starts_with(t1, ".")) { - pos++; - skip_piece(); - return; - } -} - -function read_piece(nested: i32 = 0): string { - // call(a, b, c), a[b + c] - let piece: string = get_token_c(); - piece = string_len(piece); - piece = map_ops(piece); - - let t1: string = get_token(1); - if (t1 == "(" || t1 == "[") { - nested++; - pos++; - return piece + read_piece(nested); - } - - if (t1 == ")" || t1 == "]") { - nested--; - if (nested < 0) { - return piece; - } - piece = fill_default_params(piece); - pos++; - return piece + read_piece(nested); - } - - if (nested > 0) { - pos++; - return piece + read_piece(nested); - } - - if (starts_with(t1, ".")) { - pos++; - return piece + read_piece(); - } - - return piece; -} - -function string_len(token: string): string { - // "str->length" -> "string_length(str)" - if (!ends_with(token, "->length")) { - return token; - } - let base: string = strip(token, 8); // ->length - let type: string = value_type(base); - if (type == "string_t *" || type == "struct string *") { - token = "string_length(" + base + ")"; - } - return token; -} - -function value_type(value: string): string { - let arrow: i32 = string_index_of(value, "->"); - if (arrow > -1) { - let base: string = substring(value, 0, arrow); - let type: string = map_get(value_types, base); - let member: string = substring(value, arrow + 2, value.length); - let struct_value_types: map_t = map_get(struct_types, type); - if (struct_value_types != null) { - return map_get(struct_value_types, member); - } - } - return map_get(value_types, value); -} - -function set_fn_param_types() { - pos++; // ( - while (true) { - pos++; - let t: string = get_token(); // Param name, ) or , - if (t == ")") { // Params end - break; - } - if (t == ",") { // Next param - continue; - } - - pos++; // : - let type: string = read_type(); - map_set(value_types, t, type); - - if (get_token(1) == "=") { // Skip default value - pos += 2; - } - } -} - -function number_to_string(token: string): string { - let type: string = value_type(token); - if (type == "i32") { - return "i32_to_string(" + token + ")"; - } - if (type == "f32") { - return "f32_to_string(" + token + ")"; - } - return token; -} - -function token_is_string(token: string): bool { - let is_string: bool = starts_with(token, "\"") || value_type(token) == "string_t *"; - - if (!is_string) { - let _pos: i32 = pos; - skip_piece(); - let t1: string = get_token(1); - if (t1 == "+" || t1 == "+=" || t1 == "==" || t1 == "!=") { - let t2: string = get_token(2); - if (starts_with(t2, "\"") || value_type(t2) == "string_t *") { - is_string = true; - } - } - pos = _pos; - } - - if (is_string && get_token(2) == "null") { - is_string = false; - } - - return is_string; -} - -function string_add(token: string): string { - token = "string_join(" + token + ","; - pos++; - - let token_b: string = read_piece(); - token_b = number_to_string(token_b); - token += token_b; - token += ")"; - return token; -} - -function string_ops(token: string): string { - // "str" + str + 1 + ... - - if (!token_is_string(token)) { - return token; - } - - let first: bool = true; - while (get_token_after_piece() == "+") { - if (first) { - first = false; - token = read_piece(); - token = number_to_string(token); - } - pos++; - token = string_add(token); - } - - // "str" += str + str2 - let p1: string = get_token_after_piece(); - if (p1 == "+=") { - token = read_piece(); - pos++; - token = token + "=string_join(" + token + ","; - pos++; - if (get_token_after_piece() == "+") { - let token_b: string = read_piece(); - token_b = number_to_string(token_b); - while (get_token_after_piece() == "+") { - pos++; - token_b = string_add(token_b); - } - token += token_b; - } - else { - token += read_piece(); - } - token += ")"; - } - - // str = str - else if (p1 == "=") { - let _pos: i32 = pos; - let t1: string = read_piece(); - pos++; - pos++; // = - let t2: string = read_piece(); - // TODO: let s: string = str; - if (get_token(1) == ";" && !starts_with(t2, "\"")) { // str = str; - token = t1 + "=string_copy(" + t2 + ")"; // Copy string - } - else { - pos = _pos; - } - } - - // "str" == str - else if (p1 == "==") { - token = read_piece(); - pos++; - - token = "string_equals(" + token + ","; - pos++; - token += read_piece(); - token += ")"; - } - - // "str" != str - else if (p1 == "!=") { - token = read_piece(); - pos++; - - token = "!string_equals(" + token + ","; - pos++; - token += read_piece(); - token += ")"; - } - - return token; -} - -function array_ops(token: string): string { - // array_push -> i32_array_push/any_array_push - if (token == "array_push") { - let value: string = get_token(2); - - if (get_token(3) == "[") { // raws[i].value - let t6: string = get_token(6); - value = substring(t6, 1, t6.length); // .value - } - - if (string_last_index_of(value, ".") > -1) { - value = substring(value, string_last_index_of(value, ".") + 1, value.length); - } - let type: string = array_type(value); - token = type + "_array_push"; - } - - // array_remove -> i32_array_remove / char_ptr_array_remove - else if (token == "array_remove") { - let value: string = get_token(2); - value = struct_access(value); - let type: string = value_type(value); - if (type != null && starts_with(type, "struct ")) { // struct u8_array * -> u8_array_t * - type = substring(type, 7, type.length - 2) + "_t *"; - } - - if (type == "i32_array_t *") { - token = "i32_array_remove"; - } - else if (type == "string_t_array_t *") { - token = "char_ptr_array_remove"; - } - } - - // array_index_of -> i32_array_index_of / char_ptr_array_index_of - else if (token == "array_index_of") { - let value: string = get_token(2); - value = struct_access(value); - let type: string = value_type(value); - if (type != null && starts_with(type, "struct ")) { // struct u8_array * -> u8_array_t * - type = substring(type, 7, type.length - 2) + "_t *"; - } - - if (type == "i32_array_t *") { - token = "i32_array_index_of"; - } - else if (type == "string_t_array_t *") { - token = "char_ptr_array_index_of"; - } - else { - let fn: string = map_get(fn_declarations, value); - if (fn != null && starts_with(fn, "string_t_array_t *")) { - token = "char_ptr_array_index_of"; - } - } - } - - return token; -} - -function map_ops(token: string): string { - if (token == "map_create") { - let t: string = value_type(get_token(-2)); - if (t == "i32_map_t *") { - token = "i32_map_create"; - } - else if (t == "i32_imap_t *") { - token = "i32_imap_create"; - } - else if (t == "any_imap_t *") { - token = "any_imap_create"; - } - else { - token = "any_map_create"; - } - } - - else if (token == "map_set") { - let t: string = value_type(get_token(2)); - if (t == "i32_map_t *") { - token = "i32_map_set"; - } - else if (t == "i32_imap_t *") { - token = "i32_imap_set"; - } - else if (t == "any_imap_t *") { - token = "any_imap_set"; - } - else { - token = "any_map_set"; - } - } - - else if (token == "map_get") { - let t: string = value_type(get_token(2)); - if (t == "i32_map_t *") { - token = "i32_map_get"; - } - else if (t == "i32_imap_t *") { - token = "i32_imap_get"; - } - else if (t == "any_imap_t *") { - token = "any_imap_get"; - } - else { - token = "any_map_get"; - } - } - - else if (token == "map_delete") { - let t: string = value_type(get_token(2)); - if (t == "any_imap_t *") { - token = "imap_delete"; - } - } - - return token; -} - -function _t_to_struct(type: string): string { - // type_t * -> struct type * - if (ends_with(type, "_t *") && type != "string_t *") { - let type_short: string = strip(type, 4); // _t * - if (ends_with(type_short, "_array")) { // gpu_texture_format_t_array -> i32_array - for (let i: i32 = 0; i < enums.length; ++i) { - let e: string = enums[i]; - if (starts_with(type_short, e)) { - type_short = "i32_array"; - break; - } - } - } - type = "struct " + type_short + " *"; - } - return type; -} - -// ██╗ ██╗ ██████╗ ██╗ ████████╗ ███████╗ ██████╗ -// ██║ ██║ ██╔══██╗ ██║ ╚══██╔══╝ ██╔════╝ ██╔════╝ -// ██║ █╗ ██║ ██████╔╝ ██║ ██║ █████╗ ██║ -// ██║███╗██║ ██╔══██╗ ██║ ██║ ██╔══╝ ██║ -// ╚███╔███╔╝ ██║ ██║ ██║ ██║ ███████╗ ╚██████╗ -// ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝ - -function stream_write(token: string) { - fwrite(token, 1, token.length, fhandle); -} - -function string_write(token: string) { - strings[strings.length - 1] += token; -} - -function null_write(token: string) { - return; -} - -let out: (token: string) => void = stream_write; - -function write_enums() { - for (pos = 0; pos < tokens.length; ++pos) { - let token: string = get_token(); - - // Turn "enum name {}" into "typedef enum {} name;" - if (token == "enum") { - - out = get_token(-1) == "declare" ? & null_write : & stream_write; - - pos++; - let enum_name: string = get_token(); - array_push(enums, enum_name); - - out("typedef enum{\n"); - pos++; // { - - while (true) { - // Enum contents - pos++; - token = get_token(); // Item name - - if (token == "}") { // Enum end - out("}" + enum_name + ";\n"); - break; - } - - let enum_base: string = strip(enum_name, 2); // _t - enum_base = to_upper_case(enum_base); - out("\t" + enum_base + "_" + token); - - pos++; // = or , - token = get_token(); - - if (token == "=") { // Enum value - pos++; // n - token = get_token(); - out("=" + token); - pos++; // , - } - - out(",\n"); - } - - out("\n"); - continue; - } - } - - out = & stream_write; -} - -function write_types() { - for (pos = 0; pos < tokens.length; ++pos) { - let token: string = get_token(); - - // Turn "type x = {};" into "typedef struct {} x;" - // Turn "type x = y;" into "typedef x y;" - if (token == "type") { - - out = get_token(-1) == "declare" ? & null_write : & stream_write; - - pos++; - let struct_name: string = get_token(); - let stuct_name_short: string = strip(struct_name, 2); // _t - - pos++; - token = get_token(); // = - if (token != "=") { - continue; - } - - pos++; - token = get_token(); - - // "type x = y;" - if (token != "{") { - pos--; - let type: string = read_type(); - type = _t_to_struct(type); - - out("typedef " + type + " " + struct_name + ";\n\n"); - skip_until(";"); - continue; - } - - // "type x = {};" - out("typedef struct " + stuct_name_short + "{\n"); - - let struct_value_types: map_t = map_create(); - any_array_resize(struct_value_types.keys, 512 * 2); - any_array_resize(struct_value_types.values, 512 * 2); - - map_set(struct_types, struct_name + " *", struct_value_types); - - while (true) { - // Struct contents - pos++; - let name: string = get_token(); - - if (name == "}") { // Struct end - out("}" + struct_name + ";\n"); - break; - } - - // val?: i32 -> val: i32 - name = strip_optional(name); - - pos++; - // : - let type: string = read_type(); - - // type_t * -> struct type * - type = _t_to_struct(type); - - // my_struct_t*(*NAME)(my_struct_t *) -> struct my_struct*(*NAME)(struct my_struct*) - if (string_index_of(type, "(*NAME)") > -1) { - let args_str: string = substring(type, string_index_of(type, ")(") + 2, string_last_index_of(type, ")")); - let args: string[] = string_split(args_str, ","); - - type = substring(type, 0, string_index_of(type, "(*NAME)")); - type = _t_to_struct(type); - type += "(*NAME)("; - - for (let i: i32 = 0; i < args.length; ++i) { - let arg: string = args[i]; - arg = _t_to_struct(arg); - if (i > 0) { - type += ","; - } - type += arg; - } - type += ")"; - } - - skip_until(";"); - - out("\t" + join_type_name(type, name) + ";\n"); - map_set(struct_value_types, name, type); - } - - out("\n"); - continue; - } - } - - out = & stream_write; -} - -function write_array_types() { - // Array structs (any_array_t -> scene_t_array_t) - let array_structs: map_t = map_create(); - any_array_resize(array_structs.keys, 256 * 2); - any_array_resize(array_structs.values, 256 * 2); - - for (pos = 0; pos < tokens.length; ++pos) { - let token: string = get_token(); - if (get_token(1) == "[") { - let type: string = token; - if (type == "string") { - type = "string_t"; - } - if (is_struct(type)) { - if (map_get(array_structs, type) == null) { - let as: string = "typedef struct " + type + "_array{" + type + "**buffer;int length;int capacity;}" + type + "_array_t;"; - map_set(array_structs, type, as); - } - } - pos += 2; // Skip "[]" - } - } - - let keys: string[] = map_keys(array_structs); - for (let i: i32 = 0; i < keys.length; ++i) { - let as: string = map_get(array_structs, keys[i]); - out(as); - out("\n"); - } - - out("\n"); -} - -function write_fn_declarations() { - fn_declarations = map_create(); - any_array_resize(fn_declarations.keys, 4096 * 2); - any_array_resize(fn_declarations.values, 4096 * 2); - - fn_default_params = map_create(); - any_array_resize(fn_default_params.keys, 1024 * 2); - any_array_resize(fn_default_params.values, 1024 * 2); - - let last_fn_name: string = ""; - for (pos = 0; pos < tokens.length; ++pos) { - let token: string = get_token(); - - if (token == "function") { - - out = get_token(-1) == "declare" ? & null_write : & stream_write; - - // Return type + name - pos++; - let fn_name: string = get_token(); - let ret: string = function_return_type(); - - if (fn_name == "(") { // Anonymous function - pos--; - fn_name = last_fn_name + "_" + pos; - } - else { - if (fn_name == "main") { - fn_name = "_main"; - } - last_fn_name = fn_name; - } - - // Params - let _param_pos: i32 = 0; - let params: string = "("; - pos++; // ( - while (true) { - pos++; - token = get_token(); // Param name, ) or , - - if (token == ")") { // Params end - break; - } - - if (token == ",") { // Next param - params += ","; - _param_pos++; - continue; - } - - pos++; // : - let type: string = read_type(); - params += join_type_name(type, token); - - // Store param default - if (get_token(1) == "=") { - let param: string = get_token(2); - param = enum_access(param); - map_set(fn_default_params, fn_name + _param_pos, param); - pos += 2; - } - } - params += ")"; - - let fn_decl: string = ret + " " + fn_name + params; - out(fn_decl + ";\n"); - - map_set(fn_declarations, fn_name, fn_decl); - } - } - out("\n"); - - out = & stream_write; -} - -function write_globals() { - for (pos = 0; pos < tokens.length; ++pos) { - let token: string = get_token(); - - if (token == "let") { - - out = get_token(-1) == "declare" ? & null_write : & stream_write; - - pos++; - let name: string = get_token(); - - pos++; // : - let type: string = read_type(); - - if (array_index_of(basic_types, type) == -1 && array_index_of(pass_by_value_types, type) == -1 && array_index_of(enums, type) == -1) { - array_push(global_ptrs, name); - } - - out(join_type_name(type, name) + ";"); - - // Init this var in _kickstart() - let is_initialized: bool = get_token(1) == "="; - if (is_initialized) { - let init: string = name; - tabs = 1; - while (true) { - pos++; - token = get_token(); - - token = enum_access(token); - token = array_access(token); - token = struct_alloc(token); - - if (token == ";") { - break; - } - - token = fill_fn_params(token); - - // [] -> _array_create - token = array_create(token, name); - - if (token == "map_create") { - let t: string = value_type(name); - if (t == "i32_map_t *") { - token = "i32_map_create"; - } - else if (t == "i32_imap_t *") { - token = "i32_imap_create"; - } - else if (t == "any_imap_t *") { - token = "any_imap_create"; - } - else { - token = "any_map_create"; - } - } - - init += token; - } - array_push(global_inits, init); - } - - out("\n"); - } - - // Skip function blocks - if (token == "function" && get_token(-1) != "declare") { - skip_until("{"); - skip_block(); - } - } - - out = & stream_write; -} - -function write_kickstart() { - // Start function - out("\nvoid _kickstart() {\n"); - // Init globals - for (let i: i32 = 0; i < global_inits.length; ++i) { - let val: string = global_inits[i]; - out("\t"); - let name: string = string_split(val, "=")[0]; - let global_alloc: bool = array_index_of(global_ptrs, name) > -1 && !ends_with(val, "=null") && !ends_with(val, "\""); - if (global_alloc) { - out("gc_unroot(" + name + ");"); - } - out(val + ";"); - if (global_alloc) { - out("gc_root(" + name + ");"); - } - out("\n"); - } - out("\t_main();\n"); - out("\t#ifndef NO_IRON_START\n"); - out("\tiron_start();\n"); - out("\t#endif\n"); - out("}\n\n"); -} - -function write_function() { - // Function declaration - let fn_name: string = get_token(); - - if (fn_name == "main") { - fn_name = "_main"; - } - - let fn_decl: string = map_get(fn_declarations, fn_name); - out(fn_decl + "{\n"); - - // Function body - // Re-set function param types into value_types map - set_fn_param_types(); - skip_until("{"); - - tabs = 1; - new_line = true; - let mark_as_root: string = null; - fnested.length = 0; - - while (true) { - pos++; - let token: string = get_token(); - - if (token == "function") { // Begin nested function - let anon_fn: string = fn_name + "_" + pos; - out("&" + anon_fn); - if (get_token(-1) == "=") { - out(";\n"); - } - - skip_until("{"); - out = & string_write; - array_push(strings, ""); - let fn_decl: string = map_get(fn_declarations, anon_fn); - out(fn_decl + "{\n"); - - let find: string = substring(fn_decl, 0, string_index_of(fn_decl, "(")); - let fn_pos: i32 = parse_int(substring(find, string_last_index_of(find, "_") + 1, find.length)); - let _pos: i32 = pos; - pos = fn_pos; - set_fn_param_types(); - pos = _pos; - - array_push(fnested, 1); - continue; - } - - if (fnested.length > 0) { - if (token == "{") { - fnested[fnested.length - 1]++; - } - else if (token == "}") { // End fnested function - fnested[fnested.length - 1]--; - if (fnested[fnested.length - 1] == 0) { - array_pop(fnested); - out("}\n\n"); - if (strings.length > 1) { - let s: string = array_pop(strings); - strings[strings.length - 1] = s + strings[strings.length - 1]; - } - - if (fnested.length == 0) { - out = & stream_write; - } - continue; - } - } - } - - // Function end - if (token == "}" && tabs == 1) { - out("}\n\n"); - break; - } - - handle_tabs(token); - - if (token == "for") { // Skip new lines in for (;;) loop - is_for_loop = true; - } - else if (token == "{") { - is_for_loop = false; - } - // Write type and name - else if (token == "let") { - pos++; - let name: string = get_token(); - pos++; // : - let type: string = read_type(); - out(join_type_name(type, name)); - // = or ; - pos++; - token = get_token(); - } - - // Turn val.a into val_a or val->a - token = enum_access(token); - - token = struct_access(token); - - // array[0] -> array->buffer[0] - token = array_access(token); - - // Use static alloc for global pointers - let is_assign: bool = get_token(1) == "=" || get_token(1) == "+="; // += for string_join - if (is_assign && token != ":") { - if (array_index_of(global_ptrs, token) > -1) { - out("gc_unroot(" + token + ");"); - if (get_token(2) != "null") { - mark_as_root = token; - } - } - } - if (token == ";" && mark_as_root != null) { - out(";gc_root(" + mark_as_root + ")"); - mark_as_root = null; - } - - // "= { ... }" -> GC_ALLOC_INIT - token = struct_alloc(token); - - // [] -> _array_create - token = array_create(token, get_token(-2)); - token = array_ops(token); - - // Maps - token = map_ops(token); - - // Strings - token = string_ops(token); - - // "str->length" -> "string_length(str)" - token = string_len(token); - - // a / b - > a / (float)b - if (token == "/") { - token = "/(float)"; - } - - // a(1) -> a(1, 2) // a(x: i32, y: i32 = 2) - token = fill_fn_params(token); - - // Write token - out(token); - - handle_spaces(token); - handle_new_line(token); - } -} - -function write_functions() { - for (pos = 0; pos < tokens.length; ++pos) { - let token: string = get_token(); - if (token == "function") { - pos++; - if (get_token(-2) == "declare") { - continue; - } - write_function(); - } - - // Write anonymous function body - while (strings.length > 0) { - let s: string = array_pop(strings); - out(s); - } - } -} - -function write_iron_c() { - out("#include \n\n"); - out(header); - write_enums(); - write_types(); - write_array_types(); - write_fn_declarations(); - write_globals(); - write_kickstart(); - write_functions(); -} - -// ██╗ ██╗ ██╗ ██████╗ ██╗ ██╗ ███████╗ ████████╗ █████╗ ██████╗ ████████╗ -// ██║ ██╔╝ ██║ ██╔════╝ ██║ ██╔╝ ██╔════╝ ╚══██╔══╝ ██╔══██╗ ██╔══██╗ ╚══██╔══╝ -// █████╔╝ ██║ ██║ █████╔╝ ███████╗ ██║ ███████║ ██████╔╝ ██║ -// ██╔═██╗ ██║ ██║ ██╔═██╗ ╚════██║ ██║ ██╔══██║ ██╔══██╗ ██║ -// ██║ ██╗ ██║ ╚██████╗ ██║ ██╗ ███████║ ██║ ██║ ██║ ██║ ██║ ██║ -// ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ - -function main() {} - -function alang(_alang_source: string, _alang_output: string) { - kickstart(); - - alang_source = (_alang_source); // () - no string copy - alang_source_length = alang_source.length; - alang_output = (_alang_output); - - // HEAP_SIZE - any_array_resize(tokens, 512000); - any_array_resize(strings, 32); - any_array_resize(enums, 512); - any_array_resize(fn_call_stack, 32); - i32_array_resize(param_pos_stack, 32); - any_array_resize(global_inits, 1024); - any_array_resize(global_ptrs, 1024); - any_array_resize(acontents, 2); - acontents[0] = []; - acontents[1] = []; - any_array_resize(acontents[0], 4096); - any_array_resize(acontents[1], 4096); - i32_array_resize(fnested, 32); - any_array_resize(value_types.keys, 4096 * 2); - any_array_resize(value_types.values, 4096 * 2); - any_array_resize(struct_types.keys, 512 * 2); - any_array_resize(struct_types.values, 512 * 2); - // - - alang_parse(); - fhandle = fopen(alang_output, "wb"); - write_iron_c(); - fclose(fhandle); -} diff --git a/base/tools/amake/kong/alang.c b/base/tools/amake/kong/alang.c new file mode 100644 index 00000000..7b5a641c --- /dev/null +++ b/base/tools/amake/kong/alang.c @@ -0,0 +1,3830 @@ +// Based on https://github.com/Kode/Kongruent by RobDangerous +#include "alang.h" +#include +#include +#include +#include +#include +#include +#include +// #define STB_DS_IMPLEMENTATION +#include "../../sources/libs/kong/libs/stb_ds.h" +#ifdef WIN32 +#include +#endif +#ifdef __android__ +#include +#endif + +#define static_array(type, name, max_size) \ + typedef struct name { \ + type values[max_size]; \ + size_t size; \ + size_t max; \ + } name; + +#define static_array_init(array) \ + array.size = 0; \ + array.max = sizeof(array.values) / sizeof(array.values[0]) + +#define static_array_push(array, value) \ + if (array.size >= array.max) { \ + debug_context context = {0}; \ + error(context, "Array overflow"); \ + } \ + array.values[array.size++] = value; + +#define static_array_push_p(array, value) \ + if (array->size >= array->max) { \ + debug_context context = {0}; \ + error(context, "Array overflow"); \ + } \ + array->values[array->size++] = value; + +// based on https://valkey.io/blog/new-hash-table/ + +struct meta { + uint8_t c : 1; + uint8_t presence : 7; + uint8_t hashes[7]; +}; + +struct container { + int key; +}; + +struct bucket { + struct meta meta; + void *entries[7]; +}; + +#define HASH_MAP_SIZE 256 + +struct hash_map { + struct bucket buckets[HASH_MAP_SIZE]; +}; + +static inline uint64_t hash(int key) { + uint64_t primary = key % HASH_MAP_SIZE; + uint8_t secondary = key % HASH_MAP_SIZE; + return primary | ((uint64_t)secondary << 56); +} + +static inline struct bucket *allocate_bucket(void) { +#ifdef _WIN32 + struct bucket *new_bucket = (struct bucket *)_aligned_malloc(sizeof(struct bucket), 64); +#else + struct bucket *new_bucket = (struct bucket *)aligned_alloc(64, sizeof(struct bucket)); +#endif + assert(new_bucket != NULL); + memset(new_bucket, 0, sizeof(struct bucket)); + + // cache line check + assert((uint64_t)new_bucket % 64 == 0); + assert(sizeof(struct bucket) == 64); + + return new_bucket; +} + +static inline struct hash_map *hash_map_create(void) { +#ifdef _WIN32 + struct hash_map *map = _aligned_malloc(sizeof(struct hash_map), 64); +#else + struct hash_map *map = aligned_alloc(64, sizeof(struct hash_map)); +#endif + assert(map != NULL); + memset(map, 0, sizeof(struct hash_map)); + + // cache line check + assert((uint64_t)map % 64 == 0); + + return map; +} + +static inline void hash_map_destroy(struct hash_map *map) {} + +static inline void hash_map_add_to_bucket(struct bucket *bucket, struct container *value, uint8_t secondary_hash) { + for (uint32_t index = 0; index < 7; ++index) { + if (((bucket->meta.presence >> index) & 1) == 0) { + bucket->entries[index] = value; + bucket->meta.hashes[index] = secondary_hash; + + bucket->meta.presence |= (1 << index); + + return; + } + } + + if (bucket->meta.c) { + hash_map_add_to_bucket((struct bucket *)bucket->entries[6], value, secondary_hash); + } + else { + bucket->meta.c = 1; + + struct container *previous = (struct container *)bucket->entries[6]; + uint8_t previous_secondary_hash = bucket->meta.hashes[6]; + + struct bucket *new_bucket = allocate_bucket(); + + bucket->entries[6] = new_bucket; + + hash_map_add_to_bucket(new_bucket, previous, previous_secondary_hash); + hash_map_add_to_bucket(new_bucket, value, secondary_hash); + } +} + +static inline void hash_map_add(struct hash_map *map, struct container *value) { + uint64_t hash_value = hash(value->key); + uint64_t primary = hash_value & 0xffffffffffffffu; + uint8_t secondary = (uint8_t)(hash_value << 56); + + hash_map_add_to_bucket(&map->buckets[primary], value, secondary); +} + +static inline struct container *hash_map_get_from_bucket(struct bucket *bucket, int key, uint8_t secondary_hash) { + for (uint32_t index = 0; index < 6; ++index) { + if (((bucket->meta.presence >> index) & 1) != 0 && bucket->meta.hashes[index] == secondary_hash) { + struct container *value = (struct container *)bucket->entries[index]; + + if (value->key == key) { + return value; + } + } + } + + if (bucket->meta.c) { + struct bucket *next_bucket = (struct bucket *)bucket->entries[6]; + return hash_map_get_from_bucket(next_bucket, key, secondary_hash); + } + else { + if (((bucket->meta.presence >> 6) & 1) != 0 && bucket->meta.hashes[6] == secondary_hash) { + struct container *value = (struct container *)bucket->entries[6]; + + if (value->key == key) { + return value; + } + } + } + + return NULL; +} + +static inline struct container *hash_map_get(struct hash_map *map, int key) { + uint64_t hash_value = hash(key); + uint64_t primary = hash_value & 0xffffffffffffffu; + uint8_t secondary = (uint8_t)(hash_value << 56); + + struct bucket *bucket = &map->buckets[primary]; + + return hash_map_get_from_bucket(bucket, key, secondary); +} + +static inline void hash_map_iterate_in_bucket(struct bucket *bucket, void (*callback)(struct container *, void *data), void *data) { + for (uint32_t index = 0; index < 6; ++index) { + if (((bucket->meta.presence >> index) & 1) != 0) { + struct container *value = (struct container *)bucket->entries[index]; + callback(value, data); + } + } + + if (bucket->meta.c) { + struct bucket *next_bucket = (struct bucket *)bucket->entries[6]; + hash_map_iterate_in_bucket(next_bucket, callback, data); + } + else { + if (((bucket->meta.presence >> 6) & 1) != 0) { + struct container *value = (struct container *)bucket->entries[6]; + callback(value, data); + } + } +} + +static inline void hash_map_iterate(struct hash_map *map, void (*callback)(struct container *, void *data), void *data) { + for (uint32_t bucket_index = 0; bucket_index < HASH_MAP_SIZE; ++bucket_index) { + struct bucket *bucket = &map->buckets[bucket_index]; + hash_map_iterate_in_bucket(bucket, callback, data); + } +} + +typedef struct debug_context { + const char *filename; + uint32_t column; + uint32_t line; +} debug_context; + +static void error(debug_context context, const char *message, ...); +static void error_no_context(const char *message, ...); +static void error_args(debug_context context, const char *message, va_list args); +static void error_args_no_context(const char *message, va_list args); +static void check_function(bool test, debug_context context, const char *message, ...); +#define check(test, context, message, ...) \ + assert(test); \ + check_function(test, context, message, ##__VA_ARGS__) + +typedef enum { + LOG_LEVEL_INFO, + LOG_LEVEL_WARNING, + LOG_LEVEL_ERROR +} log_level_t; +static void kong_log(log_level_t log_level, const char *format, ...); +static void kong_log_args(log_level_t log_level, const char *format, va_list args); + +//// + +#define OP_SIZE(op, opmember) offsetof(opcode, opmember) + sizeof(op.opmember) +#define NO_FUNCTION 0xFFFFFFFF +#define NO_NAME 0 +#define NO_TYPE 0xFFFFFFFF +#define MAX_MEMBERS 1024 + +struct statement; + +typedef uint32_t global_id; + +typedef struct global_array { + global_id globals[256]; + bool readable[256]; + bool writable[256]; + size_t size; +} global_array; + +struct expression; + +typedef struct expressions { + struct expression *e[256]; + size_t size; +} expressions; + +typedef struct expression { + enum { + EXPRESSION_BINARY, + EXPRESSION_UNARY, + EXPRESSION_BOOLEAN, + EXPRESSION_FLOAT, + EXPRESSION_INT, + // EXPRESSION_STRING, + EXPRESSION_VARIABLE, + EXPRESSION_GROUPING, + EXPRESSION_CALL, + EXPRESSION_MEMBER, + EXPRESSION_ELEMENT + } kind; + + type_ref type; + + union { + struct { + struct expression *left; + operatorr op; + struct expression *right; + } binary; + struct { + operatorr op; + struct expression *right; + } unary; + bool boolean; + double number; + // char string[MAX_IDENTIFIER_SIZE]; + name_id variable; + uint32_t index; + struct expression *grouping; + struct { + name_id func_name; + expressions parameters; + } call; + struct { + struct expression *of; + name_id member_name; + } member; + struct { + struct expression *of; + struct expression *element_index; + } element; + }; +} expression; + +struct statement; + +typedef struct statements { + struct statement *s[256]; + size_t size; +} statements; + +typedef struct local_variable { + name_id name; + type_ref type; + uint64_t variable_id; +} local_variable; + +typedef struct local_variables { + local_variable v[256]; + size_t size; +} local_variables; + +typedef struct block { + struct block *parent; + local_variables vars; + statements statements; +} block; + +typedef struct statement { + enum { + STATEMENT_EXPRESSION, + STATEMENT_RETURN_EXPRESSION, + STATEMENT_IF, + STATEMENT_WHILE, + STATEMENT_DO_WHILE, + STATEMENT_BLOCK, + STATEMENT_LOCAL_VARIABLE + } kind; + + union { + expression *expression; + struct { + expression *test; + struct statement *if_block; + expression *else_tests[64]; + struct statement *else_blocks[64]; + uint16_t else_size; + } iffy; + struct { + expression *test; + struct statement *while_block; + } whiley; + block block; + struct { + local_variable var; + expression *init; + } local_variable; + }; +} statement; + +typedef struct definition { + enum { + DEFINITION_FUNCTION, + DEFINITION_STRUCT, + DEFINITION_CONST_CUSTOM, + DEFINITION_CONST_BASIC + } kind; + + union { + function_id function; + global_id global; + type_id type; + }; +} definition; + +typedef struct member { + name_id name; + type_ref type; + token value; +} member; + +typedef struct members { + member m[MAX_MEMBERS]; + size_t size; +} members; + +typedef struct type { + attribute_list attributes; + name_id name; + bool built_in; + members members; + type_id base; + uint32_t array_size; +} type; + +static void allocate_globals(void); +void _compile_function_block(opcodes *code, struct statement *block); +static variable allocate_variable(type_ref type, variable_kind kind); + +void _functions_init(void); +static function_id add_function(name_id name); +static function_id find_function(name_id name); +function *_get_function(function_id function); + +void _globals_init(void); +static global_id add_global(type_id type, attribute_list attributes, name_id name); +static global_id add_global_with_value(type_id type, attribute_list attributes, name_id name, global_value value); +static global *find_global(name_id name); +static global *get_global(global_id id); +static void assign_global_var(global_id id, uint64_t var_index); + +void _names_init(void); +static name_id add_name(char *name); +char *_get_name(name_id index); + +void _parse(const char *filename, tokens *tokens); +static token tokens_get(tokens *arr, size_t index); +tokens _tokenize(const char *filename, const char *source); + +void _resolve_types(void); +static void init_type_ref(type_ref *t, name_id name); +void _types_init(void); +static type_id add_type(name_id name); +static type_id add_full_type(type *t); +static type_id find_type_by_name(name_id name); +static type_id find_type_by_ref(type_ref *t); +static type *get_type(type_id t); + +static void kong_log(log_level_t level, const char *format, ...) { + va_list args; + va_start(args, format); + kong_log_args(level, format, args); + va_end(args); +} + +static void kong_log_args(log_level_t level, const char *format, va_list args) { +#ifdef WIN32 + { + char buffer[4096]; + vsnprintf(buffer, 4090, format, args); + strcat(buffer, "\r\n"); + OutputDebugStringA(buffer); + } +#endif + + { + char buffer[4096]; + vsnprintf(buffer, 4090, format, args); + strcat(buffer, "\n"); + fprintf(level == LOG_LEVEL_INFO ? stdout : stderr, "%s", buffer); + } +} + +static void debug_break(void) { +#ifndef NDEBUG +#if defined(_MSC_VER) + __debugbreak(); +#elif defined(__clang__) + __builtin_debugtrap(); +#else +#if defined(__aarch64__) + __asm__ volatile(".inst 0xd4200000"); +#elif defined(__x86_64__) + __asm__ volatile("int $0x03"); +#else + kong_log(LOG_LEVEL_WARNING, "Oh no, debug_break is not implemented for the current compiler and CPU."); +#endif +#endif +#endif +} + +static void error_args(debug_context context, const char *message, va_list args) { + char buffer[4096]; + if (context.filename != NULL) { + sprintf(buffer, "In column %i at line %i in %s: ", context.column + 1, context.line + 1, context.filename); + } + else { + sprintf(buffer, "In column %i at line %i: ", context.column + 1, context.line + 1); + } + strcat(buffer, message); + kong_log_args(LOG_LEVEL_ERROR, buffer, args); + debug_break(); + exit(1); +} + +static void error_args_no_context(const char *message, va_list args) { + kong_log_args(LOG_LEVEL_ERROR, message, args); + exit(1); +} + +static void error(debug_context context, const char *message, ...) { + va_list args; + va_start(args, message); + error_args(context, message, args); + va_end(args); +} + +static void error_no_context(const char *message, ...) { + va_list args; + va_start(args, message); + error_args_no_context(message, args); + va_end(args); +} + +static void check_function(bool test, debug_context context, const char *message, ...) { + if (!test) { + va_list args; + va_start(args, message); + error_args(context, message, args); + va_end(args); + } +} + +//// + +typedef enum modifier { + MODIFIER_IN, + // Out, +} modifier_t; + +typedef enum mode { + MODE_SELECT, + MODE_NUMBER, + // MODE_STRING, + MODE_OPERATOR, + MODE_IDENTIFIER, + MODE_LINE_COMMENT, + MODE_COMMENT +} mode; + +typedef struct modifiers { + modifier_t m[16]; + size_t size; +} modifiers_t; + +typedef struct tokenizer_state { + const char *iterator; + char next; + char next_next; + int line, column; + bool line_end; +} tokenizer_state; + +typedef struct block_ids { + uint64_t start; + uint64_t end; +} block_ids; + +typedef struct state { + tokens *tokens; + size_t index; + debug_context context; +} state_t; + +typedef struct tokenizer_buffer { + char *buf; + size_t current_size; + size_t max_size; + int column, line; +} tokenizer_buffer; + +typedef struct prefix { + char str[5]; + size_t size; +} prefix; + +struct { + char *key; + name_id value; +} *names_hash = NULL; + +allocated_global __allocated_globals[1024]; +size_t __allocated_globals_size = 0; +static const char all_names[1024 * 1024]; +static uint64_t next_variable_id = 1; +static variable all_variables[1024 * 1024]; +static function *functions = NULL; +static function_id functions_size = 128; +static function_id next_function_index = 0; +static global globals[1024]; +static global_id globals_size = 0; +static char *names = NULL; +static size_t names_size = 1024 * 1024; +static name_id names_index = 1; +static statement statements_buffer[8192]; +static int statement_index = 0; +static expression experessions_buffer[8192]; +static int expression_index = 0; +static type *types = NULL; +static type_id types_size = 1024; +static type_id next_type_index = 0; +type_id _void_id; +type_id _float_id; +type_id _int_id; +type_id _uint_id; +type_id _bool_id; +static type_id function_type_id; + +static definition parse_definition(state_t *state); +static statement *parse_statement(state_t *state, block *parent_block); +static expression *parse_expression(state_t *state); +static definition parse_struct(state_t *state); +static definition parse_function(state_t *state); +static definition parse_const(state_t *state, attribute_list attributes); +static void resolve_types_in_expression(statement *parent, expression *e); + +static allocated_global find_allocated_global(name_id name) { + for (size_t i = 0; i < __allocated_globals_size; ++i) { + if (name == __allocated_globals[i].g->name) { + return __allocated_globals[i]; + } + } + + allocated_global a; + a.g = NULL; + a.variable_id = 0; + return a; +} + +static variable find_local_var(block *b, name_id name) { + if (b == NULL) { + variable var; + var.index = 0; + init_type_ref(&var.type, NO_NAME); + return var; + } + + for (size_t i = 0; i < b->vars.size; ++i) { + if (b->vars.v[i].name == name) { + debug_context context = {0}; + check(b->vars.v[i].type.type != NO_TYPE, context, "Local variable does not have a type"); + variable var; + var.index = b->vars.v[i].variable_id; + var.type = b->vars.v[i].type; + var.kind = VARIABLE_LOCAL; + return var; + } + } + + return find_local_var(b->parent, name); +} + +static variable find_variable(block *parent, name_id name) { + variable local_var = find_local_var(parent, name); + if (local_var.index == 0) { + allocated_global global = find_allocated_global(name); + if (global.g->type != NO_TYPE && global.variable_id != 0) { + variable v; + init_type_ref(&v.type, NO_NAME); + v.type.type = global.g->type; + v.index = global.variable_id; + v.kind = VARIABLE_GLOBAL; + return v; + } + else { + debug_context context = {0}; + error(context, "Variable %s not found", _get_name(name)); + + variable v; + v.index = 0; + return v; + } + } + else { + return local_var; + } +} + +static variable allocate_variable(type_ref type, variable_kind kind) { + variable v; + v.index = next_variable_id; + v.type = type; + v.kind = kind; + all_variables[v.index] = v; + ++next_variable_id; + return v; +} + +static opcode *emit_op(opcodes *code, opcode *o) { + assert(code->size + o->size < OPCODES_SIZE); + + uint8_t *location = &code->o[code->size]; + + memcpy(&code->o[code->size], o, o->size); + + code->size += o->size; + + return (opcode *)location; +} + +static variable emit_expression(opcodes *code, block *parent, expression *e) { + switch (e->kind) { + case EXPRESSION_BINARY: { + expression *left = e->binary.left; + expression *right = e->binary.right; + + debug_context context = {0}; + + switch (e->binary.op) { + case OPERATOR_EQUALS: + case OPERATOR_NOT_EQUALS: + case OPERATOR_GREATER: + case OPERATOR_GREATER_EQUAL: + case OPERATOR_LESS: + case OPERATOR_LESS_EQUAL: + case OPERATOR_AND: + case OPERATOR_OR: { + variable right_var = emit_expression(code, parent, right); + variable left_var = emit_expression(code, parent, left); + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = _bool_id; + variable result_var = allocate_variable(t, VARIABLE_INTERNAL); + + opcode o; + switch (e->binary.op) { + case OPERATOR_EQUALS: + o.type = OPCODE_EQUALS; + break; + case OPERATOR_NOT_EQUALS: + o.type = OPCODE_NOT_EQUALS; + break; + case OPERATOR_GREATER: + o.type = OPCODE_GREATER; + break; + case OPERATOR_GREATER_EQUAL: + o.type = OPCODE_GREATER_EQUAL; + break; + case OPERATOR_LESS: + o.type = OPCODE_LESS; + break; + case OPERATOR_LESS_EQUAL: + o.type = OPCODE_LESS_EQUAL; + break; + case OPERATOR_AND: + o.type = OPCODE_AND; + break; + case OPERATOR_OR: + o.type = OPCODE_OR; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_binary); + o.op_binary.right = right_var; + o.op_binary.left = left_var; + o.op_binary.result = result_var; + emit_op(code, &o); + + return result_var; + } + case OPERATOR_MINUS: + case OPERATOR_PLUS: + case OPERATOR_DIVIDE: + case OPERATOR_MULTIPLY: + case OPERATOR_MOD: + case OPERATOR_BITWISE_XOR: + case OPERATOR_BITWISE_AND: + case OPERATOR_BITWISE_OR: + case OPERATOR_LEFT_SHIFT: + case OPERATOR_RIGHT_SHIFT: { + variable right_var = emit_expression(code, parent, right); + variable left_var = emit_expression(code, parent, left); + variable result_var = allocate_variable(e->type, VARIABLE_INTERNAL); + + opcode o; + switch (e->binary.op) { + case OPERATOR_MINUS: + o.type = OPCODE_SUB; + break; + case OPERATOR_PLUS: + o.type = OPCODE_ADD; + break; + case OPERATOR_DIVIDE: + o.type = OPCODE_DIVIDE; + break; + case OPERATOR_MULTIPLY: + o.type = OPCODE_MULTIPLY; + break; + case OPERATOR_MOD: + o.type = OPCODE_MOD; + break; + case OPERATOR_BITWISE_XOR: + o.type = OPCODE_BITWISE_XOR; + break; + case OPERATOR_BITWISE_AND: + o.type = OPCODE_BITWISE_AND; + break; + case OPERATOR_BITWISE_OR: + o.type = OPCODE_BITWISE_OR; + break; + case OPERATOR_LEFT_SHIFT: + o.type = OPCODE_LEFT_SHIFT; + break; + case OPERATOR_RIGHT_SHIFT: + o.type = OPCODE_RIGHT_SHIFT; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_binary); + o.op_binary.right = right_var; + o.op_binary.left = left_var; + o.op_binary.result = result_var; + emit_op(code, &o); + + return result_var; + } + case OPERATOR_NOT: { + error(context, "! is not a binary operator"); + } + case OPERATOR_ASSIGN: + case OPERATOR_MINUS_ASSIGN: + case OPERATOR_PLUS_ASSIGN: + case OPERATOR_DIVIDE_ASSIGN: + case OPERATOR_MULTIPLY_ASSIGN: { + variable v = emit_expression(code, parent, right); + + switch (left->kind) { + case EXPRESSION_VARIABLE: { + opcode o; + switch (e->binary.op) { + case OPERATOR_ASSIGN: + o.type = OPCODE_STORE_VARIABLE; + break; + case OPERATOR_MINUS_ASSIGN: + o.type = OPCODE_SUB_AND_STORE_VARIABLE; + break; + case OPERATOR_PLUS_ASSIGN: + o.type = OPCODE_ADD_AND_STORE_VARIABLE; + break; + case OPERATOR_DIVIDE_ASSIGN: + o.type = OPCODE_DIVIDE_AND_STORE_VARIABLE; + break; + case OPERATOR_MULTIPLY_ASSIGN: + o.type = OPCODE_MULTIPLY_AND_STORE_VARIABLE; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_store_var); + o.op_store_var.from = v; + o.op_store_var.to = find_variable(parent, left->variable); + emit_op(code, &o); + break; + } + case EXPRESSION_ELEMENT: + case EXPRESSION_MEMBER: { + opcode o; + switch (e->binary.op) { + case OPERATOR_ASSIGN: + o.type = OPCODE_STORE_ACCESS_LIST; + break; + case OPERATOR_MINUS_ASSIGN: + o.type = OPCODE_SUB_AND_STORE_ACCESS_LIST; + break; + case OPERATOR_PLUS_ASSIGN: + o.type = OPCODE_ADD_AND_STORE_ACCESS_LIST; + break; + case OPERATOR_DIVIDE_ASSIGN: + o.type = OPCODE_DIVIDE_AND_STORE_ACCESS_LIST; + break; + case OPERATOR_MULTIPLY_ASSIGN: + o.type = OPCODE_MULTIPLY_AND_STORE_ACCESS_LIST; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_store_access_list); + o.op_store_access_list.from = v; + + expression *of = left; + + access access_list[64]; + uint32_t access_list_size = 0; + + while (of->kind == EXPRESSION_ELEMENT || of->kind == EXPRESSION_MEMBER) { + access *a = &access_list[access_list_size]; + a->type = of->type.type; + + switch (of->kind) { + case EXPRESSION_ELEMENT: + a->kind = ACCESS_ELEMENT; + a->access_element.index = emit_expression(code, parent, of->element.element_index); + + of = of->element.of; + + break; + case EXPRESSION_MEMBER: + a->kind = ACCESS_MEMBER; + a->access_member.name = of->member.member_name; + + of = of->member.of; + + break; + default: + assert(false); + break; + } + + access_list_size += 1; + } + + o.op_store_access_list.access_list_size = access_list_size; + + for (uint32_t access_index = 0; access_index < access_list_size; ++access_index) { + o.op_store_access_list.access_list[access_list_size - access_index - 1] = access_list[access_index]; + } + + o.op_store_access_list.to = emit_expression(code, parent, of); + + emit_op(code, &o); + break; + } + default: { + debug_context context = {0}; + error(context, "Expected a variable or an access"); + } + } + + return v; + } + } + break; + } + case EXPRESSION_UNARY: { + debug_context context = {0}; + switch (e->unary.op) { + case OPERATOR_EQUALS: + error(context, "not implemented"); + case OPERATOR_NOT_EQUALS: + error(context, "not implemented"); + case OPERATOR_GREATER: + error(context, "not implemented"); + case OPERATOR_GREATER_EQUAL: + error(context, "not implemented"); + case OPERATOR_LESS: + error(context, "not implemented"); + case OPERATOR_LESS_EQUAL: + error(context, "not implemented"); + case OPERATOR_MINUS: { + variable v = emit_expression(code, parent, e->unary.right); + opcode o; + o.type = OPCODE_NEGATE; + o.size = OP_SIZE(o, op_negate); + o.op_negate.from = v; + o.op_negate.to = allocate_variable(v.type, VARIABLE_INTERNAL); + emit_op(code, &o); + return o.op_negate.to; + } + case OPERATOR_PLUS: + error(context, "not implemented"); + case OPERATOR_DIVIDE: + error(context, "not implemented"); + case OPERATOR_MULTIPLY: + error(context, "not implemented"); + case OPERATOR_NOT: { + variable v = emit_expression(code, parent, e->unary.right); + opcode o; + o.type = OPCODE_NOT; + o.size = OP_SIZE(o, op_not); + o.op_not.from = v; + o.op_not.to = allocate_variable(v.type, VARIABLE_INTERNAL); + emit_op(code, &o); + return o.op_not.to; + } + case OPERATOR_OR: + error(context, "not implemented"); + case OPERATOR_BITWISE_XOR: + error(context, "not implemented"); + case OPERATOR_BITWISE_AND: + error(context, "not implemented"); + case OPERATOR_BITWISE_OR: + error(context, "not implemented"); + case OPERATOR_LEFT_SHIFT: + error(context, "not implemented"); + case OPERATOR_RIGHT_SHIFT: + error(context, "not implemented"); + case OPERATOR_AND: + error(context, "not implemented"); + case OPERATOR_MOD: + error(context, "not implemented"); + case OPERATOR_ASSIGN: + error(context, "not implemented"); + case OPERATOR_PLUS_ASSIGN: + case OPERATOR_MINUS_ASSIGN: + case OPERATOR_MULTIPLY_ASSIGN: + case OPERATOR_DIVIDE_ASSIGN: + error(context, "not implemented"); + } + } + case EXPRESSION_BOOLEAN: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = _float_id; + variable v = allocate_variable(t, VARIABLE_INTERNAL); + + opcode o; + o.type = OPCODE_LOAD_BOOL_CONSTANT; + o.size = OP_SIZE(o, op_load_bool_constant); + o.op_load_bool_constant.boolean = e->boolean; + o.op_load_bool_constant.to = v; + emit_op(code, &o); + + return v; + } + case EXPRESSION_FLOAT: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = _float_id; + variable v = allocate_variable(t, VARIABLE_INTERNAL); + + opcode o; + o.type = OPCODE_LOAD_FLOAT_CONSTANT; + o.size = OP_SIZE(o, op_load_float_constant); + o.op_load_float_constant.number = (float)e->number; + o.op_load_float_constant.to = v; + emit_op(code, &o); + + return v; + } + case EXPRESSION_INT: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = _int_id; + variable v = allocate_variable(t, VARIABLE_INTERNAL); + + opcode o; + o.type = OPCODE_LOAD_INT_CONSTANT; + o.size = OP_SIZE(o, op_load_float_constant); + o.op_load_int_constant.number = (int)e->number; + o.op_load_int_constant.to = v; + emit_op(code, &o); + + return v; + } + // case EXPRESSION_STRING: + // error("not implemented", 0, 0); + case EXPRESSION_VARIABLE: { + return find_variable(parent, e->variable); + } + case EXPRESSION_GROUPING: { + return emit_expression(code, parent, e->grouping); + } + case EXPRESSION_CALL: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = e->type.type; + variable v = allocate_variable(t, VARIABLE_INTERNAL); + + opcode o; + o.type = OPCODE_CALL; + o.size = OP_SIZE(o, op_call); + o.op_call.func = e->call.func_name; + o.op_call.var = v; + + debug_context context = {0}; + check(e->call.parameters.size <= sizeof(o.op_call.parameters) / sizeof(variable), context, "Call parameters missized"); + for (size_t i = 0; i < e->call.parameters.size; ++i) { + o.op_call.parameters[i] = emit_expression(code, parent, e->call.parameters.e[i]); + } + o.op_call.parameters_size = (uint8_t)e->call.parameters.size; + + emit_op(code, &o); + + return v; + } + case EXPRESSION_ELEMENT: + case EXPRESSION_MEMBER: { + opcode o; + o.type = OPCODE_LOAD_ACCESS_LIST; + o.size = OP_SIZE(o, op_load_access_list); + + variable v = allocate_variable(e->type, VARIABLE_INTERNAL); + o.op_load_access_list.to = v; + + expression *of = e; + + access access_list[64]; + uint32_t access_list_size = 0; + + while (of->kind == EXPRESSION_ELEMENT || of->kind == EXPRESSION_MEMBER) { + access *a = &access_list[access_list_size]; + a->type = of->type.type; + + switch (of->kind) { + case EXPRESSION_ELEMENT: + a->kind = ACCESS_ELEMENT; + a->access_element.index = emit_expression(code, parent, of->element.element_index); + + of = of->element.of; + + break; + case EXPRESSION_MEMBER: + a->kind = ACCESS_MEMBER; + a->access_member.name = of->member.member_name; + + of = of->member.of; + + break; + default: + assert(false); + break; + } + + access_list_size += 1; + } + + o.op_load_access_list.access_list_size = access_list_size; + + for (uint32_t access_index = 0; access_index < access_list_size; ++access_index) { + o.op_load_access_list.access_list[access_list_size - access_index - 1] = access_list[access_index]; + } + + o.op_load_access_list.from = emit_expression(code, parent, of); + + emit_op(code, &o); + + return v; + } + default: { + debug_context context = {0}; + error(context, "not implemented"); + } + } + + { + debug_context context = {0}; + error(context, "Supposedly unreachable code reached"); + variable v; + v.index = 0; + return v; + } +} + +static block_ids emit_statement(opcodes *code, block *parent, statement *statement) { + switch (statement->kind) { + case STATEMENT_EXPRESSION: + emit_expression(code, parent, statement->expression); + break; + case STATEMENT_RETURN_EXPRESSION: { + opcode o; + o.type = OPCODE_RETURN; + variable v = emit_expression(code, parent, statement->expression); + if (v.index == 0) { + o.size = offsetof(opcode, op_return); + } + else { + o.size = OP_SIZE(o, op_return); + o.op_return.var = v; + } + emit_op(code, &o); + break; + } + case STATEMENT_IF: { + struct previous_condition { + variable condition; + variable summed_condition; + }; + struct previous_condition previous_conditions[64] = {0}; + uint8_t previous_conditions_size = 0; + + { + opcode o; + o.type = OPCODE_IF; + o.size = OP_SIZE(o, op_if); + + variable initial_condition = emit_expression(code, parent, statement->iffy.test); + + o.op_if.condition = initial_condition; + + opcode *written_opcode = emit_op(code, &o); + + previous_conditions[previous_conditions_size].condition = initial_condition; + previous_conditions_size += 1; + + block_ids ids = emit_statement(code, parent, statement->iffy.if_block); + + written_opcode->op_if.start_id = ids.start; + written_opcode->op_if.end_id = ids.end; + } + + for (uint16_t i = 0; i < statement->iffy.else_size; ++i) { + variable current_condition; + { + opcode o; + o.type = OPCODE_NOT; + o.size = OP_SIZE(o, op_not); + o.op_not.from = previous_conditions[previous_conditions_size - 1].condition; + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = _bool_id; + current_condition = allocate_variable(t, VARIABLE_INTERNAL); + o.op_not.to = current_condition; + emit_op(code, &o); + } + + variable summed_condition; + if (previous_conditions_size == 1) { + summed_condition = previous_conditions[0].summed_condition = current_condition; + } + else { + opcode o; + o.type = OPCODE_AND; + o.size = OP_SIZE(o, op_binary); + o.op_binary.left = previous_conditions[previous_conditions_size - 2].summed_condition; + o.op_binary.right = current_condition; + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = _bool_id; + summed_condition = allocate_variable(t, VARIABLE_INTERNAL); + o.op_binary.result = summed_condition; + emit_op(code, &o); + } + + opcode o; + o.type = OPCODE_IF; + o.size = OP_SIZE(o, op_if); + + if (statement->iffy.else_tests[i] != NULL) { + variable v = emit_expression(code, parent, statement->iffy.else_tests[i]); + + variable else_test; + { + opcode o; + o.type = OPCODE_AND; + o.size = OP_SIZE(o, op_binary); + o.op_binary.left = summed_condition; + o.op_binary.right = v; + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = _bool_id; + else_test = allocate_variable(t, VARIABLE_INTERNAL); + o.op_binary.result = else_test; + emit_op(code, &o); + } + + o.op_if.condition = else_test; + + previous_conditions[previous_conditions_size].condition = v; + previous_conditions_size += 1; + } + else { + o.op_if.condition = summed_condition; + } + + { + opcode *written_opcode = emit_op(code, &o); + + block_ids ids = emit_statement(code, parent, statement->iffy.else_blocks[i]); + + written_opcode->op_if.start_id = ids.start; + written_opcode->op_if.end_id = ids.end; + } + } + + break; + } + case STATEMENT_WHILE: { + uint64_t start_id = next_variable_id; + ++next_variable_id; + uint64_t continue_id = next_variable_id; + ++next_variable_id; + uint64_t end_id = next_variable_id; + ++next_variable_id; + + { + opcode o; + o.type = OPCODE_WHILE_START; + o.op_while_start.start_id = start_id; + o.op_while_start.continue_id = continue_id; + o.op_while_start.end_id = end_id; + o.size = OP_SIZE(o, op_while_start); + emit_op(code, &o); + } + + { + opcode o; + o.type = OPCODE_WHILE_CONDITION; + o.size = OP_SIZE(o, op_while); + + variable v = emit_expression(code, parent, statement->whiley.test); + + o.op_while.condition = v; + o.op_while.end_id = end_id; + + emit_op(code, &o); + } + + emit_statement(code, parent, statement->whiley.while_block); + + { + opcode o; + o.type = OPCODE_WHILE_END; + o.op_while_end.start_id = start_id; + o.op_while_end.continue_id = continue_id; + o.op_while_end.end_id = end_id; + o.size = OP_SIZE(o, op_while_end); + emit_op(code, &o); + } + + break; + } + case STATEMENT_DO_WHILE: { + uint64_t start_id = next_variable_id; + ++next_variable_id; + uint64_t continue_id = next_variable_id; + ++next_variable_id; + uint64_t end_id = next_variable_id; + ++next_variable_id; + + { + opcode o; + o.type = OPCODE_WHILE_START; + o.op_while_start.start_id = start_id; + o.op_while_start.continue_id = continue_id; + o.op_while_start.end_id = end_id; + o.size = OP_SIZE(o, op_while_start); + emit_op(code, &o); + } + + emit_statement(code, parent, statement->whiley.while_block); + + { + opcode o; + o.type = OPCODE_WHILE_CONDITION; + o.size = OP_SIZE(o, op_while); + + variable v = emit_expression(code, parent, statement->whiley.test); + + o.op_while.condition = v; + o.op_while.end_id = end_id; + + emit_op(code, &o); + } + + { + opcode o; + o.type = OPCODE_WHILE_END; + o.op_while_end.start_id = start_id; + o.op_while_end.continue_id = continue_id; + o.op_while_end.end_id = end_id; + o.size = OP_SIZE(o, op_while_end); + emit_op(code, &o); + } + + break; + } + case STATEMENT_BLOCK: { + for (size_t i = 0; i < statement->block.vars.size; ++i) { + variable var = allocate_variable(statement->block.vars.v[i].type, VARIABLE_LOCAL); + statement->block.vars.v[i].variable_id = var.index; + } + + uint64_t start_block_id = next_variable_id; + ++next_variable_id; + + uint64_t end_block_id = next_variable_id; + ++next_variable_id; + + { + opcode o; + o.type = OPCODE_BLOCK_START; + o.op_block.id = start_block_id; + o.size = OP_SIZE(o, op_block); + emit_op(code, &o); + } + + for (size_t i = 0; i < statement->block.statements.size; ++i) { + emit_statement(code, &statement->block, statement->block.statements.s[i]); + } + + { + opcode o; + o.type = OPCODE_BLOCK_END; + o.op_block.id = end_block_id; + o.size = OP_SIZE(o, op_block); + emit_op(code, &o); + } + + block_ids ids; + ids.start = start_block_id; + ids.end = end_block_id; + return ids; + } + case STATEMENT_LOCAL_VARIABLE: { + opcode o; + o.type = OPCODE_VAR; + o.size = OP_SIZE(o, op_var); + + variable init_var = {0}; + if (statement->local_variable.init != NULL) { + init_var = emit_expression(code, parent, statement->local_variable.init); + } + + variable local_var = find_local_var(parent, statement->local_variable.var.name); + statement->local_variable.var.variable_id = local_var.index; + o.op_var.var.index = statement->local_variable.var.variable_id; + debug_context context = {0}; + check(statement->local_variable.var.type.type != NO_TYPE, context, "Local var has no type"); + o.op_var.var.type = statement->local_variable.var.type; + emit_op(code, &o); + + if (statement->local_variable.init != NULL) { + opcode o; + o.type = OPCODE_STORE_VARIABLE; + o.size = OP_SIZE(o, op_store_var); + + o.op_store_var.from = init_var; + o.op_store_var.to = local_var; + + emit_op(code, &o); + } + + break; + } + } + + block_ids ids; + ids.start = 0; + ids.end = 0; + return ids; +} + +static void allocate_globals(void) { + for (global_id i = 0; get_global(i) != NULL && get_global(i)->type != NO_TYPE; ++i) { + global *g = get_global(i); + + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = g->type; + variable v = allocate_variable(t, VARIABLE_GLOBAL); + __allocated_globals[__allocated_globals_size].g = g; + __allocated_globals[__allocated_globals_size].variable_id = v.index; + __allocated_globals_size += 1; + + assign_global_var(i, v.index); + } +} + +void _compile_function_block(opcodes *code, struct statement *block) { + if (block == NULL) { + // built-in + return; + } + + if (block->kind != STATEMENT_BLOCK) { + debug_context context = {0}; + error(context, "Expected a block"); + } + for (size_t i = 0; i < block->block.vars.size; ++i) { + variable var = allocate_variable(block->block.vars.v[i].type, VARIABLE_LOCAL); + block->block.vars.v[i].variable_id = var.index; + } + for (size_t i = 0; i < block->block.statements.size; ++i) { + emit_statement(code, &block->block, block->block.statements.s[i]); + } +} + +static void add_func_int(char *name) { + function_id func = add_function(add_name(name)); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("int")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_float(char *name) { + function_id func = add_function(add_name(name)); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("float")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_uint(char *name) { + function_id func = add_function(add_name(name)); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("uint")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_float_float(char *name) { + function_id func = add_function(add_name(name)); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("float")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("a"); + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size = 1; + f->block = NULL; +} + +void _functions_init(void) { + function *new_functions = realloc(functions, functions_size * sizeof(function)); + debug_context context = {0}; + check(new_functions != NULL, context, "Could not allocate functions"); + functions = new_functions; + next_function_index = 0; + + { + function_id func = add_function(add_name("float")); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("float")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("int")); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("int")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("int")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("uint")); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("uint")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("bool")); + function *f = _get_function(func); + init_type_ref(&f->return_type, add_name("bool")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("bool")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + add_func_float_float("print"); + // add_func_float_float("sin"); + // add_func_float_float("cos"); +} + +static void grow_functions_if_needed(uint64_t size) { + while (size >= functions_size) { + functions_size *= 2; + function *new_functions = realloc(functions, functions_size * sizeof(function)); + debug_context context = {0}; + check(new_functions != NULL, context, "Could not allocate functions"); + functions = new_functions; + } +} + +static function_id add_function(name_id name) { + grow_functions_if_needed(next_function_index + 1); + + function_id f = next_function_index; + ++next_function_index; + + functions[f].name = name; + functions[f].attributes.attributes_count = 0; + init_type_ref(&functions[f].return_type, NO_NAME); + functions[f].parameters_size = 0; + memset(functions[f].parameter_attributes, 0, sizeof(functions[f].parameter_attributes)); + functions[f].block = NULL; + memset(functions[f].code.o, 0, sizeof(functions[f].code.o)); + functions[f].code.size = 0; + + return f; +} + +function *_get_function(function_id function) { + if (function >= next_function_index) { + return NULL; + } + return &functions[function]; +} + +void _globals_init(void) { + global_value int_value; + int_value.kind = GLOBAL_VALUE_INT; + + attribute_list attributes = {0}; + + // int_value.value.ints[0] = 0; + // add_global_with_value(_float_id, attributes, add_name("COMPARE_ALWAYS"), int_value); + + // global_value uint_value; + // uint_value.kind = GLOBAL_VALUE_UINT; + + // uint_value.value.uints[0] = 0; + // add_global_with_value(_uint_id, attributes, add_name("TEXTURE_FORMAT_R8_UNORM"), uint_value); +} + +static global_id add_global(type_id type, attribute_list attributes, name_id name) { + uint32_t index = globals_size; + globals[index].name = name; + globals[index].type = type; + globals[index].var_index = 0; + globals[index].value.kind = GLOBAL_VALUE_NONE; + globals[index].attributes = attributes; + globals[index].usage = 0; + globals_size += 1; + return index; +} + +static global_id add_global_with_value(type_id type, attribute_list attributes, name_id name, global_value value) { + uint32_t index = globals_size; + globals[index].name = name; + globals[index].type = type; + globals[index].var_index = 0; + globals[index].value = value; + globals[index].attributes = attributes; + globals[index].usage = 0; + globals_size += 1; + return index; +} + +static global *find_global(name_id name) { + for (uint32_t i = 0; i < globals_size; ++i) { + if (globals[i].name == name) { + return &globals[i]; + } + } + + return NULL; +} + +static global *get_global(global_id id) { + if (id >= globals_size) { + return NULL; + } + + return &globals[id]; +} + +static void assign_global_var(global_id id, uint64_t var_index) { + debug_context context = {0}; + check(id < globals_size, context, "Encountered a global with a weird id"); + globals[id].var_index = var_index; +} + +void _names_init(void) { + char *new_names = realloc(names, names_size); + debug_context context = {0}; + check(new_names != NULL, context, "Could not allocate names"); + names = new_names; + names[0] = 0; // make NO_NAME a proper string + + sh_new_arena(names_hash); // TODO: Get rid of this by using indices internally in the hash-map so it can survive grow_names_if_needed +} + +static void grow_names_if_needed(size_t size) { + while (size >= names_size) { + names_size *= 2; + char *new_names = realloc(names, names_size); + debug_context context = {0}; + check(new_names != NULL, context, "Could not allocate names"); + names = new_names; + } +} + +static name_id add_name(char *name) { + ptrdiff_t old_id_index = shgeti(names_hash, name); + + if (old_id_index >= 0) { + return names_hash[old_id_index].value; + } + + size_t length = strlen(name); + + grow_names_if_needed(names_index + length + 1); + + name_id id = names_index; + + memcpy(&names[id], name, length); + names[id + length] = 0; + + names_index += length + 1; + + shput(names_hash, &names[id], id); + + return id; +} + +char *_get_name(name_id id) { + debug_context context = {0}; + check(id < names_index, context, "Encountered a weird name id"); + return &names[id]; +} + +static statement *statement_allocate(void) { + //// + // statement *s = (statement *)malloc(sizeof(statement)); + statement *s = &statements_buffer[statement_index]; + statement_index++; + //// + debug_context context = {0}; + check(s != NULL, context, "Could not allocate statement"); + return s; +} + +// static void statement_free(statement *statement) { +// free(statement); +// } + +static void statements_init(statements *statements) { + statements->size = 0; +} + +static void statements_add(statements *statements, statement *statement) { + statements->s[statements->size] = statement; + statements->size += 1; +} + +static expression *expression_allocate(void) { + //// + // expression *e = (expression *)malloc(sizeof(expression)); + expression *e = &experessions_buffer[expression_index]; + expression_index++; + //// + debug_context context = {0}; + check(e != NULL, context, "Could not allocate expression"); + init_type_ref(&e->type, NO_NAME); + return e; +} + +// static void expression_free(expression *expression) { +// free(expression); +// } + +static token current(state_t *state) { + token token = tokens_get(state->tokens, state->index); + return token; +} + +static void update_debug_context(state_t *state) { + state->context.column = current(state).column; + state->context.line = current(state).line; +} + +static void advance_state(state_t *state) { + state->index += 1; + update_debug_context(state); +} + +static void match_token(state_t *state, int token, const char *error_message) { + int current_token = current(state).kind; + if (current_token != token) { + error(state->context, error_message); + } +} + +static void match_token_identifier(state_t *state) { + if (current(state).kind != TOKEN_IDENTIFIER) { + error(state->context, "Expected an identifier"); + } +} + +void _parse(const char *filename, tokens *tokens) { + state_t state = {0}; + state.context.filename = filename; + state.tokens = tokens; + state.index = 0; + + for (;;) { + token token = current(&state); + if (token.kind == TOKEN_NONE) { + return; + } + else { + parse_definition(&state); + } + } +} + +static statement *parse_block(state_t *state, block *parent_block) { + match_token(state, TOKEN_LEFT_CURLY, "Expected an opening curly bracket"); + advance_state(state); + + statements statements; + statements_init(&statements); + + statement *new_block = statement_allocate(); + new_block->kind = STATEMENT_BLOCK; + new_block->block.parent = parent_block; + new_block->block.vars.size = 0; + + for (;;) { + switch (current(state).kind) { + case TOKEN_RIGHT_CURLY: { + advance_state(state); + new_block->block.statements = statements; + return new_block; + } + case TOKEN_NONE: { + update_debug_context(state); + error(state->context, "File ended before a block ended"); + return NULL; + } + default: + statements_add(&statements, parse_statement(state, &new_block->block)); + break; + } + } +} + +// static void modifiers_init(modifiers_t *modifiers) { +// modifiers->size = 0; +// } + +// static void modifiers_add(modifiers_t *modifiers, modifier_t modifier) { +// modifiers->m[modifiers->size] = modifier; +// modifiers->size += 1; +// } + +static definition parse_definition(state_t *state) { + attribute_list attributes = {0}; + + switch (current(state).kind) { + case TOKEN_STRUCT: { + definition structy = parse_struct(state); + get_type(structy.type)->attributes = attributes; + return structy; + } + case TOKEN_FUNCTION: { + definition d = parse_function(state); + function *f = _get_function(d.function); + f->attributes = attributes; + return d; + } + case TOKEN_CONST: { + definition d = parse_const(state, attributes); + return d; + } + default: { + update_debug_context(state); + error(state->context, "Expected a struct, a function or a const"); + + definition d = {0}; + return d; + } + } +} + +static type_ref parse_type_ref(state_t *state) { + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + token type_name = current(state); + advance_state(state); + + uint32_t array_size = 0; + if (current(state).kind == TOKEN_LEFT_SQUARE) { + advance_state(state); + if (current(state).kind == TOKEN_INT) { + array_size = (uint32_t)current(state).number; + if (array_size == 0) { + error(state->context, "Array size of 0 is not allowed"); + } + advance_state(state); + } + else { + array_size = UINT32_MAX; + } + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); + advance_state(state); + } + + type_ref t; + init_type_ref(&t, type_name.identifier); + t.unresolved.array_size = array_size; + return t; +} + +static statement *parse_statement(state_t *state, block *parent_block) { + switch (current(state).kind) { + case TOKEN_IF: { + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *if_block = parse_statement(state, parent_block); + statement *s = statement_allocate(); + s->kind = STATEMENT_IF; + s->iffy.test = test; + s->iffy.if_block = if_block; + + s->iffy.else_size = 0; + + while (current(state).kind == TOKEN_ELSE) { + advance_state(state); + + if (current(state).kind == TOKEN_IF) { + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *if_block = parse_statement(state, parent_block); + + s->iffy.else_tests[s->iffy.else_size] = test; + s->iffy.else_blocks[s->iffy.else_size] = if_block; + } + else { + statement *else_block = parse_statement(state, parent_block); + s->iffy.else_tests[s->iffy.else_size] = NULL; + s->iffy.else_blocks[s->iffy.else_size] = else_block; + } + + s->iffy.else_size += 1; + assert(s->iffy.else_size < 64); + } + + return s; + } + case TOKEN_WHILE: { + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *while_block = parse_statement(state, parent_block); + + statement *s = statement_allocate(); + s->kind = STATEMENT_WHILE; + s->whiley.test = test; + s->whiley.while_block = while_block; + + return s; + } + case TOKEN_DO: { + advance_state(state); + + statement *do_block = parse_statement(state, parent_block); + + statement *s = statement_allocate(); + s->kind = STATEMENT_DO_WHILE; + s->whiley.while_block = do_block; + + match_token(state, TOKEN_WHILE, "Expected \"while\""); + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + s->whiley.test = test; + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + return s; + } + case TOKEN_FOR: { + statements outer_block_statements; + statements_init(&outer_block_statements); + + statement *outer_block = statement_allocate(); + outer_block->kind = STATEMENT_BLOCK; + outer_block->block.parent = parent_block; + outer_block->block.vars.size = 0; + outer_block->block.statements = outer_block_statements; + + advance_state(state); + + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + statement *pre = parse_statement(state, &outer_block->block); + statements_add(&outer_block->block.statements, pre); + + expression *test = parse_expression(state); + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + expression *post_expression = parse_expression(state); + + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *inner_block = parse_statement(state, &outer_block->block); + + statement *post_statement = statement_allocate(); + post_statement->kind = STATEMENT_EXPRESSION; + post_statement->expression = post_expression; + + statements_add(&inner_block->block.statements, post_statement); + + statement *s = statement_allocate(); + s->kind = STATEMENT_WHILE; + s->whiley.test = test; + s->whiley.while_block = inner_block; + + statements_add(&outer_block->block.statements, s); + + return outer_block; + } + case TOKEN_LEFT_CURLY: { + return parse_block(state, parent_block); + } + case TOKEN_VAR: { + advance_state(state); + + match_token_identifier(state); + token name = current(state); + advance_state(state); + + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + + type_ref type = parse_type_ref(state); + + expression *init = NULL; + + if (current(state).kind == TOKEN_OPERATOR) { + check(current(state).op == OPERATOR_ASSIGN, state->context, "Expected an assign"); + advance_state(state); + init = parse_expression(state); + } + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + statement *statement = statement_allocate(); + statement->kind = STATEMENT_LOCAL_VARIABLE; + statement->local_variable.var.name = name.identifier; + statement->local_variable.var.type = type; + statement->local_variable.var.variable_id = 0; + statement->local_variable.init = init; + return statement; + } + case TOKEN_RETURN: { + advance_state(state); + + expression *expr = parse_expression(state); + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + statement *statement = statement_allocate(); + statement->kind = STATEMENT_RETURN_EXPRESSION; + statement->expression = expr; + return statement; + } + default: { + expression *expr = parse_expression(state); + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + statement *statement = statement_allocate(); + statement->kind = STATEMENT_EXPRESSION; + statement->expression = expr; + return statement; + } + } +} + +static expression *parse_assign(state_t *state); + +static expression *parse_expression(state_t *state) { + return parse_assign(state); +} + +static expression *parse_logical(state_t *state); + +static expression *parse_assign(state_t *state) { + expression *expr = parse_logical(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_ASSIGN || op == OPERATOR_MINUS_ASSIGN || op == OPERATOR_PLUS_ASSIGN || op == OPERATOR_DIVIDE_ASSIGN || + op == OPERATOR_MULTIPLY_ASSIGN) { + advance_state(state); + expression *right = parse_logical(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_bitwise(state_t *state); + +static expression *parse_logical(state_t *state) { + expression *expr = parse_bitwise(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_OR || op == OPERATOR_AND) { + advance_state(state); + expression *right = parse_bitwise(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_equality(state_t *state); + +static expression *parse_bitwise(state_t *state) { + expression *expr = parse_equality(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_BITWISE_XOR || op == OPERATOR_BITWISE_OR || op == OPERATOR_BITWISE_AND) { + advance_state(state); + expression *right = parse_equality(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_comparison(state_t *state); + +static expression *parse_equality(state_t *state) { + expression *expr = parse_comparison(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_EQUALS || op == OPERATOR_NOT_EQUALS) { + advance_state(state); + expression *right = parse_comparison(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_shift(state_t *state); + +static expression *parse_comparison(state_t *state) { + expression *expr = parse_shift(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_GREATER || op == OPERATOR_GREATER_EQUAL || op == OPERATOR_LESS || op == OPERATOR_LESS_EQUAL) { + advance_state(state); + expression *right = parse_shift(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_addition(state_t *state); + +static expression *parse_shift(state_t *state) { + expression *expr = parse_addition(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_LEFT_SHIFT || op == OPERATOR_RIGHT_SHIFT) { + advance_state(state); + expression *right = parse_addition(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_multiplication(state_t *state); + +static expression *parse_addition(state_t *state) { + expression *expr = parse_multiplication(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_MINUS || op == OPERATOR_PLUS) { + advance_state(state); + expression *right = parse_multiplication(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_unary(state_t *state); + +static expression *parse_multiplication(state_t *state) { + expression *expr = parse_unary(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_DIVIDE || op == OPERATOR_MULTIPLY || op == OPERATOR_MOD) { + advance_state(state); + expression *right = parse_unary(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_primary(state_t *state); + +static expression *parse_unary(state_t *state) { + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_NOT || op == OPERATOR_MINUS) { + advance_state(state); + expression *right = parse_unary(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_UNARY; + expression->unary.op = op; + expression->unary.right = right; + return expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return parse_primary(state); +} + +static expression *parse_member_or_element_access(state_t *state, expression *of) { + if (current(state).kind == TOKEN_DOT) { + advance_state(state); + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + + token token = current(state); + + advance_state(state); + + expression *member = expression_allocate(); + member->kind = EXPRESSION_MEMBER; + member->member.of = of; + member->member.member_name = token.identifier; + + expression *sub = parse_member_or_element_access(state, member); + + return sub; + } + else if (current(state).kind == TOKEN_LEFT_SQUARE) { + advance_state(state); + + expression *index = parse_expression(state); + + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); + + advance_state(state); + + expression *element = expression_allocate(); + element->kind = EXPRESSION_ELEMENT; + element->element.of = of; + element->element.element_index = index; + + expression *sub = parse_member_or_element_access(state, element); + + return sub; + } + + if (current(state).kind == TOKEN_LEFT_PAREN) { + error(state->context, "Function members not supported."); + } + + return of; +} + +static expression *parse_call(state_t *state, name_id func_name); + +static expression *parse_primary(state_t *state) { + expression *left = NULL; + + switch (current(state).kind) { + case TOKEN_BOOLEAN: { + bool value = current(state).boolean; + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_BOOLEAN; + left->boolean = value; + break; + } + case TOKEN_FLOAT: { + double value = current(state).number; + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_FLOAT; + left->number = value; + break; + } + case TOKEN_INT: { + double value = current(state).number; + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_INT; + left->number = value; + break; + } + /*case TOKEN_STRING: { + token token = current(state); + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_STRING; + left->string = add_name(token.string); + break; + }*/ + case TOKEN_IDENTIFIER: { + token token = current(state); + advance_state(state); + if (current(state).kind == TOKEN_LEFT_PAREN) { + left = parse_call(state, token.identifier); + } + else { + expression *var = expression_allocate(); + var->kind = EXPRESSION_VARIABLE; + var->variable = token.identifier; + left = var; + } + break; + } + case TOKEN_LEFT_PAREN: { + advance_state(state); + expression *expr = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_GROUPING; + left->grouping = expr; + break; + } + default: + error(state->context, "Unexpected token"); + return NULL; + } + + return parse_member_or_element_access(state, left); +} + +static expressions parse_parameters(state_t *state) { + expressions e; + e.size = 0; + + if (current(state).kind == TOKEN_RIGHT_PAREN) { + advance_state(state); + return e; + } + + for (;;) { + e.e[e.size] = parse_expression(state); + e.size += 1; + + if (current(state).kind == TOKEN_COMMA) { + advance_state(state); + } + else { + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + return e; + } + } +} + +static expression *parse_call(state_t *state, name_id func_name) { + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *call = NULL; + call = expression_allocate(); + call->kind = EXPRESSION_CALL; + call->call.func_name = func_name; + call->call.parameters = parse_parameters(state); + + return parse_member_or_element_access(state, call); +} + +static definition parse_struct_inner(state_t *state, name_id name) { + match_token(state, TOKEN_LEFT_CURLY, "Expected an opening curly bracket"); + advance_state(state); + + token member_names[MAX_MEMBERS]; + type_ref type_refs[MAX_MEMBERS]; + token member_values[MAX_MEMBERS]; + size_t count = 0; + + while (current(state).kind != TOKEN_RIGHT_CURLY) { + debug_context context = {0}; + check(count < MAX_MEMBERS, context, "Out of members"); + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + member_names[count] = current(state); + + advance_state(state); + + if (current(state).kind == TOKEN_COLON) { + advance_state(state); + type_refs[count] = parse_type_ref(state); + } + else { + type_ref t; + t.type = NO_TYPE; + t.unresolved.name = NO_NAME; + t.unresolved.array_size = 0; + type_refs[count] = t; + } + + if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_ASSIGN) { + advance_state(state); + if (current(state).kind == TOKEN_BOOLEAN || current(state).kind == TOKEN_FLOAT || current(state).kind == TOKEN_INT || + current(state).kind == TOKEN_IDENTIFIER) { + member_values[count] = current(state); + advance_state(state); + + if (current(state).kind == TOKEN_LEFT_PAREN) { + advance_state(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a right paren"); + advance_state(state); + } + } + else { + debug_context context = {0}; + error(context, "Unsupported assign in struct"); + } + } + else { + member_values[count].kind = TOKEN_NONE; + member_values[count].identifier = NO_NAME; + } + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + + advance_state(state); + + ++count; + } + + advance_state(state); + + definition definition; + definition.kind = DEFINITION_STRUCT; + + definition.type = add_type(name); + + type *s = get_type(definition.type); + + for (size_t i = 0; i < count; ++i) { + member member; + member.name = member_names[i].identifier; + member.value = member_values[i]; + if (member.value.kind != TOKEN_NONE) { + if (member.value.kind == TOKEN_BOOLEAN) { + init_type_ref(&member.type, add_name("bool")); + } + else if (member.value.kind == TOKEN_FLOAT) { + init_type_ref(&member.type, add_name("float")); + } + else if (member.value.kind == TOKEN_INT) { + init_type_ref(&member.type, add_name("int")); + } + else if (member.value.kind == TOKEN_IDENTIFIER) { + global *g = find_global(member.value.identifier); + if (g != NULL && g->name != NO_NAME) { + init_type_ref(&member.type, get_type(g->type)->name); + } + else { + init_type_ref(&member.type, add_name("fun")); + } + } + else { + debug_context context = {0}; + error(context, "Unsupported value in struct"); + } + } + else { + member.type = type_refs[i]; + } + + s->members.m[i] = member; + } + s->members.size = count; + + return definition; +} + +static definition parse_struct(state_t *state) { + advance_state(state); + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + token name = current(state); + advance_state(state); + + return parse_struct_inner(state, name.identifier); +} + +static definition parse_function(state_t *state) { + advance_state(state); + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + + token name = current(state); + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + uint8_t parameters_size = 0; + name_id param_names[256] = {0}; + type_ref param_types[256] = {0}; + name_id param_attributes[256] = {0}; + + while (current(state).kind != TOKEN_RIGHT_PAREN) { + if (current(state).kind == TOKEN_HASH) { + advance_state(state); + match_token(state, TOKEN_LEFT_SQUARE, "Expected an opening square bracket"); + advance_state(state); + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + token attribute_name = current(state); + param_attributes[parameters_size] = attribute_name.identifier; + advance_state(state); + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); + advance_state(state); + } + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + param_names[parameters_size] = current(state).identifier; + advance_state(state); + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + param_types[parameters_size] = parse_type_ref(state); + if (current(state).kind == TOKEN_COMMA) { + advance_state(state); + } + parameters_size += 1; + } + + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + + type_ref return_type = parse_type_ref(state); + + statement *block = parse_block(state, NULL); + + definition d; + d.kind = DEFINITION_FUNCTION; + d.function = add_function(name.identifier); + function *f = _get_function(d.function); + f->return_type = return_type; + f->parameters_size = parameters_size; + for (uint8_t parameter_index = 0; parameter_index < parameters_size; ++parameter_index) { + f->parameter_names[parameter_index] = param_names[parameter_index]; + f->parameter_types[parameter_index] = param_types[parameter_index]; + f->parameter_attributes[parameter_index] = param_attributes[parameter_index]; + } + f->block = block; + + return d; +} + +static definition parse_const(state_t *state, attribute_list attributes) { + advance_state(state); + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + + token name = current(state); + advance_state(state); + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + + name_id type_name = NO_NAME; + type_id type = NO_TYPE; + name_id format_name = NO_NAME; + + if (current(state).kind == TOKEN_LEFT_CURLY) { + type = parse_struct_inner(state, NO_NAME).type; + } + else { + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + type_name = current(state).identifier; + advance_state(state); + } + + bool array = false; + uint32_t array_size = UINT32_MAX; + + if (current(state).kind == TOKEN_LEFT_SQUARE) { + array = true; + advance_state(state); + + if (current(state).kind == TOKEN_INT) { + array_size = (uint32_t)current(state).number; + advance_state(state); + } + + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a right square bracket"); + advance_state(state); + } + + expression *value = NULL; + if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_ASSIGN) { + advance_state(state); + value = parse_expression(state); + } + + if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_LESS) { + advance_state(state); + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + format_name = current(state).identifier; + advance_state(state); + + if (current(state).kind == TOKEN_LEFT_PAREN) { + advance_state(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a right paren"); + advance_state(state); + } + + if (current(state).kind != TOKEN_OPERATOR || current(state).op != OPERATOR_GREATER) { + error(state->context, "Expected a greater than"); + } + advance_state(state); + } + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + definition d = {0}; + + if (type_name == NO_NAME) { + debug_context context = {0}; + check(type != NO_TYPE, context, "Const has no type"); + d.kind = DEFINITION_CONST_CUSTOM; + d.global = add_global(type, attributes, name.identifier); + } + else if (type_name == add_name("float")) { + debug_context context = {0}; + check(value != NULL, context, "const float requires an initialization value"); + check(value->kind == EXPRESSION_FLOAT || value->kind == EXPRESSION_INT, context, "const float requires a number"); + + global_value float_value; + float_value.kind = GLOBAL_VALUE_FLOAT; + + float_value.value.floats[0] = (float)value->number; + + d.kind = DEFINITION_CONST_BASIC; + d.global = add_global_with_value(_float_id, attributes, name.identifier, float_value); + } + else { + debug_context context = {0}; + error(context, "Unsupported global"); + } + + return d; +} + +static token tokens_get(tokens *tokens, size_t index) { + debug_context context = {0}; + check(tokens->current_size > index, context, "Token index out of bounds"); + return tokens->t[index]; +} + +static bool is_num(char ch, char chch) { + return (ch >= '0' && ch <= '9') || (ch == '-' && chch >= '0' && chch <= '9'); +} + +static bool is_op(char ch) { + return ch == '&' || ch == '|' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=' || ch == '!' || ch == '<' || ch == '>' || ch == '%' || + ch == '^'; +} + +static bool is_whitespace(char ch) { + return ch == ' ' || (ch >= 9 && ch <= 13); +} + +static void tokenizer_state_init(debug_context *context, tokenizer_state *state, const char *source) { + state->line = state->column = 0; + state->iterator = source; + state->next = *state->iterator; + if (*state->iterator != 0) { + state->iterator += 1; + } + state->next_next = *state->iterator; + state->line_end = false; + + context->column = 0; + context->line = 0; +} + +static void tokenizer_state_advance(debug_context *context, tokenizer_state *state) { + state->next = state->next_next; + if (*state->iterator != 0) { + state->iterator += 1; + } + state->next_next = *state->iterator; + + if (state->line_end) { + state->line_end = false; + state->line += 1; + state->column = 0; + } + else { + state->column += 1; + } + + if (state->next == '\n') { + state->line_end = true; + } + + context->column = state->column; + context->line = state->line; +} + +static void tokenizer_buffer_init(tokenizer_buffer *buffer) { + buffer->max_size = 1024 * 1024; + buffer->buf = (char *)malloc(buffer->max_size); + buffer->current_size = 0; + buffer->column = buffer->line = 0; +} + +static void tokenizer_buffer_reset(tokenizer_buffer *buffer, tokenizer_state *state) { + buffer->current_size = 0; + buffer->column = state->column; + buffer->line = state->line; +} + +static void tokenizer_buffer_add(tokenizer_buffer *buffer, char ch) { + debug_context context = {0}; + check(buffer->current_size < buffer->max_size, context, "Token buffer is too small"); + buffer->buf[buffer->current_size] = ch; + buffer->current_size += 1; +} + +static bool tokenizer_buffer_equals(tokenizer_buffer *buffer, const char *str) { + buffer->buf[buffer->current_size] = 0; + return strcmp(buffer->buf, str) == 0; +} + +static name_id tokenizer_buffer_to_name(tokenizer_buffer *buffer) { + debug_context context = {0}; + check(buffer->current_size < buffer->max_size, context, "Token buffer is too small"); + buffer->buf[buffer->current_size] = 0; + buffer->current_size += 1; + return add_name(buffer->buf); +} + +static double tokenizer_buffer_parse_number(tokenizer_buffer *buffer) { + buffer->buf[buffer->current_size] = 0; + return strtod(buffer->buf, NULL); +} + +static token token_create(int kind, tokenizer_state *state) { + token token; + token.kind = kind; + token.column = state->column; + token.line = state->line; + return token; +} + +static void tokens_init(tokens *tokens) { + tokens->max_size = 1024 * 1024; + tokens->t = malloc(tokens->max_size * sizeof(token)); + tokens->current_size = 0; +} + +static void tokens_add(tokens *tokens, token token) { + tokens->t[tokens->current_size] = token; + tokens->current_size += 1; + debug_context context = {0}; + check(tokens->current_size <= tokens->max_size, context, "Out of tokens"); +} + +static void tokens_add_identifier(tokenizer_state *state, tokens *tokens, tokenizer_buffer *buffer) { + token token; + + if (tokenizer_buffer_equals(buffer, "true")) { + token = token_create(TOKEN_BOOLEAN, state); + token.boolean = true; + } + else if (tokenizer_buffer_equals(buffer, "false")) { + token = token_create(TOKEN_BOOLEAN, state); + token.boolean = false; + } + else if (tokenizer_buffer_equals(buffer, "if")) { + token = token_create(TOKEN_IF, state); + } + else if (tokenizer_buffer_equals(buffer, "else")) { + token = token_create(TOKEN_ELSE, state); + } + else if (tokenizer_buffer_equals(buffer, "while")) { + token = token_create(TOKEN_WHILE, state); + } + else if (tokenizer_buffer_equals(buffer, "do")) { + token = token_create(TOKEN_DO, state); + } + else if (tokenizer_buffer_equals(buffer, "for")) { + token = token_create(TOKEN_FOR, state); + } + else if (tokenizer_buffer_equals(buffer, "in")) { + token = token_create(TOKEN_IN, state); + } + else if (tokenizer_buffer_equals(buffer, "struct")) { + token = token_create(TOKEN_STRUCT, state); + } + else if (tokenizer_buffer_equals(buffer, "fun")) { + token = token_create(TOKEN_FUNCTION, state); + } + else if (tokenizer_buffer_equals(buffer, "var")) { + token = token_create(TOKEN_VAR, state); + } + else if (tokenizer_buffer_equals(buffer, "const")) { + token = token_create(TOKEN_CONST, state); + } + else if (tokenizer_buffer_equals(buffer, "return")) { + token = token_create(TOKEN_RETURN, state); + } + else { + token = token_create(TOKEN_IDENTIFIER, state); + token.identifier = tokenizer_buffer_to_name(buffer); + } + + token.column = buffer->column; + token.line = buffer->line; + tokens_add(tokens, token); +} + +tokens _tokenize(const char *filename, const char *source) { + mode mode = MODE_SELECT; + bool number_has_dot = false; + + tokens tokens; + tokens_init(&tokens); + + debug_context context = {0}; + context.filename = filename; + + tokenizer_state state; + tokenizer_state_init(&context, &state, source); + + tokenizer_buffer buffer; + tokenizer_buffer_init(&buffer); + + for (;;) { + if (state.next == 0) { + switch (mode) { + case MODE_IDENTIFIER: + tokens_add_identifier(&state, &tokens, &buffer); + break; + case MODE_NUMBER: { + token token = token_create(number_has_dot ? TOKEN_FLOAT : TOKEN_INT, &state); + token.number = tokenizer_buffer_parse_number(&buffer); + tokens_add(&tokens, token); + break; + } + case MODE_SELECT: + case MODE_LINE_COMMENT: + break; + // case MODE_STRING: + // error("Unclosed string", state.column, state.line); + case MODE_OPERATOR: + error(context, "File ends with an operator"); + case MODE_COMMENT: + error(context, "Unclosed comment"); + } + + tokens_add(&tokens, token_create(TOKEN_NONE, &state)); + //// + free(buffer.buf); + //// + return tokens; + } + else { + char ch = (char)state.next; + switch (mode) { + case MODE_SELECT: { + if (ch == '/') { + if (state.next_next >= 0) { + char chch = state.next_next; + switch (chch) { + case '/': + mode = MODE_LINE_COMMENT; + break; + case '*': + mode = MODE_COMMENT; + break; + default: + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + mode = MODE_OPERATOR; + } + } + } + else if (is_num(ch, state.next_next)) { + mode = MODE_NUMBER; + number_has_dot = false; + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + } + else if (is_op(ch)) { + mode = MODE_OPERATOR; + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + } + else if (is_whitespace(ch)) { + } + else if (ch == '(') { + tokens_add(&tokens, token_create(TOKEN_LEFT_PAREN, &state)); + } + else if (ch == ')') { + tokens_add(&tokens, token_create(TOKEN_RIGHT_PAREN, &state)); + } + else if (ch == '{') { + tokens_add(&tokens, token_create(TOKEN_LEFT_CURLY, &state)); + } + else if (ch == '}') { + tokens_add(&tokens, token_create(TOKEN_RIGHT_CURLY, &state)); + } + else if (ch == '#') { + tokens_add(&tokens, token_create(TOKEN_HASH, &state)); + } + else if (ch == '[') { + tokens_add(&tokens, token_create(TOKEN_LEFT_SQUARE, &state)); + } + else if (ch == ']') { + tokens_add(&tokens, token_create(TOKEN_RIGHT_SQUARE, &state)); + } + else if (ch == ';') { + tokens_add(&tokens, token_create(TOKEN_SEMICOLON, &state)); + } + else if (ch == '.') { + tokens_add(&tokens, token_create(TOKEN_DOT, &state)); + } + else if (ch == ':') { + tokens_add(&tokens, token_create(TOKEN_COLON, &state)); + } + else if (ch == ',') { + tokens_add(&tokens, token_create(TOKEN_COMMA, &state)); + } + else if (ch == '"' || ch == '\'') { + // mode = MODE_STRING; + // tokenizer_buffer_reset(&buffer, &state); + error(context, "Strings are not supported"); + } + else { + mode = MODE_IDENTIFIER; + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + } + tokenizer_state_advance(&context, &state); + break; + } + case MODE_LINE_COMMENT: { + if (ch == '\n') { + mode = MODE_SELECT; + } + tokenizer_state_advance(&context, &state); + break; + } + case MODE_COMMENT: { + if (ch == '*') { + if (state.next_next >= 0) { + char chch = (char)state.next_next; + if (chch == '/') { + mode = MODE_SELECT; + tokenizer_state_advance(&context, &state); + } + } + } + tokenizer_state_advance(&context, &state); + break; + } + case MODE_NUMBER: { + if (is_num(ch, 0) || ch == '.') { + if (ch == '.') { + number_has_dot = true; + } + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&context, &state); + } + else { + token token = token_create(number_has_dot ? TOKEN_FLOAT : TOKEN_INT, &state); + token.number = tokenizer_buffer_parse_number(&buffer); + tokens_add(&tokens, token); + mode = MODE_SELECT; + } + break; + } + case MODE_OPERATOR: { + char long_op[3]; + long_op[0] = 0; + if (buffer.current_size == 1) { + long_op[0] = buffer.buf[0]; + long_op[1] = ch; + long_op[2] = 0; + } + + if (strcmp(long_op, "==") == 0 || strcmp(long_op, "!=") == 0 || strcmp(long_op, "<=") == 0 || strcmp(long_op, ">=") == 0 || + strcmp(long_op, "||") == 0 || strcmp(long_op, "&&") == 0 || strcmp(long_op, "->") == 0 || strcmp(long_op, "-=") == 0 || + strcmp(long_op, "+=") == 0 || strcmp(long_op, "/=") == 0 || strcmp(long_op, "*=") == 0 || strcmp(long_op, "<<") == 0 || + strcmp(long_op, ">>") == 0) { + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&context, &state); + } + + if (tokenizer_buffer_equals(&buffer, "==")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_EQUALS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "!=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_NOT_EQUALS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, ">")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_GREATER; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, ">=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_GREATER_EQUAL; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "<")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_LESS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "<=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_LESS_EQUAL; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "-=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MINUS_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "+=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_PLUS_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "/=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_DIVIDE_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "*=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MULTIPLY_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "-")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MINUS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "+")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_PLUS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "/")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_DIVIDE; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "*")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MULTIPLY; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "!")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_NOT; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "||")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_OR; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "^")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_BITWISE_XOR; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "&")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_BITWISE_AND; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "|")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_BITWISE_OR; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "<<")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_LEFT_SHIFT; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, ">>")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_RIGHT_SHIFT; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "&&")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_AND; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "%")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MOD; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_ASSIGN; + tokens_add(&tokens, token); + } + else { + error(context, "Weird operator"); + } + + mode = MODE_SELECT; + break; + } + /*case MODE_STRING: { + if (ch == '"' || ch == '\'') { + token token = token_create(TOKEN_STRING, &state); + tokenizer_buffer_copy_to_string(&buffer, token.string); + token.column = buffer.column; + token.line = buffer.line; + tokens_add(&tokens, token); + + tokenizer_state_advance(&state); + mode = MODE_SELECT; + } + else { + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&state); + } + break; + }*/ + case MODE_IDENTIFIER: { + if (is_whitespace(ch) || is_op(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '"' || ch == '\'' || + ch == ';' || ch == '.' || ch == ',' || ch == ':') { + tokens_add_identifier(&state, &tokens, &buffer); + mode = MODE_SELECT; + } + else { + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&context, &state); + } + break; + } + } + } + } +} + +static type_ref find_local_var_type(block *b, name_id name) { + if (b == NULL) { + type_ref t; + init_type_ref(&t, NO_NAME); + return t; + } + + for (size_t i = 0; i < b->vars.size; ++i) { + if (b->vars.v[i].name == name) { + debug_context context = {0}; + check(b->vars.v[i].type.type != NO_TYPE, context, "Local var has no type"); + return b->vars.v[i].type; + } + } + + return find_local_var_type(b->parent, name); +} + +static void resolve_types_in_element(statement *parent_block, expression *element) { + resolve_types_in_expression(parent_block, element->element.of); + resolve_types_in_expression(parent_block, element->element.element_index); + + type_id of_type = element->element.of->type.type; + + assert(of_type != NO_TYPE); + + type *of = get_type(of_type); + + if (of->array_size > 0) { + element->type.type = of->base; + } + else { + debug_context context = {0}; + error(context, "Indexed non-array %s", _get_name(of->name)); + } +} + +static void resolve_types_in_member(statement *parent_block, expression *member) { + resolve_types_in_expression(parent_block, member->member.of); + + type_id of_type = member->member.of->type.type; + name_id member_name = member->member.member_name; + + assert(of_type != NO_TYPE); + + type *of_struct = get_type(of_type); + + for (size_t i = 0; i < of_struct->members.size; ++i) { + if (of_struct->members.m[i].name == member_name) { + member->type = of_struct->members.m[i].type; + return; + } + } + + debug_context context = {0}; + error(context, "Member %s not found", _get_name(member_name)); +} + +static bool types_compatible(type_id left, type_id right) { + if (left == right) { + return true; + } + if ((left == _int_id && right == _float_id) || (left == _float_id && right == _int_id)) { + return true; + } + if ((left == _uint_id && right == _float_id) || (left == _float_id && right == _uint_id)) { + return true; + } + if ((left == _uint_id && right == _int_id) || (left == _int_id && right == _uint_id)) { + return true; + } + return false; +} + +static type_ref upgrade_type(type_ref left_type, type_ref right_type) { + type_id left = left_type.type; + type_id right = right_type.type; + + if (left == right) { + return left_type; + } + + if (left == _int_id && right == _float_id) { + return right_type; + } + if (left == _float_id && right == _int_id) { + return left_type; + } + + if (left == _uint_id && right == _float_id) { + return right_type; + } + if (left == _float_id && right == _uint_id) { + return left_type; + } + + if (left == _uint_id && right == _int_id) { + return right_type; + } + if (left == _int_id && right == _uint_id) { + return left_type; + } + + kong_log(LOG_LEVEL_WARNING, "Suspicious type upgrade"); + return left_type; +} + +static void resolve_types_in_expression(statement *parent, expression *e) { + switch (e->kind) { + case EXPRESSION_BINARY: { + resolve_types_in_expression(parent, e->binary.left); + resolve_types_in_expression(parent, e->binary.right); + switch (e->binary.op) { + case OPERATOR_EQUALS: + case OPERATOR_NOT_EQUALS: + case OPERATOR_GREATER: + case OPERATOR_GREATER_EQUAL: + case OPERATOR_LESS: + case OPERATOR_LESS_EQUAL: + case OPERATOR_OR: + case OPERATOR_AND: { + e->type.type = _bool_id; + break; + } + case OPERATOR_BITWISE_XOR: + case OPERATOR_BITWISE_AND: + case OPERATOR_BITWISE_OR: + case OPERATOR_LEFT_SHIFT: + case OPERATOR_RIGHT_SHIFT: { + e->type = e->binary.left->type; + break; + } + case OPERATOR_MULTIPLY: + case OPERATOR_MULTIPLY_ASSIGN: { + type_id left_type = e->binary.left->type.type; + type_id right_type = e->binary.right->type.type; + if (types_compatible(left_type, right_type)) { + e->type = upgrade_type(e->binary.left->type, e->binary.right->type); + } + else { + debug_context context = {0}; + error(context, "Type mismatch %s vs %s", _get_name(get_type(left_type)->name), _get_name(get_type(right_type)->name)); + } + break; + } + case OPERATOR_MINUS: + case OPERATOR_PLUS: + case OPERATOR_DIVIDE: + case OPERATOR_MOD: { + type_id left_type = e->binary.left->type.type; + type_id right_type = e->binary.right->type.type; + if (!types_compatible(left_type, right_type)) { + debug_context context = {0}; + error(context, "Type mismatch %s vs %s", _get_name(get_type(left_type)->name), _get_name(get_type(right_type)->name)); + } + e->type = upgrade_type(e->binary.left->type, e->binary.right->type); + break; + } + case OPERATOR_ASSIGN: + case OPERATOR_DIVIDE_ASSIGN: + case OPERATOR_MINUS_ASSIGN: + case OPERATOR_PLUS_ASSIGN: { + type_id left_type = e->binary.left->type.type; + type_id right_type = e->binary.right->type.type; + if (!types_compatible(left_type, right_type)) { + debug_context context = {0}; + error(context, "Type mismatch %s vs %s", _get_name(get_type(left_type)->name), _get_name(get_type(right_type)->name)); + } + e->type = e->binary.left->type; + break; + } + case OPERATOR_NOT: { + debug_context context = {0}; + error(context, "Weird binary operator"); + break; + } + } + break; + } + case EXPRESSION_UNARY: { + resolve_types_in_expression(parent, e->unary.right); + switch (e->unary.op) { + case OPERATOR_MINUS: + case OPERATOR_PLUS: { + e->type = e->unary.right->type; + break; + } + case OPERATOR_NOT: { + e->type.type = _bool_id; + break; + } + case OPERATOR_EQUALS: + case OPERATOR_NOT_EQUALS: + case OPERATOR_GREATER: + case OPERATOR_GREATER_EQUAL: + case OPERATOR_LESS: + case OPERATOR_LESS_EQUAL: + case OPERATOR_DIVIDE: + case OPERATOR_MULTIPLY: + case OPERATOR_OR: + case OPERATOR_BITWISE_XOR: + case OPERATOR_BITWISE_AND: + case OPERATOR_BITWISE_OR: + case OPERATOR_LEFT_SHIFT: + case OPERATOR_RIGHT_SHIFT: + case OPERATOR_AND: + case OPERATOR_MOD: + case OPERATOR_ASSIGN: + default: { + debug_context context = {0}; + error(context, "Weird unary operator"); + break; + } + } + break; + } + case EXPRESSION_BOOLEAN: { + e->type.type = _bool_id; + break; + } + case EXPRESSION_FLOAT: { + e->type.type = _float_id; + break; + } + case EXPRESSION_INT: { + e->type.type = _int_id; + break; + } + case EXPRESSION_VARIABLE: { + global *g = find_global(e->variable); + if (g != NULL && g->type != NO_TYPE) { + e->type.type = g->type; + } + else { + type_ref type = find_local_var_type(&parent->block, e->variable); + if (type.type == NO_TYPE) { + type = find_local_var_type(&parent->block, e->variable); + debug_context context = {0}; + error(context, "Variable %s not found", _get_name(e->variable)); + } + e->type = type; + } + break; + } + case EXPRESSION_GROUPING: { + resolve_types_in_expression(parent, e->grouping); + e->type = e->grouping->type; + break; + } + case EXPRESSION_CALL: { + for (function_id i = 0; _get_function(i) != NULL; ++i) { + function *f = _get_function(i); + if (f->name == e->call.func_name) { + e->type = f->return_type; + break; + } + } + for (size_t i = 0; i < e->call.parameters.size; ++i) { + resolve_types_in_expression(parent, e->call.parameters.e[i]); + } + break; + } + case EXPRESSION_MEMBER: { + resolve_types_in_member(parent, e); + break; + } + case EXPRESSION_ELEMENT: { + resolve_types_in_element(parent, e); + break; + } + } + + if (e->type.type == NO_TYPE) { + debug_context context = {0}; + // const char *n = _get_name(e->call.func_name); + error(context, "Could not resolve type"); + } +} + +static void resolve_types_in_block(statement *parent, statement *block) { + debug_context context = {0}; + check(block->kind == STATEMENT_BLOCK, context, "Malformed block"); + + for (size_t i = 0; i < block->block.statements.size; ++i) { + statement *s = block->block.statements.s[i]; + switch (s->kind) { + case STATEMENT_EXPRESSION: { + resolve_types_in_expression(block, s->expression); + break; + } + case STATEMENT_RETURN_EXPRESSION: { + resolve_types_in_expression(block, s->expression); + break; + } + case STATEMENT_IF: { + resolve_types_in_expression(block, s->iffy.test); + resolve_types_in_block(block, s->iffy.if_block); + for (uint16_t i = 0; i < s->iffy.else_size; ++i) { + if (s->iffy.else_tests[i] != NULL) { + resolve_types_in_expression(block, s->iffy.else_tests[i]); + } + resolve_types_in_block(block, s->iffy.else_blocks[i]); + } + break; + } + case STATEMENT_WHILE: + case STATEMENT_DO_WHILE: { + resolve_types_in_expression(block, s->whiley.test); + resolve_types_in_block(block, s->whiley.while_block); + break; + } + case STATEMENT_BLOCK: { + resolve_types_in_block(block, s); + break; + } + case STATEMENT_LOCAL_VARIABLE: { + name_id var_name = s->local_variable.var.name; + name_id var_type_name = s->local_variable.var.type.unresolved.name; + + if (s->local_variable.var.type.type == NO_TYPE && var_type_name != NO_NAME) { + s->local_variable.var.type.type = find_type_by_ref(&s->local_variable.var.type); + } + + if (s->local_variable.var.type.type == NO_TYPE) { + debug_context context = {0}; + error(context, "Could not find type %s for %s", _get_name(var_type_name), _get_name(var_name)); + } + + if (s->local_variable.init != NULL) { + resolve_types_in_expression(block, s->local_variable.init); + } + + block->block.vars.v[block->block.vars.size].name = var_name; + block->block.vars.v[block->block.vars.size].type = s->local_variable.var.type; + ++block->block.vars.size; + break; + } + } + } +} + +void _resolve_types(void) { + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *s = get_type(i); + for (size_t j = 0; j < s->members.size; ++j) { + if (s->members.m[j].type.type == NO_TYPE) { + name_id name = s->members.m[j].type.unresolved.name; + s->members.m[j].type.type = find_type_by_name(name); + if (s->members.m[j].type.type == NO_TYPE) { + debug_context context = {0}; + error(context, "Could not find type %s in %s", _get_name(name), _get_name(s->name)); + } + } + } + } + + for (function_id i = 0; _get_function(i) != NULL; ++i) { + function *f = _get_function(i); + + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (f->parameter_types[parameter_index].type == NO_TYPE) { + name_id parameter_type_name = f->parameter_types[parameter_index].unresolved.name; + f->parameter_types[parameter_index].type = find_type_by_name(parameter_type_name); + if (f->parameter_types[parameter_index].type == NO_TYPE) { + debug_context context = {0}; + error(context, "Could not find type %s for %s", _get_name(parameter_type_name), _get_name(f->name)); + } + } + } + + if (f->return_type.type == NO_TYPE) { + f->return_type.type = find_type_by_ref(&f->return_type); + + if (f->return_type.type == NO_TYPE) { + error_no_context("Could not find type %s for %s", _get_name(f->return_type.unresolved.name), _get_name(f->name)); + } + } + } + + for (function_id i = 0; _get_function(i) != NULL; ++i) { + function *f = _get_function(i); + + if (f->block == NULL) { + // built in + continue; + } + + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + f->block->block.vars.v[f->block->block.vars.size].name = f->parameter_names[parameter_index]; + f->block->block.vars.v[f->block->block.vars.size].type = f->parameter_types[parameter_index]; + f->block->block.vars.v[f->block->block.vars.size].variable_id = 0; + ++f->block->block.vars.size; + } + + resolve_types_in_block(NULL, f->block); + } +} + +static void init_type_ref(type_ref *t, name_id name) { + t->type = NO_TYPE; + t->unresolved.name = name; + t->unresolved.array_size = 0; +} + +void _types_init(void) { + type *new_types = realloc(types, types_size * sizeof(type)); + debug_context context = {0}; + check(new_types != NULL, context, "Could not allocate types"); + types = new_types; + next_type_index = 0; + + _void_id = add_type(add_name("void")); + get_type(_void_id)->built_in = true; + + _bool_id = add_type(add_name("bool")); + get_type(_bool_id)->built_in = true; + _float_id = add_type(add_name("float")); + get_type(_float_id)->built_in = true; + _int_id = add_type(add_name("int")); + get_type(_int_id)->built_in = true; + _uint_id = add_type(add_name("uint")); + get_type(_uint_id)->built_in = true; + + { + function_type_id = add_type(add_name("fun")); + get_type(function_type_id)->built_in = true; + } +} + +static void grow_types_if_needed(uint64_t size) { + while (size >= types_size) { + types_size *= 2; + type *new_types = realloc(types, types_size * sizeof(type)); + debug_context context = {0}; + check(new_types != NULL, context, "Could not allocate types"); + types = new_types; + } +} + +static bool types_equal(type *a, type *b) { + return a->name == b->name && a->attributes.attributes_count == 0 && b->attributes.attributes_count == 0 && a->members.size == 0 && b->members.size == 0 && + a->built_in == b->built_in && a->array_size == b->array_size && a->base == b->base; +} + +static type_id add_type(name_id name) { + grow_types_if_needed(next_type_index + 1); + + type_id s = next_type_index; + ++next_type_index; + + types[s].name = name; + types[s].attributes.attributes_count = 0; + types[s].members.size = 0; + types[s].built_in = false; + types[s].array_size = 0; + types[s].base = NO_TYPE; + + return s; +} + +static type_id add_full_type(type *t) { + for (type_id type_index = 0; type_index < next_type_index; ++type_index) { + if (types_equal(&types[type_index], t)) { + return type_index; + } + } + + grow_types_if_needed(next_type_index + 1); + + type_id s = next_type_index; + ++next_type_index; + + types[s] = *t; + + return s; +} + +static type_id find_type_by_name(name_id name) { + debug_context context = {0}; + check(name != NO_NAME, context, "Attempted to find a no-name"); + for (type_id i = 0; i < next_type_index; ++i) { + if (types[i].name == name) { + return i; + } + } + + return NO_TYPE; +} + +static type_id find_type_by_ref(type_ref *t) { + if (t->type != NO_TYPE) { + return t->type; + } + + debug_context context = {0}; + check(t->unresolved.name != NO_NAME, context, "Attempted to find a no-name"); + + type_id base_type_id = NO_TYPE; + + for (type_id i = 0; i < next_type_index; ++i) { + if (types[i].name == t->unresolved.name) { + if (types[i].array_size == t->unresolved.array_size) { + return i; + } + base_type_id = i; + } + } + + if (base_type_id != NO_TYPE) { + type_id new_type_id = add_type(t->unresolved.name); + type *new_type = get_type(new_type_id); + new_type->array_size = t->unresolved.array_size; + + type *base_type = get_type(base_type_id); + new_type->base = base_type_id; + new_type->built_in = base_type->built_in; + + return new_type_id; + } + + return NO_TYPE; +} + +static type *get_type(type_id s) { + if (s >= next_type_index) { + return NULL; + } + return &types[s]; +} diff --git a/base/tools/amake/alang_c.c b/base/tools/amake/kong/alang_c.c similarity index 100% rename from base/tools/amake/alang_c.c rename to base/tools/amake/kong/alang_c.c diff --git a/base/tools/amake/alang_eval.c b/base/tools/amake/kong/alang_eval.c similarity index 100% rename from base/tools/amake/alang_eval.c rename to base/tools/amake/kong/alang_eval.c diff --git a/base/tools/amake/project.js b/base/tools/amake/project.js index b871809a..93b943cb 100644 --- a/base/tools/amake/project.js +++ b/base/tools/amake/project.js @@ -3,11 +3,10 @@ let project = new Project("amake"); // alang project.add_define("NO_GC"); +project.add_define("NO_GC_USE_HEAP"); project.add_define("NO_IRON_API"); -project.add_define("NO_IRON_START"); -project.add_tsfiles("./"); // alang.ts project.add_include_dir("./"); // iron.h -project.add_cfiles("build/iron.c"); +project.add_cfiles("alang.c"); project.add_include_dir("../../sources"); project.add_cfiles("../../sources/iron_string.c"); project.add_cfiles("../../sources/iron_array.c"); diff --git a/base/tools/amake/readme.md b/base/tools/amake/readme.md index 906ca4f6..efedb275 100644 --- a/base/tools/amake/readme.md +++ b/base/tools/amake/readme.md @@ -3,5 +3,5 @@ Iron build tool. ```bash -../../make --compile --alangjs +../../make --compile ``` diff --git a/base/tools/make.js b/base/tools/make.js index c65791b7..ca408f9a 100644 --- a/base/tools/make.js +++ b/base/tools/make.js @@ -2750,23 +2750,10 @@ function write_ts_project(projectdir, options) { source += file; } - if (goptions.alangjs) { - globalThis.std = std; - globalThis.fs_readfile = fs_readfile; - globalThis.fs_writefile = fs_writefile; - globalThis.flags.alang_source = source; - globalThis.flags.alang_output = os_cwd() + path_sep + "build" + path_sep + "iron.c"; - let alang = irondir + '/tools/amake/alang.js'; - (1, eval)(fs_readfile(alang)); - } - else { - // let alang_input = os_cwd() + path_sep + "build" + path_sep + "iron.ts"; - // fs_writefile(alang_input, source); - let alang_output = os_cwd() + path_sep + "build" + path_sep + "iron.c"; - let start = Date.now(); - amake.alang(source, alang_output); - console.log("alang took " + (Date.now() - start) + "ms."); - } + let alang_output = os_cwd() + path_sep + "build" + path_sep + "iron.c"; + let start = Date.now(); + amake.alang(source, alang_output); + console.log("alang took " + (Date.now() - start) + "ms."); } function export_project_files(name, options, exporter, defines) { @@ -3316,7 +3303,6 @@ let goptions = { ccompiler : 'clang', cppcompiler : 'clang++', arch : 'default', - alangjs : false, js : false, ashader : false, };