Compare commits
8 Commits
ff1927a5c6
...
b16ba10b0d
Author | SHA1 | Date | |
---|---|---|---|
b16ba10b0d | |||
678e71129d | |||
fba3cd6660 | |||
cf59c1e75b | |||
c932c3c609 | |||
f061419edf | |||
92c63092a1 | |||
5560de2904 |
@ -3,10 +3,14 @@
|
|||||||
|
|
||||||
<label> ::= <identifier> <colon>
|
<label> ::= <identifier> <colon>
|
||||||
|
|
||||||
<directive> ::= <dot> <section_directive>
|
<directive> ::= <dot> (<section_directive> | <export_directive> | <import_directive> )
|
||||||
|
|
||||||
<section_directive> ::= "section" <identifier>
|
<section_directive> ::= "section" <identifier>
|
||||||
|
|
||||||
|
<export_directive> ::= "export" <identifier>
|
||||||
|
|
||||||
|
<import_directive> ::= "import" <identifier>
|
||||||
|
|
||||||
<instruction> ::= <identifier> <operands>
|
<instruction> ::= <identifier> <operands>
|
||||||
|
|
||||||
<operands> ::= <operand> ( <comma> <operand> )*
|
<operands> ::= <operand> ( <comma> <operand> )*
|
||||||
|
@ -123,6 +123,10 @@ const char *ast_node_id_to_cstr(node_id_t id) {
|
|||||||
return "NODE_PLUS_OR_MINUS";
|
return "NODE_PLUS_OR_MINUS";
|
||||||
case NODE_SECTION_DIRECTIVE:
|
case NODE_SECTION_DIRECTIVE:
|
||||||
return "NODE_SECTION_DIRECTIVE";
|
return "NODE_SECTION_DIRECTIVE";
|
||||||
|
case NODE_IMPORT_DIRECTIVE:
|
||||||
|
return "NODE_IMPORT_DIRECTIVE";
|
||||||
|
case NODE_EXPORT_DIRECTIVE:
|
||||||
|
return "NODE_EXPORT_DIRECTIVE";
|
||||||
case NODE_REGISTER:
|
case NODE_REGISTER:
|
||||||
return "NODE_REGISTER";
|
return "NODE_REGISTER";
|
||||||
case NODE_SECTION:
|
case NODE_SECTION:
|
||||||
@ -157,6 +161,10 @@ const char *ast_node_id_to_cstr(node_id_t id) {
|
|||||||
return "NODE_ASTERISK";
|
return "NODE_ASTERISK";
|
||||||
case NODE_DOT:
|
case NODE_DOT:
|
||||||
return "NODE_DOT";
|
return "NODE_DOT";
|
||||||
|
case NODE_IMPORT:
|
||||||
|
return "NODE_IMPORT";
|
||||||
|
case NODE_EXPORT:
|
||||||
|
return "NODE_EXPORT";
|
||||||
}
|
}
|
||||||
assert(!"Unreachable, weird node id" && id);
|
assert(!"Unreachable, weird node id" && id);
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
|
@ -29,10 +29,14 @@ typedef enum node_id {
|
|||||||
NODE_REGISTER_OFFSET,
|
NODE_REGISTER_OFFSET,
|
||||||
NODE_PLUS_OR_MINUS,
|
NODE_PLUS_OR_MINUS,
|
||||||
NODE_SECTION_DIRECTIVE,
|
NODE_SECTION_DIRECTIVE,
|
||||||
|
NODE_IMPORT_DIRECTIVE,
|
||||||
|
NODE_EXPORT_DIRECTIVE,
|
||||||
|
|
||||||
// Validated primitives
|
// Validated primitives
|
||||||
NODE_REGISTER,
|
NODE_REGISTER,
|
||||||
NODE_SECTION,
|
NODE_SECTION,
|
||||||
|
NODE_IMPORT,
|
||||||
|
NODE_EXPORT,
|
||||||
|
|
||||||
// Primitive nodes
|
// Primitive nodes
|
||||||
NODE_IDENTIFIER,
|
NODE_IDENTIFIER,
|
||||||
|
159
src/encoder/symbols.c
Normal file
159
src/encoder/symbols.c
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#include "symbols.h"
|
||||||
|
#include "../error.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
constexpr size_t symbol_table_default_cap = 64;
|
||||||
|
constexpr size_t symbol_table_max_cap = 1 << 16;
|
||||||
|
|
||||||
|
error_t *const err_symbol_table_invalid_node = &(error_t){
|
||||||
|
.message = "Unexpected node id when adding symbol to symbol table"};
|
||||||
|
error_t *const err_symbol_table_max_cap = &(error_t){
|
||||||
|
.message = "Failed to increase symbol table length, max capacity reached"};
|
||||||
|
error_t *const err_symbol_table_incompatible_symbols =
|
||||||
|
&(error_t){.message = "Failed to update symbol with incompatible kind"};
|
||||||
|
|
||||||
|
error_t *symbol_table_alloc(symbol_table_t **output) {
|
||||||
|
*output = nullptr;
|
||||||
|
|
||||||
|
symbol_table_t *table = calloc(1, sizeof(symbol_table_t));
|
||||||
|
if (table == nullptr)
|
||||||
|
return err_allocation_failed;
|
||||||
|
|
||||||
|
table->symbols = calloc(symbol_table_default_cap, sizeof(symbol_t));
|
||||||
|
if (table->symbols == nullptr) {
|
||||||
|
free(table);
|
||||||
|
return err_allocation_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->cap = symbol_table_default_cap;
|
||||||
|
table->len = 0;
|
||||||
|
|
||||||
|
*output = table;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void symbol_table_free(symbol_table_t *table) {
|
||||||
|
free(table->symbols);
|
||||||
|
free(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t *symbol_table_grow_cap(symbol_table_t *table) {
|
||||||
|
if (table->cap >= symbol_table_max_cap)
|
||||||
|
return err_symbol_table_max_cap;
|
||||||
|
|
||||||
|
size_t new_cap = table->cap * 2;
|
||||||
|
symbol_t *new_symbols = realloc(table->symbols, new_cap * sizeof(symbol_t));
|
||||||
|
if (new_symbols == nullptr)
|
||||||
|
return err_allocation_failed;
|
||||||
|
|
||||||
|
table->symbols = new_symbols;
|
||||||
|
table->cap = new_cap;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t *symbol_table_get_node_info(ast_node_t *node, symbol_kind_t *kind,
|
||||||
|
char **name) {
|
||||||
|
switch (node->id) {
|
||||||
|
case NODE_LABEL:
|
||||||
|
*kind = SYMBOL_LOCAL;
|
||||||
|
*name = node->children[0]->token_entry->token.value;
|
||||||
|
return nullptr;
|
||||||
|
case NODE_LABEL_REFERENCE:
|
||||||
|
*kind = SYMBOL_REFERENCE;
|
||||||
|
*name = node->token_entry->token.value;
|
||||||
|
return nullptr;
|
||||||
|
case NODE_IMPORT_DIRECTIVE:
|
||||||
|
*kind = SYMBOL_IMPORT;
|
||||||
|
*name = node->children[1]->token_entry->token.value;
|
||||||
|
return nullptr;
|
||||||
|
case NODE_EXPORT_DIRECTIVE:
|
||||||
|
*kind = SYMBOL_EXPORT;
|
||||||
|
*name = node->children[1]->token_entry->token.value;
|
||||||
|
return nullptr;
|
||||||
|
default:
|
||||||
|
return err_symbol_table_invalid_node;
|
||||||
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
old \ new | REFERENCE | LOCAL | IMPORT | EXPORT |
|
||||||
|
-------------|-----------|----------|----------|----------|
|
||||||
|
REFERENCE | | replace | replace | replace |
|
||||||
|
-------------|-----------|----------|----------|----------|
|
||||||
|
LOCAL | | | ERR | replace |
|
||||||
|
-------------|-----------|----------|----------|----------|
|
||||||
|
IMPORT | | | | ERR |
|
||||||
|
-------------|-----------|----------|----------|----------|
|
||||||
|
EXPORT | | | ERR | |
|
||||||
|
-------------|-----------|----------|----------|----------|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool symbol_table_should_update(symbol_kind_t old, symbol_kind_t new) {
|
||||||
|
if (old == SYMBOL_REFERENCE)
|
||||||
|
return new != SYMBOL_REFERENCE;
|
||||||
|
if (old == SYMBOL_LOCAL)
|
||||||
|
return new == SYMBOL_EXPORT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool symbol_table_should_error(symbol_kind_t old, symbol_kind_t new) {
|
||||||
|
if (new == SYMBOL_IMPORT)
|
||||||
|
return old == SYMBOL_LOCAL || old == SYMBOL_EXPORT;
|
||||||
|
if (new == SYMBOL_EXPORT)
|
||||||
|
return old == SYMBOL_IMPORT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @pre The symbol _must not_ already be in the table.
|
||||||
|
*/
|
||||||
|
error_t *symbol_table_add(symbol_table_t *table, char *name, symbol_kind_t kind,
|
||||||
|
ast_node_t *node) {
|
||||||
|
if (table->len >= table->cap) {
|
||||||
|
error_t *err = symbol_table_grow_cap(table);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->symbols[table->len] = (symbol_t){
|
||||||
|
.name = name,
|
||||||
|
.kind = kind,
|
||||||
|
.node = node,
|
||||||
|
};
|
||||||
|
|
||||||
|
table->len += 1;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t *symbol_table_update(symbol_table_t *table, ast_node_t *node) {
|
||||||
|
char *name;
|
||||||
|
symbol_kind_t kind;
|
||||||
|
error_t *err = symbol_table_get_node_info(node, &kind, &name);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, name);
|
||||||
|
if (!symbol)
|
||||||
|
return symbol_table_add(table, name, kind, node);
|
||||||
|
if (symbol_table_should_error(symbol->kind, kind))
|
||||||
|
return err_symbol_table_incompatible_symbols;
|
||||||
|
if (symbol_table_should_update(symbol->kind, kind)) {
|
||||||
|
symbol->name = name;
|
||||||
|
symbol->kind = kind;
|
||||||
|
symbol->node = node;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol_t *symbol_table_lookup(symbol_table_t *table, const char *name) {
|
||||||
|
for (size_t i = 0; i < table->len; ++i) {
|
||||||
|
if (strcmp(table->symbols[i].name, name) == 0)
|
||||||
|
return &table->symbols[i];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
46
src/encoder/symbols.h
Normal file
46
src/encoder/symbols.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef INCLUDE_ENCODER_SYMBOLS_H_
|
||||||
|
#define INCLUDE_ENCODER_SYMBOLS_H_
|
||||||
|
|
||||||
|
#include "../ast.h"
|
||||||
|
|
||||||
|
extern error_t *const err_symbol_table_invalid_node;
|
||||||
|
extern error_t *const err_symbol_table_max_cap;
|
||||||
|
extern error_t *const err_symbol_table_incompatible_symbols;
|
||||||
|
|
||||||
|
typedef enum symbol_kind {
|
||||||
|
SYMBOL_REFERENCE,
|
||||||
|
SYMBOL_LOCAL,
|
||||||
|
SYMBOL_EXPORT,
|
||||||
|
SYMBOL_IMPORT,
|
||||||
|
} symbol_kind_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent a symbol in the program
|
||||||
|
*
|
||||||
|
* Symbols with the same name can only be in the table once. IMPORT or EXPORT
|
||||||
|
* symbols take precedence over REFERENCE symbols. If any reference symbols
|
||||||
|
* remain after the first encoding pass this indicates an error. Trying to add
|
||||||
|
* an IMPORT or EXPORT symbol if the same name already exists as the other kind
|
||||||
|
* is an error.
|
||||||
|
*
|
||||||
|
* This symbol table never taken ownership of the name string, it's lifted
|
||||||
|
* straight from the node->token.value.
|
||||||
|
*/
|
||||||
|
typedef struct symbol {
|
||||||
|
char *name;
|
||||||
|
symbol_kind_t kind;
|
||||||
|
ast_node_t *node;
|
||||||
|
} symbol_t;
|
||||||
|
|
||||||
|
typedef struct symbol_table {
|
||||||
|
size_t cap;
|
||||||
|
size_t len;
|
||||||
|
symbol_t *symbols;
|
||||||
|
} symbol_table_t;
|
||||||
|
|
||||||
|
error_t *symbol_table_alloc(symbol_table_t **table);
|
||||||
|
void symbol_table_free(symbol_table_t *table);
|
||||||
|
error_t *symbol_table_update(symbol_table_t *table, ast_node_t *node);
|
||||||
|
symbol_t *symbol_table_lookup(symbol_table_t *table, const char *name);
|
||||||
|
|
||||||
|
#endif // INCLUDE_ENCODER_SYMBOLS_H_
|
43
src/main.c
43
src/main.c
@ -32,21 +32,22 @@ void print_text(tokenlist_t *list) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_ast(tokenlist_t *list) {
|
error_t *print_ast(tokenlist_t *list) {
|
||||||
parse_result_t result = parse(list->head);
|
parse_result_t result = parse(list->head);
|
||||||
if (result.err) {
|
if (result.err)
|
||||||
puts(result.err->message);
|
return result.err;
|
||||||
error_free(result.err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ast_node_print(result.node);
|
ast_node_print(result.node);
|
||||||
|
|
||||||
if (result.next != nullptr) {
|
if (result.next != nullptr) {
|
||||||
puts("First unparsed token:");
|
puts("First unparsed token:");
|
||||||
lexer_token_print(&result.next->token);
|
lexer_token_print(&result.next->token);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_node_free(result.node);
|
ast_node_free(result.node);
|
||||||
|
if (result.next != nullptr) {
|
||||||
|
return errorf("did not parse entire input token stream");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_execution_mode(int argc, char *argv[]) {
|
int get_execution_mode(int argc, char *argv[]) {
|
||||||
@ -63,6 +64,20 @@ int get_execution_mode(int argc, char *argv[]) {
|
|||||||
return MODE_AST;
|
return MODE_AST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_t *do_action(mode_t mode, tokenlist_t *list) {
|
||||||
|
switch (mode) {
|
||||||
|
case MODE_TOKENS:
|
||||||
|
print_tokens(list);
|
||||||
|
return nullptr;
|
||||||
|
case MODE_TEXT:
|
||||||
|
print_text(list);
|
||||||
|
return nullptr;
|
||||||
|
case MODE_AST:
|
||||||
|
return print_ast(list);
|
||||||
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
mode_t mode = get_execution_mode(argc, argv);
|
mode_t mode = get_execution_mode(argc, argv);
|
||||||
char *filename = argv[2];
|
char *filename = argv[2];
|
||||||
@ -81,17 +96,9 @@ int main(int argc, char *argv[]) {
|
|||||||
if (err)
|
if (err)
|
||||||
goto cleanup_tokens;
|
goto cleanup_tokens;
|
||||||
|
|
||||||
switch (mode) {
|
err = do_action(mode, list);
|
||||||
case MODE_TOKENS:
|
if (err)
|
||||||
print_tokens(list);
|
goto cleanup_tokens;
|
||||||
break;
|
|
||||||
case MODE_TEXT:
|
|
||||||
print_text(list);
|
|
||||||
break;
|
|
||||||
case MODE_AST:
|
|
||||||
print_ast(list);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenlist_free(list);
|
tokenlist_free(list);
|
||||||
error_free(err);
|
error_free(err);
|
||||||
|
@ -83,7 +83,7 @@ parse_result_t parse_register_expression(tokenlist_entry_t *current) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse_result_t parse_immediate(tokenlist_entry_t *current) {
|
parse_result_t parse_immediate(tokenlist_entry_t *current) {
|
||||||
parser_t parsers[] = {parse_number, parse_identifier, nullptr};
|
parser_t parsers[] = {parse_number, parse_label_reference, nullptr};
|
||||||
parse_result_t result = parse_any(current, parsers);
|
parse_result_t result = parse_any(current, parsers);
|
||||||
return parse_result_wrap(NODE_IMMEDIATE, result);
|
return parse_result_wrap(NODE_IMMEDIATE, result);
|
||||||
}
|
}
|
||||||
@ -119,8 +119,24 @@ parse_result_t parse_section_directive(tokenlist_entry_t *current) {
|
|||||||
return parse_consecutive(current, NODE_SECTION_DIRECTIVE, parsers);
|
return parse_consecutive(current, NODE_SECTION_DIRECTIVE, parsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_result_t parse_import_directive(tokenlist_entry_t *current) {
|
||||||
|
parser_t parsers[] = {parse_import, parse_identifier, nullptr};
|
||||||
|
return parse_consecutive(current, NODE_IMPORT_DIRECTIVE, parsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_result_t parse_export_directive(tokenlist_entry_t *current) {
|
||||||
|
parser_t parsers[] = {parse_export, parse_identifier, nullptr};
|
||||||
|
return parse_consecutive(current, NODE_EXPORT_DIRECTIVE, parsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_result_t parse_directive_options(tokenlist_entry_t *current) {
|
||||||
|
parser_t parsers[] = {parse_section_directive, parse_import_directive,
|
||||||
|
parse_export_directive, nullptr};
|
||||||
|
return parse_any(current, parsers);
|
||||||
|
}
|
||||||
|
|
||||||
parse_result_t parse_directive(tokenlist_entry_t *current) {
|
parse_result_t parse_directive(tokenlist_entry_t *current) {
|
||||||
parser_t parsers[] = {parse_dot, parse_section_directive, nullptr};
|
parser_t parsers[] = {parse_dot, parse_directive_options, nullptr};
|
||||||
return parse_consecutive(current, NODE_DIRECTIVE, parsers);
|
return parse_consecutive(current, NODE_DIRECTIVE, parsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,5 +152,6 @@ parse_result_t parse_statement(tokenlist_entry_t *current) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse_result_t parse(tokenlist_entry_t *current) {
|
parse_result_t parse(tokenlist_entry_t *current) {
|
||||||
|
current = tokenlist_skip_trivia(current);
|
||||||
return parse_many(current, NODE_PROGRAM, true, parse_statement);
|
return parse_many(current, NODE_PROGRAM, true, parse_statement);
|
||||||
}
|
}
|
||||||
|
@ -101,3 +101,19 @@ parse_result_t parse_section(tokenlist_entry_t *current) {
|
|||||||
return parse_token(current, TOKEN_IDENTIFIER, NODE_SECTION,
|
return parse_token(current, TOKEN_IDENTIFIER, NODE_SECTION,
|
||||||
is_section_token);
|
is_section_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_import_token(lexer_token_t *token) {
|
||||||
|
return strcmp(token->value, "import") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_result_t parse_import(tokenlist_entry_t *current) {
|
||||||
|
return parse_token(current, TOKEN_IDENTIFIER, NODE_IMPORT, is_import_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_export_token(lexer_token_t *token) {
|
||||||
|
return strcmp(token->value, "export") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_result_t parse_export(tokenlist_entry_t *current) {
|
||||||
|
return parse_token(current, TOKEN_IDENTIFIER, NODE_EXPORT, is_export_token);
|
||||||
|
}
|
||||||
|
@ -26,5 +26,7 @@ parse_result_t parse_label_reference(tokenlist_entry_t *current);
|
|||||||
*/
|
*/
|
||||||
parse_result_t parse_register(tokenlist_entry_t *current);
|
parse_result_t parse_register(tokenlist_entry_t *current);
|
||||||
parse_result_t parse_section(tokenlist_entry_t *current);
|
parse_result_t parse_section(tokenlist_entry_t *current);
|
||||||
|
parse_result_t parse_import(tokenlist_entry_t *current);
|
||||||
|
parse_result_t parse_export(tokenlist_entry_t *current);
|
||||||
|
|
||||||
#endif // INCLUDE_PARSER_PRIMITIVES_H_
|
#endif // INCLUDE_PARSER_PRIMITIVES_H_
|
||||||
|
65
tests/input/manysymbols.asm
Normal file
65
tests/input/manysymbols.asm
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
lbl_0: ; 65 symbols used for testing growing the symbols table
|
||||||
|
lbl_1:
|
||||||
|
lbl_2:
|
||||||
|
lbl_3:
|
||||||
|
lbl_4:
|
||||||
|
lbl_5:
|
||||||
|
lbl_6:
|
||||||
|
lbl_7:
|
||||||
|
lbl_8:
|
||||||
|
lbl_9:
|
||||||
|
lbl_10:
|
||||||
|
lbl_11:
|
||||||
|
lbl_12:
|
||||||
|
lbl_13:
|
||||||
|
lbl_14:
|
||||||
|
lbl_15:
|
||||||
|
lbl_16:
|
||||||
|
lbl_17:
|
||||||
|
lbl_18:
|
||||||
|
lbl_19:
|
||||||
|
lbl_20:
|
||||||
|
lbl_21:
|
||||||
|
lbl_22:
|
||||||
|
lbl_23:
|
||||||
|
lbl_24:
|
||||||
|
lbl_25:
|
||||||
|
lbl_26:
|
||||||
|
lbl_27:
|
||||||
|
lbl_28:
|
||||||
|
lbl_29:
|
||||||
|
lbl_30:
|
||||||
|
lbl_31:
|
||||||
|
lbl_32:
|
||||||
|
lbl_33:
|
||||||
|
lbl_34:
|
||||||
|
lbl_35:
|
||||||
|
lbl_36:
|
||||||
|
lbl_37:
|
||||||
|
lbl_38:
|
||||||
|
lbl_39:
|
||||||
|
lbl_40:
|
||||||
|
lbl_41:
|
||||||
|
lbl_42:
|
||||||
|
lbl_43:
|
||||||
|
lbl_44:
|
||||||
|
lbl_45:
|
||||||
|
lbl_46:
|
||||||
|
lbl_47:
|
||||||
|
lbl_48:
|
||||||
|
lbl_49:
|
||||||
|
lbl_50:
|
||||||
|
lbl_51:
|
||||||
|
lbl_52:
|
||||||
|
lbl_53:
|
||||||
|
lbl_54:
|
||||||
|
lbl_55:
|
||||||
|
lbl_56:
|
||||||
|
lbl_57:
|
||||||
|
lbl_58:
|
||||||
|
lbl_59:
|
||||||
|
lbl_60:
|
||||||
|
lbl_61:
|
||||||
|
lbl_62:
|
||||||
|
lbl_63:
|
||||||
|
lbl_64:
|
5
tests/input/regression/test_trivia_head.asm
Normal file
5
tests/input/regression/test_trivia_head.asm
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
; sample program with trivia on the head of the tokenlist
|
||||||
|
|
||||||
|
_start:
|
||||||
|
xor rax, rax
|
||||||
|
call exit
|
12
tests/input/symbols.asm
Normal file
12
tests/input/symbols.asm
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.import test
|
||||||
|
.export test
|
||||||
|
test:
|
||||||
|
call test
|
||||||
|
.import more
|
||||||
|
.export more
|
||||||
|
more:
|
||||||
|
call more
|
||||||
|
.import other
|
||||||
|
.export other
|
||||||
|
other:
|
||||||
|
call other
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
; Small valid code snippet that should contain all different AST nodes
|
; Small valid code snippet that should contain all different AST nodes
|
||||||
|
|
||||||
|
.export _start
|
||||||
|
.import exit
|
||||||
|
|
||||||
_start:
|
_start:
|
||||||
mov eax, ebx
|
mov eax, ebx
|
||||||
lea eax, [eax + ebx * 4 + 8]
|
lea eax, [eax + ebx * 4 + 8]
|
||||||
@ -19,3 +22,5 @@ _start:
|
|||||||
push 0xffff:64
|
push 0xffff:64
|
||||||
push 0o777:16
|
push 0o777:16
|
||||||
push 0b0001:16
|
push 0b0001:16
|
||||||
|
mov rax, 0
|
||||||
|
call exit
|
||||||
|
@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
extern MunitTest ast_tests[];
|
extern MunitTest ast_tests[];
|
||||||
extern MunitTest lexer_tests[];
|
extern MunitTest lexer_tests[];
|
||||||
|
extern MunitTest regression_tests[];
|
||||||
|
extern MunitTest symbols_tests[];
|
||||||
|
|
||||||
int main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
|
int main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
|
||||||
MunitSuite suites[] = {
|
MunitSuite suites[] = {
|
||||||
|
{"/regression", regression_tests, nullptr, 1, MUNIT_SUITE_OPTION_NONE},
|
||||||
{"/ast", ast_tests, nullptr, 1, MUNIT_SUITE_OPTION_NONE},
|
{"/ast", ast_tests, nullptr, 1, MUNIT_SUITE_OPTION_NONE},
|
||||||
{"/lexer", lexer_tests, nullptr, 1, MUNIT_SUITE_OPTION_NONE},
|
{"/lexer", lexer_tests, nullptr, 1, MUNIT_SUITE_OPTION_NONE},
|
||||||
|
{"/symbols", symbols_tests, nullptr, 1, MUNIT_SUITE_OPTION_NONE},
|
||||||
{nullptr, nullptr, nullptr, 0, MUNIT_SUITE_OPTION_NONE},
|
{nullptr, nullptr, nullptr, 0, MUNIT_SUITE_OPTION_NONE},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
31
tests/regression.c
Normal file
31
tests/regression.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "../src/ast.h"
|
||||||
|
#include "../src/parser/parser.h"
|
||||||
|
#include "munit.h"
|
||||||
|
|
||||||
|
MunitResult test_regression_trivia_head(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
lexer_t *lex = &(lexer_t){};
|
||||||
|
error_t *err = lexer_open(lex, "tests/input/regression/test_trivia_head.asm");
|
||||||
|
munit_assert_null(err);
|
||||||
|
|
||||||
|
tokenlist_t *list;
|
||||||
|
err = tokenlist_alloc(&list);
|
||||||
|
munit_assert_null(err);
|
||||||
|
|
||||||
|
err = tokenlist_fill(list, lex);
|
||||||
|
munit_assert_null(err);
|
||||||
|
|
||||||
|
parse_result_t result = parse(list->head);
|
||||||
|
munit_assert_null(result.err);
|
||||||
|
munit_assert_null(result.next);
|
||||||
|
|
||||||
|
ast_node_free(result.node);
|
||||||
|
tokenlist_free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitTest regression_tests[] = {
|
||||||
|
{"/trivia_head", test_regression_trivia_head, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{nullptr, nullptr, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}
|
||||||
|
};
|
351
tests/symbols.c
Normal file
351
tests/symbols.c
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
#include "../src/encoder/symbols.h"
|
||||||
|
#include "../src/ast.h"
|
||||||
|
#include "../src/error.h"
|
||||||
|
#include "../src/lexer.h"
|
||||||
|
#include "../src/parser/parser.h"
|
||||||
|
#include "munit.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void symbols_setup_test(ast_node_t **node, tokenlist_t **list, char *path) {
|
||||||
|
lexer_t *lex = &(lexer_t){};
|
||||||
|
lexer_open(lex, path);
|
||||||
|
tokenlist_alloc(list);
|
||||||
|
tokenlist_fill(*list, lex);
|
||||||
|
parse_result_t result = parse((*list)->head);
|
||||||
|
lexer_close(lex);
|
||||||
|
|
||||||
|
*node = result.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_table_alloc(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
error_t *err = symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
munit_assert_ptr_not_null(table);
|
||||||
|
munit_assert_ptr_null(err);
|
||||||
|
munit_assert_size(table->cap, ==, 64); // Default capacity
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
munit_assert_ptr_not_null(table->symbols);
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_table_lookup_empty(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, "nonexistent");
|
||||||
|
munit_assert_ptr_null(symbol);
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_add_reference(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/symbols.asm");
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
ast_node_t *reference = root->children[3]->children[1]->children[0]->children[0];
|
||||||
|
munit_assert_int(reference->id, ==, NODE_LABEL_REFERENCE);
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
|
||||||
|
error_t *err = symbol_table_update(table, reference);
|
||||||
|
munit_assert_null(err);
|
||||||
|
munit_assert_size(table->len, ==, 1);
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, "test");
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(SYMBOL_REFERENCE, ==, symbol->kind);
|
||||||
|
munit_assert_ptr_equal(reference, symbol->node);
|
||||||
|
munit_assert_string_equal(symbol->name, "test");
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_add_label(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/symbols.asm");
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
ast_node_t *label = root->children[2];
|
||||||
|
munit_assert_int(label->id, ==, NODE_LABEL);
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
|
||||||
|
error_t *err = symbol_table_update(table, label);
|
||||||
|
munit_assert_null(err);
|
||||||
|
munit_assert_size(table->len, ==, 1);
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, "test");
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(SYMBOL_LOCAL, ==, symbol->kind);
|
||||||
|
munit_assert_ptr_equal(label, symbol->node);
|
||||||
|
munit_assert_string_equal(symbol->name, "test");
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_add_import(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/symbols.asm");
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
ast_node_t *import_directive = root->children[0]->children[1];
|
||||||
|
munit_assert_int(import_directive->id, ==, NODE_IMPORT_DIRECTIVE);
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
|
||||||
|
error_t *err = symbol_table_update(table, import_directive);
|
||||||
|
munit_assert_null(err);
|
||||||
|
munit_assert_size(table->len, ==, 1);
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, "test");
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(SYMBOL_IMPORT, ==, symbol->kind);
|
||||||
|
munit_assert_ptr_equal(import_directive, symbol->node);
|
||||||
|
munit_assert_string_equal(symbol->name, "test");
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_symbol_update(const char *name, ast_node_t *first, symbol_kind_t first_kind, ast_node_t *second,
|
||||||
|
symbol_kind_t second_kind, bool should_succeed, bool should_update) {
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
error_t *err = symbol_table_update(table, first);
|
||||||
|
munit_assert_null(err);
|
||||||
|
munit_assert_size(table->len, ==, 1);
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, name);
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(first_kind, ==, symbol->kind);
|
||||||
|
munit_assert_ptr_equal(first, symbol->node);
|
||||||
|
munit_assert_string_equal(symbol->name, name);
|
||||||
|
|
||||||
|
err = symbol_table_update(table, second);
|
||||||
|
if (should_succeed)
|
||||||
|
munit_assert_null(err);
|
||||||
|
else
|
||||||
|
munit_assert_ptr_equal(err, err_symbol_table_incompatible_symbols);
|
||||||
|
munit_assert_size(table->len, ==, 1);
|
||||||
|
|
||||||
|
symbol = symbol_table_lookup(table, name);
|
||||||
|
if (should_update) {
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(second_kind, ==, symbol->kind);
|
||||||
|
munit_assert_ptr_equal(second, symbol->node);
|
||||||
|
munit_assert_string_equal(symbol->name, name);
|
||||||
|
} else {
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(first_kind, ==, symbol->kind);
|
||||||
|
munit_assert_ptr_equal(first, symbol->node);
|
||||||
|
munit_assert_string_equal(symbol->name, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_upgrade_valid(const MunitParameter params[], void *data) {
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/symbols.asm");
|
||||||
|
|
||||||
|
ast_node_t *reference = root->children[3]->children[1]->children[0]->children[0];
|
||||||
|
ast_node_t *label = root->children[2];
|
||||||
|
ast_node_t *import_directive = root->children[0]->children[1];
|
||||||
|
ast_node_t *export_directive = root->children[1]->children[1];
|
||||||
|
|
||||||
|
// real upgrades
|
||||||
|
test_symbol_update("test", reference, SYMBOL_REFERENCE, label, SYMBOL_LOCAL, true, true);
|
||||||
|
test_symbol_update("test", reference, SYMBOL_REFERENCE, import_directive, SYMBOL_IMPORT, true, true);
|
||||||
|
test_symbol_update("test", reference, SYMBOL_REFERENCE, export_directive, SYMBOL_EXPORT, true, true);
|
||||||
|
test_symbol_update("test", label, SYMBOL_LOCAL, export_directive, SYMBOL_EXPORT, true, true);
|
||||||
|
|
||||||
|
// identity upgrades
|
||||||
|
test_symbol_update("test", reference, SYMBOL_REFERENCE, reference, SYMBOL_REFERENCE, true, false);
|
||||||
|
test_symbol_update("test", label, SYMBOL_LOCAL, label, SYMBOL_LOCAL, true, false);
|
||||||
|
test_symbol_update("test", import_directive, SYMBOL_IMPORT, import_directive, SYMBOL_IMPORT, true, false);
|
||||||
|
test_symbol_update("test", export_directive, SYMBOL_EXPORT, export_directive, SYMBOL_EXPORT, true, false);
|
||||||
|
|
||||||
|
// downgrades that are allowed and ignored
|
||||||
|
test_symbol_update("test", label, SYMBOL_LOCAL, reference, SYMBOL_REFERENCE, true, false);
|
||||||
|
test_symbol_update("test", import_directive, SYMBOL_IMPORT, reference, SYMBOL_REFERENCE, true, false);
|
||||||
|
test_symbol_update("test", export_directive, SYMBOL_EXPORT, reference, SYMBOL_REFERENCE, true, false);
|
||||||
|
test_symbol_update("test", export_directive, SYMBOL_EXPORT, label, SYMBOL_LOCAL, true, false);
|
||||||
|
test_symbol_update("test", import_directive, SYMBOL_IMPORT, label, SYMBOL_LOCAL, true, false);
|
||||||
|
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_upgrade_invalid(const MunitParameter params[], void *data) {
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/symbols.asm");
|
||||||
|
|
||||||
|
ast_node_t *reference = root->children[3]->children[1]->children[0]->children[0];
|
||||||
|
ast_node_t *label = root->children[2];
|
||||||
|
ast_node_t *import_directive = root->children[0]->children[1];
|
||||||
|
ast_node_t *export_directive = root->children[1]->children[1];
|
||||||
|
|
||||||
|
// invalid upgrades
|
||||||
|
test_symbol_update("test", label, SYMBOL_LOCAL, import_directive, SYMBOL_IMPORT, false, false);
|
||||||
|
test_symbol_update("test", export_directive, SYMBOL_EXPORT, import_directive, SYMBOL_IMPORT, false, false);
|
||||||
|
test_symbol_update("test", import_directive, SYMBOL_IMPORT, export_directive, SYMBOL_EXPORT, false, false);
|
||||||
|
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_add_export(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/symbols.asm");
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
ast_node_t *export_directive = root->children[1]->children[1];
|
||||||
|
munit_assert_int(export_directive->id, ==, NODE_EXPORT_DIRECTIVE);
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
|
||||||
|
error_t *err = symbol_table_update(table, export_directive);
|
||||||
|
munit_assert_null(err);
|
||||||
|
munit_assert_size(table->len, ==, 1);
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, "test");
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(SYMBOL_EXPORT, ==, symbol->kind);
|
||||||
|
munit_assert_ptr_equal(export_directive, symbol->node);
|
||||||
|
munit_assert_string_equal(symbol->name, "test");
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_table_growth(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
|
||||||
|
// Set up with our manysymbols.asm file
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/manysymbols.asm");
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
// Initial capacity should be the default (64)
|
||||||
|
munit_assert_size(table->cap, ==, 64);
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
|
||||||
|
// Add the first 64 labels (indices 0-63)
|
||||||
|
size_t initial_cap = table->cap;
|
||||||
|
for (size_t i = 0; i < 64; i++) {
|
||||||
|
ast_node_t *label = root->children[i];
|
||||||
|
munit_assert_int(label->id, ==, NODE_LABEL);
|
||||||
|
|
||||||
|
error_t *err = symbol_table_update(table, label);
|
||||||
|
munit_assert_null(err);
|
||||||
|
munit_assert_size(table->len, ==, i + 1);
|
||||||
|
|
||||||
|
// Capacity should remain the same for the first 64 labels
|
||||||
|
munit_assert_size(table->cap, ==, initial_cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now add the 65th label (index 64), which should trigger growth
|
||||||
|
ast_node_t *final_label = root->children[64];
|
||||||
|
munit_assert_int(final_label->id, ==, NODE_LABEL);
|
||||||
|
|
||||||
|
error_t *err = symbol_table_update(table, final_label);
|
||||||
|
munit_assert_null(err);
|
||||||
|
munit_assert_size(table->len, ==, 65);
|
||||||
|
|
||||||
|
// Capacity should have doubled
|
||||||
|
munit_assert_size(table->cap, ==, initial_cap * 2);
|
||||||
|
|
||||||
|
// Validate we can look up all the symbols
|
||||||
|
for (size_t i = 0; i <= 64; i++) {
|
||||||
|
char name[10];
|
||||||
|
sprintf(name, "lbl_%zu", i);
|
||||||
|
|
||||||
|
symbol_t *symbol = symbol_table_lookup(table, name);
|
||||||
|
munit_assert_not_null(symbol);
|
||||||
|
munit_assert_int(SYMBOL_LOCAL, ==, symbol->kind);
|
||||||
|
munit_assert_string_equal(symbol->name, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitResult test_symbol_invalid_node(const MunitParameter params[], void *data) {
|
||||||
|
(void)params;
|
||||||
|
(void)data;
|
||||||
|
ast_node_t *root;
|
||||||
|
tokenlist_t *list;
|
||||||
|
symbol_table_t *table = nullptr;
|
||||||
|
symbols_setup_test(&root, &list, "tests/input/symbols.asm");
|
||||||
|
symbol_table_alloc(&table);
|
||||||
|
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
error_t *err = symbol_table_update(table, root);
|
||||||
|
munit_assert_ptr_equal(err, err_symbol_table_invalid_node);
|
||||||
|
munit_assert_size(table->len, ==, 0);
|
||||||
|
|
||||||
|
symbol_table_free(table);
|
||||||
|
ast_node_free(root);
|
||||||
|
tokenlist_free(list);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MunitTest symbols_tests[] = {
|
||||||
|
{"/table_alloc", test_symbol_table_alloc, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/table_lookup_empty", test_symbol_table_lookup_empty, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/add_reference", test_symbol_add_reference, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/add_label", test_symbol_add_label, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/add_import", test_symbol_add_import, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/add_export", test_symbol_add_export, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/upgrade_valid", test_symbol_upgrade_valid, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/upgrade_invalid", test_symbol_upgrade_invalid, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/table_growth", test_symbol_table_growth, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{"/invalid_node", test_symbol_invalid_node, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr},
|
||||||
|
{nullptr, nullptr, nullptr, nullptr, MUNIT_TEST_OPTION_NONE, nullptr}
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user