#include "onyxlex.h"
#include "onyxtypes.h"
-typedef struct AstNode AstNode;
-typedef struct AstTyped AstTyped;
typedef struct AstUnaryOp AstUnaryOp;
typedef struct AstBinOp AstBinaryOp;
typedef struct AstAssign AstAssign;
typedef struct AstWhile AstWhile;
typedef struct AstLocalGroup AstLocalGroup;
-typedef struct AstType AstType;
typedef struct AstBasicType AstBasicType;
typedef struct AstPointerType AstPointerType;
typedef struct AstFunctionType AstFunctionType;
// arguments existing in AstNode. I do this to avoid a nested
// "inheiritance" where you would have to say node.base.base.next
// for example
-struct AstNode {
- AstKind kind;
- u32 flags;
- OnyxToken *token;
- AstNode *next;
-};
-struct AstTyped {
- AstKind kind;
- u32 flags;
- OnyxToken *token;
- AstNode *next;
-
- // NOTE: 'type_node' is filled out by the parser.
- // For a type such as '^^i32', the tree would look something like
- //
- // Typed Thing -> AstPointerType -> AstPointerType -> AstNode (symbol node)
- //
- // The symbol node will be filled out during symbol resolution.
- // It will end up pointing to an AstBasicType that corresponds to
- // the underlying type.
- //
- // 'type' is filled out afterwards. If it is NULL, the Type* is built
- // using the type_node. This can then be used to typecheck this node.
- AstType *type_node;
- Type *type;
+#define AstNode_members { \
+ AstKind kind; \
+ u32 flags; \
+ OnyxToken *token; \
+ AstNode *next; \
};
+#define AstNode_base struct AstNode_members;
+
+typedef struct AstNode AstNode;
+struct AstNode AstNode_members;
+
+// Type Nodes
+// NOTE: This node is very similar to an AstNode, just
+// without the 'next' member. This is because types
+// can't be in expressions so a 'next' thing
+// doesn't make sense.
+#define AstType_members { AstKind kind; u32 flags; char* name; }
+#define AstType_base struct AstType_members;
+
+typedef struct AstType AstType;
+struct AstType AstType_members;
+
+// NOTE: 'type_node' is filled out by the parser. \
+// For a type such as '^^i32', the tree would look something like
+//
+// Typed Thing -> AstPointerType -> AstPointerType -> AstNode (symbol node)
+//
+// The symbol node will be filled out during symbol resolution.
+// It will end up pointing to an AstBasicType that corresponds to
+// the underlying type.
+//
+// 'type' is filled out afterwards. If it is NULL, the Type* is built
+// using the type_node. This can then be used to typecheck this node.
+#define AstTyped_members { \
+ AstKind kind; \
+ u32 flags; \
+ OnyxToken *token; \
+ AstNode *next; \
+ AstType *type_node; \
+ Type *type; \
+}
+#define AstTyped_base struct AstTyped_members;
+
+typedef struct AstTyped AstTyped;
+struct AstTyped AstTyped_members;
// Expression Nodes
-struct AstBinOp { AstTyped base; BinaryOp operation; AstTyped *left, *right; };
-struct AstUnaryOp { AstTyped base; UnaryOp operation; AstTyped *expr; };
-struct AstAssign { AstNode base; AstTyped* lval; AstTyped* expr; };
-struct AstNumLit { AstTyped base; union { i32 i; i64 l; f32 f; f64 d; } value; };
-struct AstLocal { AstTyped base; AstLocal *prev_local; };
-struct AstReturn { AstNode base; AstTyped* expr; };
-struct AstCall { AstTyped base; AstArgument *arguments; AstNode *callee; };
-struct AstArgument { AstTyped base; AstTyped *value; };
+struct AstBinOp { AstTyped_base; BinaryOp operation; AstTyped *left, *right; };
+struct AstUnaryOp { AstTyped_base; UnaryOp operation; AstTyped *expr; };
+struct AstAssign { AstNode_base; AstTyped* lval; AstTyped* expr; };
+struct AstNumLit { AstTyped_base; union { i32 i; i64 l; f32 f; f64 d; } value; };
+struct AstLocal { AstTyped_base; AstLocal *prev_local; };
+struct AstReturn { AstNode_base; AstTyped* expr; };
+struct AstCall { AstTyped_base; AstArgument *arguments; AstNode *callee; };
+struct AstArgument { AstTyped_base; AstTyped *value; };
// Structure Nodes
-struct AstLocalGroup { AstNode base; AstLocalGroup *prev_group; AstLocal *last_local; };
-struct AstBlock { AstNode base; AstNode *body; AstLocalGroup *locals; };
-struct AstWhile { AstNode base; AstTyped *cond; AstBlock *body; };
+struct AstLocalGroup { AstNode_base; AstLocalGroup *prev_group; AstLocal *last_local; };
+struct AstBlock { AstNode_base; AstNode *body; AstLocalGroup *locals; };
+struct AstWhile { AstNode_base; AstTyped *cond; AstBlock *body; };
struct AstIf {
- AstNode base;
+ AstNode_base;
AstTyped *cond;
union {
} true_block, false_block;
};
-// Type Nodes
-// NOTE: This node is very similar to an AstNode, just
-// without the 'next' member. This is because types
-// can't be in expressions so a 'next' thing
-// doesn't make sense.
-struct AstType { AstKind kind; u32 flags; char* name; };
-struct AstBasicType { AstType base; Type* type; };
-struct AstPointerType { AstType base; AstType* elem; };
-struct AstFunctionType { AstType base; AstType* return_type; u64 param_count; AstType* params[]; };
+struct AstBasicType { AstType_base; Type* type; };
+struct AstPointerType { AstType_base; AstType* elem; };
+struct AstFunctionType { AstType_base; AstType* return_type; u64 param_count; AstType* params[]; };
// Top level nodes
-struct AstBinding { AstTyped base; AstNode* node; };
-struct AstForeign { AstNode base; OnyxToken *mod_token, *name_token; AstNode *import; };
-struct AstUse { AstNode base; OnyxToken *filename; };
+struct AstBinding { AstTyped_base; AstNode* node; };
+struct AstForeign { AstNode_base; OnyxToken *mod_token, *name_token; AstNode *import; };
+struct AstUse { AstNode_base; OnyxToken *filename; };
struct AstGlobal {
- AstTyped base;
+ AstTyped_base;
union {
// NOTE: Used when a global is exported with a specific name
};
};
struct AstFunction {
- AstTyped base;
+ AstTyped_base;
AstBlock *body;
AstLocal *params;
// NOTE: This needs to have 'arguments' in the
// same position as AstNodeCall
-struct AstIntrinsicCall { AstTyped base; AstArgument *arguments; OnyxIntrinsic intrinsic; };
+struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; OnyxIntrinsic intrinsic; };
// NOTE: Simple data structure for storing what comes out of the parser
typedef struct ParserOutput {
#include "onyxastnodes.h"
#include "onyxmsgs.h"
-typedef struct SemPassSymbol {
+typedef struct SemSymbol {
AstNode *node;
- struct SemPassSymbol *shadowed;
-} SemPassSymbol;
+ struct SemSymbol *shadowed;
+} SemSymbol;
-typedef struct OnyxSemPassState {
+typedef struct SemState {
// NOTE: Adding node_allocator in case we need
// to make any more node in the tree
bh_allocator allocator, node_allocator;
Type* expected_return_type;
// NOTE: All symbols a given point that we can resolve
- bh_table(SemPassSymbol *) symbols;
-} OnyxSemPassState;
+ bh_table(SemSymbol *) symbols;
+} SemState;
// NOTE: Resolving all symbols in the tree
-void onyx_resolve_symbols(OnyxSemPassState* state, ParserOutput* program);
+void onyx_resolve_symbols(SemState* state, ParserOutput* program);
// NOTE: Inferring and checking types in the tree
-void onyx_type_check(OnyxSemPassState* state, ParserOutput* program);
+void onyx_type_check(SemState* state, ParserOutput* program);
// NOTE: Full semantic pass
-OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMessages* msgs);
-void onyx_sempass(OnyxSemPassState* state, ParserOutput* program);
+SemState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMessages* msgs);
+void onyx_sempass(SemState* state, ParserOutput* program);
#endif
typedef struct CompilerState {
OnyxCompileOptions* options;
- bh_arena ast_arena, msg_arena, sp_arena;
+ bh_arena ast_arena, msg_arena, sp_arena;
bh_allocator token_alloc, ast_alloc, msg_alloc, sp_alloc;
bh_table(bh_file_contents) loaded_files;
if (compiler_state->options->verbose_output)
bh_printf("[Checking semantics]\n");
- OnyxSemPassState sp_state = onyx_sempass_create(compiler_state->sp_alloc, compiler_state->ast_alloc, &compiler_state->msgs);
+ SemState sp_state = onyx_sempass_create(compiler_state->sp_alloc, compiler_state->ast_alloc, &compiler_state->msgs);
onyx_sempass(&sp_state, &compiler_state->parse_output);
if (onyx_message_has_errors(&compiler_state->msgs)) {
global_heap_allocator = bh_managed_heap_allocator(&global_heap);
OnyxCompileOptions compile_opts = compile_opts_parse(global_heap_allocator, argc, argv);
- CompilerState compile_state = {
- .parse_output = {
- .top_level_bindings = NULL,
- .nodes_to_process = NULL,
-
- .functions = NULL,
- .globals = NULL,
- },
- .wasm_mod = { 0 }
- };
+ CompilerState compile_state = { 0 };
compiler_state_init(&compile_state, &compile_opts);
CompilerProgress compiler_progress = ONYX_COMPILER_PROGRESS_FAILED_READ;
#define BH_DEBUG
#include "onyxsempass.h"
-static b32 check_function(OnyxSemPassState* state, AstFunction* func);
-static b32 check_block(OnyxSemPassState* state, AstBlock* block);
-static b32 check_statement_chain(OnyxSemPassState* state, AstNode* start);
-static b32 check_statement(OnyxSemPassState* state, AstNode* stmt);
-static b32 check_assignment(OnyxSemPassState* state, AstAssign* assign);
-static b32 check_return(OnyxSemPassState* state, AstReturn* retnode);
-static b32 check_if(OnyxSemPassState* state, AstIf* ifnode);
-static b32 check_while(OnyxSemPassState* state, AstWhile* whilenode);
-static b32 check_call(OnyxSemPassState* state, AstCall* call);
-static b32 check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop);
-static b32 check_expression(OnyxSemPassState* state, AstTyped* expr);
-static b32 check_global(OnyxSemPassState* state, AstGlobal* global);
-
-static b32 check_assignment(OnyxSemPassState* state, AstAssign* assign) {
+static b32 check_function(SemState* state, AstFunction* func);
+static b32 check_block(SemState* state, AstBlock* block);
+static b32 check_statement_chain(SemState* state, AstNode* start);
+static b32 check_statement(SemState* state, AstNode* stmt);
+static b32 check_assignment(SemState* state, AstAssign* assign);
+static b32 check_return(SemState* state, AstReturn* retnode);
+static b32 check_if(SemState* state, AstIf* ifnode);
+static b32 check_while(SemState* state, AstWhile* whilenode);
+static b32 check_call(SemState* state, AstCall* call);
+static b32 check_binaryop(SemState* state, AstBinaryOp* binop);
+static b32 check_expression(SemState* state, AstTyped* expr);
+static b32 check_global(SemState* state, AstGlobal* global);
+
+static b32 check_assignment(SemState* state, AstAssign* assign) {
if (assign->lval->kind == Ast_Kind_Symbol) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL,
if ((assign->lval->flags & Ast_Flag_Const) != 0 && assign->lval->type != NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_ASSIGN_CONST,
- assign->base.token->pos,
+ assign->token->pos,
assign->lval->token->text, assign->lval->token->length);
return 1;
}
if ((assign->lval->flags & Ast_Flag_Lval) == 0) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_NOT_LVAL,
- assign->base.token->pos,
+ assign->token->pos,
assign->lval->token->text, assign->lval->token->length);
return 1;
}
if (!types_are_compatible(assign->lval->type, assign->expr->type)) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH,
- assign->base.token->pos,
+ assign->token->pos,
type_get_name(assign->lval->type),
type_get_name(assign->expr->type));
return 1;
return 0;
}
-static b32 check_return(OnyxSemPassState* state, AstReturn* retnode) {
+static b32 check_return(SemState* state, AstReturn* retnode) {
if (retnode->expr) {
if (check_expression(state, retnode->expr)) return 1;
if (state->expected_return_type->Basic.size > 0) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- retnode->base.token->pos,
+ retnode->token->pos,
"returning from non-void function without value");
return 1;
}
return 0;
}
-static b32 check_if(OnyxSemPassState* state, AstIf* ifnode) {
+static b32 check_if(SemState* state, AstIf* ifnode) {
if (check_expression(state, ifnode->cond)) return 1;
if (!type_is_bool(ifnode->cond->type)) {
return 0;
}
-static b32 check_while(OnyxSemPassState* state, AstWhile* whilenode) {
+static b32 check_while(SemState* state, AstWhile* whilenode) {
if (check_expression(state, whilenode->cond)) return 1;
if (!type_is_bool(whilenode->cond->type)) {
return check_block(state, whilenode->body);
}
-static b32 check_call(OnyxSemPassState* state, AstCall* call) {
+static b32 check_call(SemState* state, AstCall* call) {
AstFunction* callee = (AstFunction *) call->callee;
- if (callee->base.kind == Ast_Kind_Symbol) {
+ if (callee->kind == Ast_Kind_Symbol) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL,
- callee->base.token->pos,
- callee->base.token->text, callee->base.token->length);
+ callee->token->pos,
+ callee->token->text, callee->token->length);
return 1;
}
- if (callee->base.type == NULL) {
- callee->base.type = type_build_from_ast(state->node_allocator, callee->base.type_node);
+ if (callee->type == NULL) {
+ callee->type = type_build_from_ast(state->node_allocator, callee->type_node);
}
- if (callee->base.type->kind != Type_Kind_Function) {
+ if (callee->type->kind != Type_Kind_Function) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_CALL_NON_FUNCTION,
- call->base.token->pos,
- callee->base.token->text, callee->base.token->length);
+ call->token->pos,
+ callee->token->text, callee->token->length);
return 1;
}
// NOTE: If we calling an intrinsic function, translate the
// call into an intrinsic call node.
- if (callee->base.flags & Ast_Flag_Intrinsic) {
- call->base.kind = Ast_Kind_Intrinsic_Call;
+ if (callee->flags & Ast_Flag_Intrinsic) {
+ call->kind = Ast_Kind_Intrinsic_Call;
call->callee = NULL;
token_toggle_end(callee->intrinsic_name);
token_toggle_end(callee->intrinsic_name);
}
- call->base.type = callee->base.type->Function.return_type;
+ call->type = callee->type->Function.return_type;
AstLocal* formal_param = callee->params;
AstArgument* actual_param = call->arguments;
while (formal_param != NULL && actual_param != NULL) {
if (check_expression(state, (AstTyped *) actual_param)) return 1;
- if (formal_param->base.type == NULL) {
- formal_param->base.type = type_build_from_ast(state->node_allocator, formal_param->base.type_node);
+ if (formal_param->type == NULL) {
+ formal_param->type = type_build_from_ast(state->node_allocator, formal_param->type_node);
}
- if (!types_are_compatible(formal_param->base.type, actual_param->base.type)) {
+ if (!types_are_compatible(formal_param->type, actual_param->type)) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_FUNCTION_PARAM_TYPE_MISMATCH,
- actual_param->base.token->pos,
- callee->base.token->text, callee->base.token->length,
- type_get_name(formal_param->base.type),
+ actual_param->token->pos,
+ callee->token->text, callee->token->length,
+ type_get_name(formal_param->type),
arg_pos,
- type_get_name(actual_param->base.type));
+ type_get_name(actual_param->type));
return 1;
}
arg_pos++;
- formal_param = (AstLocal *) formal_param->base.next;
- actual_param = (AstArgument *) actual_param->base.next;
+ formal_param = (AstLocal *) formal_param->next;
+ actual_param = (AstArgument *) actual_param->next;
}
if (formal_param != NULL && actual_param == NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- call->base.token->pos,
+ call->token->pos,
"too few arguments to function call");
return 1;
}
if (formal_param == NULL && actual_param != NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- call->base.token->pos,
+ call->token->pos,
"too many arguments to function call");
return 1;
}
return 0;
}
-static b32 check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) {
+static b32 check_binaryop(SemState* state, AstBinaryOp* binop) {
if (check_expression(state, binop->left)) return 1;
if (check_expression(state, binop->right)) return 1;
if (binop->left->type == NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
- binop->base.token->pos,
+ binop->token->pos,
NULL, 0);
return 1;
}
if (binop->right->type == NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
- binop->base.token->pos,
+ binop->token->pos,
NULL, 0);
return 1;
}
|| type_is_pointer(binop->right->type)) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- binop->base.token->pos,
+ binop->token->pos,
"binary operations are not supported for pointers (yet).");
return 1;
}
if (!types_are_compatible(binop->left->type, binop->right->type)) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
- binop->base.token->pos,
+ binop->token->pos,
type_get_name(binop->left->type),
type_get_name(binop->right->type));
return 1;
if (binop->operation >= Binary_Op_Equal
&& binop->operation <= Binary_Op_Greater_Equal) {
- binop->base.type = &basic_types[Basic_Kind_Bool];
+ binop->type = &basic_types[Basic_Kind_Bool];
} else {
- binop->base.type = binop->left->type;
+ binop->type = binop->left->type;
}
return 0;
}
-static b32 check_expression(OnyxSemPassState* state, AstTyped* expr) {
+static b32 check_expression(SemState* state, AstTyped* expr) {
if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
return retval;
}
-static b32 check_global(OnyxSemPassState* state, AstGlobal* global) {
- if (global->base.type == NULL)
- global->base.type = type_build_from_ast(state->allocator, global->base.type_node);
+static b32 check_global(SemState* state, AstGlobal* global) {
+ if (global->type == NULL)
+ global->type = type_build_from_ast(state->allocator, global->type_node);
- if (global->base.type == NULL) {
+ if (global->type == NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
- global->base.token->pos,
+ global->token->pos,
global->exported_name->text,
global->exported_name->length);
return 0;
}
-static b32 check_statement(OnyxSemPassState* state, AstNode* stmt) {
+static b32 check_statement(SemState* state, AstNode* stmt) {
switch (stmt->kind) {
case Ast_Kind_Assignment: return check_assignment(state, (AstAssign *) stmt);
case Ast_Kind_Return: return check_return(state, (AstReturn *) stmt);
}
}
-static b32 check_statement_chain(OnyxSemPassState* state, AstNode* start) {
+static b32 check_statement_chain(SemState* state, AstNode* start) {
while (start) {
if (check_statement(state, start)) return 1;
start = start->next;
return 0;
}
-static b32 check_block(OnyxSemPassState* state, AstBlock* block) {
+static b32 check_block(SemState* state, AstBlock* block) {
if (check_statement_chain(state, block->body)) return 1;
forll(AstLocal, local, block->locals->last_local, prev_local) {
- if (local->base.type == NULL) {
+ if (local->type == NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
- local->base.token->pos,
- local->base.token->text, local->base.token->length);
+ local->token->pos,
+ local->token->text, local->token->length);
return 1;
}
}
return 0;
}
-static b32 check_function(OnyxSemPassState* state, AstFunction* func) {
- for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) {
- if (param->base.type == NULL) {
- param->base.type = type_build_from_ast(state->node_allocator, param->base.type_node);
+static b32 check_function(SemState* state, AstFunction* func) {
+ for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
+ if (param->type == NULL) {
+ param->type = type_build_from_ast(state->node_allocator, param->type_node);
}
- if (param->base.type == NULL) {
+ if (param->type == NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- param->base.token->pos,
+ param->token->pos,
"function parameter types must be known");
return 1;
}
- if (param->base.type->Basic.size == 0) {
+ if (param->type->Basic.size == 0) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- param->base.token->pos,
+ param->token->pos,
"function parameters must have non-void types");
return 1;
}
}
- if (func->base.type == NULL) {
- func->base.type = type_build_from_ast(state->node_allocator, func->base.type_node);
+ if (func->type == NULL) {
+ func->type = type_build_from_ast(state->node_allocator, func->type_node);
}
- if ((func->base.flags & Ast_Flag_Exported) != 0) {
- if ((func->base.flags & Ast_Flag_Foreign) != 0) {
+ if ((func->flags & Ast_Flag_Exported) != 0) {
+ if ((func->flags & Ast_Flag_Foreign) != 0) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- func->base.token->pos,
+ func->token->pos,
"exporting a foreign function");
return 1;
}
- if ((func->base.flags & Ast_Flag_Intrinsic) != 0) {
+ if ((func->flags & Ast_Flag_Intrinsic) != 0) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- func->base.token->pos,
+ func->token->pos,
"exporting a intrinsic function");
return 1;
}
- if ((func->base.flags & Ast_Flag_Inline) != 0) {
+ if ((func->flags & Ast_Flag_Inline) != 0) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- func->base.token->pos,
+ func->token->pos,
"exporting a inlined function");
return 1;
}
if (func->exported_name == NULL) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
- func->base.token->pos,
+ func->token->pos,
"exporting function without a name");
return 1;
}
}
- state->expected_return_type = func->base.type->Function.return_type;
+ state->expected_return_type = func->type->Function.return_type;
if (func->body) {
return check_block(state, func->body);
}
return 0;
}
-static b32 check_node(OnyxSemPassState* state, AstNode* node) {
+static b32 check_node(SemState* state, AstNode* node) {
switch (node->kind) {
case Ast_Kind_Function: return check_function(state, (AstFunction *) node);
case Ast_Kind_Block: return check_block(state, (AstBlock *) node);
}
}
-void onyx_type_check(OnyxSemPassState* state, ParserOutput* program) {
+void onyx_type_check(SemState* state, ParserOutput* program) {
bh_arr_each(AstNode *, node, program->nodes_to_process) {
check_node(state, *node);
static AstNumLit* parse_numeric_literal(OnyxParser* parser) {
AstNumLit* lit_node = make_node(AstNumLit, Ast_Kind_Literal);
- lit_node->base.token = expect_token(parser, Token_Type_Literal_Numeric);
- lit_node->base.flags |= Ast_Flag_Comptime;
+ lit_node->token = expect_token(parser, Token_Type_Literal_Numeric);
+ lit_node->flags |= Ast_Flag_Comptime;
lit_node->value.l = 0ll;
AstType* type;
- token_toggle_end(lit_node->base.token);
- char* tok = lit_node->base.token->text;
+ token_toggle_end(lit_node->token);
+ char* tok = lit_node->token->text;
// NOTE: charset_contains() behaves more like string_contains()
// so I'm using it in this case
if (charset_contains(tok, '.')) {
- if (tok[lit_node->base.token->length - 1] == 'f') {
+ if (tok[lit_node->token->length - 1] == 'f') {
type = (AstType *) &basic_type_f32;
lit_node->value.f = strtof(tok, NULL);
} else {
lit_node->value.l = value;
}
- lit_node->base.type_node = type;
- token_toggle_end(lit_node->base.token);
+ lit_node->type_node = type;
+ token_toggle_end(lit_node->token);
return lit_node;
}
negate_node->expr = factor;
if ((factor->flags & Ast_Flag_Comptime) != 0) {
- negate_node->base.flags |= Ast_Flag_Comptime;
+ negate_node->flags |= Ast_Flag_Comptime;
}
retval = (AstTyped *) negate_node;
{
AstUnaryOp* not_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
not_node->operation = Unary_Op_Not;
- not_node->base.token = expect_token(parser, '!');
+ not_node->token = expect_token(parser, '!');
not_node->expr = parse_factor(parser);
if ((not_node->expr->flags & Ast_Flag_Comptime) != 0) {
- not_node->base.flags |= Ast_Flag_Comptime;
+ not_node->flags |= Ast_Flag_Comptime;
}
retval = (AstTyped *) not_node;
// NOTE: Function call
AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
- call_node->base.token = expect_token(parser, '(');
+ call_node->token = expect_token(parser, '(');
call_node->callee = (AstNode *) sym_node;
AstArgument** prev = &call_node->arguments;
AstArgument* curr = NULL;
while (parser->curr->type != ')') {
curr = make_node(AstArgument, Ast_Kind_Argument);
- curr->base.token = parser->curr;
+ curr->token = parser->curr;
curr->value = parse_expression(parser);
- if (curr != NULL && curr->base.kind != Ast_Kind_Error) {
+ if (curr != NULL && curr->kind != Ast_Kind_Error) {
*prev = curr;
- prev = (AstArgument **) &curr->base.next;
+ prev = (AstArgument **) &curr->next;
}
if (parser->curr->type == ')')
case Token_Type_Literal_True:
{
AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal);
- bool_node->base.type_node = (AstType *) &basic_type_bool;
- bool_node->base.token = expect_token(parser, Token_Type_Literal_True);
+ bool_node->type_node = (AstType *) &basic_type_bool;
+ bool_node->token = expect_token(parser, Token_Type_Literal_True);
bool_node->value.i = 1;
retval = (AstTyped *) bool_node;
break;
case Token_Type_Literal_False:
{
AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal);
- bool_node->base.type_node = (AstType *) &basic_type_bool;
- bool_node->base.token = expect_token(parser, Token_Type_Literal_False);
+ bool_node->type_node = (AstType *) &basic_type_bool;
+ bool_node->token = expect_token(parser, Token_Type_Literal_False);
bool_node->value.i = 0;
retval = (AstTyped *) bool_node;
break;
consume_token(parser);
AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
- cast_node->base.type_node = parse_type(parser);
+ cast_node->type_node = parse_type(parser);
cast_node->operation = Unary_Op_Cast;
cast_node->expr = retval;
retval = (AstTyped *) cast_node;
AstBinaryOp* bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
bin_op->operation = bin_op_kind;
- bin_op->base.token = bin_op_tok;
+ bin_op->token = bin_op_tok;
while ( !bh_arr_is_empty(tree_stack) &&
get_precedence(bh_arr_last(tree_stack)->operation) >= get_precedence(bin_op_kind))
bin_op->right = right;
if ((left->flags & Ast_Flag_Comptime) != 0 && (right->flags & Ast_Flag_Comptime) != 0) {
- bin_op->base.flags |= Ast_Flag_Comptime;
+ bin_op->flags |= Ast_Flag_Comptime;
}
}
}
AstBlock* body = parse_block(parser);
AstWhile* while_node = make_node(AstWhile, Ast_Kind_While);
- while_node->base.token = while_token;
+ while_node->token = while_token;
while_node->cond = cond;
while_node->body = body;
}
AstLocal* local = make_node(AstLocal, Ast_Kind_Local);
- local->base.token = symbol;
- local->base.type_node = type_node;
- local->base.flags |= Ast_Flag_Lval; // NOTE: DELETE
+ local->token = symbol;
+ local->type_node = type_node;
+ local->flags |= Ast_Flag_Lval; // NOTE: DELETE
*ret = (AstNode *) local;
if (parser->curr->type == '=' || parser->curr->type == ':') {
if (parser->curr->type == ':') {
- local->base.flags |= Ast_Flag_Const;
+ local->flags |= Ast_Flag_Const;
}
AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment);
- local->base.next = (AstNode *) assignment;
- assignment->base.token = parser->curr;
+ local->next = (AstNode *) assignment;
+ assignment->token = parser->curr;
consume_token(parser);
AstTyped* expr = parse_expression(parser);
token_toggle_end(parser->curr);
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_EXPECTED_EXPRESSION,
- assignment->base.token->pos,
+ assignment->token->pos,
parser->curr->text);
token_toggle_end(parser->curr);
return 1;
case '=':
{
AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment);
- assignment->base.token = parser->curr;
+ assignment->token = parser->curr;
consume_token(parser);
AstNode* lval = make_node(AstNode, Ast_Kind_Symbol);
AstBinaryOp* bin_op_node = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
bin_op_node->operation = bin_op;
- bin_op_node->base.token = parser->curr;
+ bin_op_node->token = parser->curr;
consume_token(parser);
AstTyped* expr = parse_expression(parser);
bin_op_node->right = expr;
AstAssign* assign_node = make_node(AstAssign, Ast_Kind_Assignment);
- assign_node->base.token = bin_op_node->base.token;
+ assign_node->token = bin_op_node->token;
// TODO: Maybe I don't need to make another lval node?
AstNode* lval = make_node(AstNode, Ast_Kind_Symbol);
// 'return' <expr>?
static AstReturn* parse_return_statement(OnyxParser* parser) {
AstReturn* return_node = make_node(AstReturn, Ast_Kind_Return);
- return_node->base.token = expect_token(parser, Token_Type_Keyword_Return);
+ return_node->token = expect_token(parser, Token_Type_Keyword_Return);
AstTyped* expr = NULL;
if (parser->curr->type == '^') {
consume_token(parser);
AstPointerType* new = make_node(AstPointerType, Ast_Kind_Pointer_Type);
- new->base.flags |= Basic_Flag_Pointer;
+ new->flags |= Basic_Flag_Pointer;
*next_insertion = (AstType *) new;
next_insertion = &new->elem;
}
expect_token(parser, ':');
curr_param = make_node(AstLocal, Ast_Kind_Param);
- curr_param->base.token = symbol;
- curr_param->base.flags |= Ast_Flag_Const;
- curr_param->base.type_node = parse_type(parser);
+ curr_param->token = symbol;
+ curr_param->flags |= Ast_Flag_Const;
+ curr_param->type_node = parse_type(parser);
if (first_param == NULL) first_param = curr_param;
- curr_param->base.next = NULL;
- if (trailer) trailer->base.next = (AstNode *) curr_param;
+ curr_param->next = NULL;
+ if (trailer) trailer->next = (AstNode *) curr_param;
trailer = curr_param;
}
static AstFunction* parse_function_definition(OnyxParser* parser) {
AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function);
- func_def->base.token = expect_token(parser, Token_Type_Keyword_Proc);
+ func_def->token = expect_token(parser, Token_Type_Keyword_Proc);
while (parser->curr->type == '#') {
if (parse_possible_directive(parser, "intrinsic")) {
- func_def->base.flags |= Ast_Flag_Intrinsic;
+ func_def->flags |= Ast_Flag_Intrinsic;
if (parser->curr->type == Token_Type_Literal_String) {
OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
}
else if (parse_possible_directive(parser, "inline")) {
- func_def->base.flags |= Ast_Flag_Inline;
+ func_def->flags |= Ast_Flag_Inline;
}
else if (parse_possible_directive(parser, "foreign")) {
func_def->foreign_module = expect_token(parser, Token_Type_Literal_String);
func_def->foreign_name = expect_token(parser, Token_Type_Literal_String);
- func_def->base.flags |= Ast_Flag_Foreign;
+ func_def->flags |= Ast_Flag_Foreign;
}
else if (parse_possible_directive(parser, "export")) {
- func_def->base.flags |= Ast_Flag_Exported;
+ func_def->flags |= Ast_Flag_Exported;
if (parser->curr->type == Token_Type_Literal_String) {
OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
u64 param_count = 0;
for (AstLocal* param = params;
param != NULL;
- param = (AstLocal *) param->base.next)
+ param = (AstLocal *) param->next)
param_count++;
AstFunctionType* type_node = bh_alloc(parser->allocator, sizeof(AstFunctionType) + param_count * sizeof(AstType *));
- type_node->base.kind = Ast_Kind_Function_Type;
+ type_node->kind = Ast_Kind_Function_Type;
type_node->param_count = param_count;
type_node->return_type = return_type;
u32 i = 0;
for (AstLocal* param = params;
param != NULL;
- param = (AstLocal *) param->base.next) {
- type_node->params[i] = param->base.type_node;
+ param = (AstLocal *) param->next) {
+ type_node->params[i] = param->type_node;
i++;
}
- func_def->base.type_node = (AstType *) type_node;
+ func_def->type_node = (AstType *) type_node;
func_def->body = parse_block(parser);
// 'global' <type>
static AstTyped* parse_global_declaration(OnyxParser* parser) {
AstGlobal* global_node = make_node(AstGlobal, Ast_Kind_Global);
- global_node->base.token = expect_token(parser, Token_Type_Keyword_Global);
+ global_node->token = expect_token(parser, Token_Type_Keyword_Global);
while (parser->curr->type == '#') {
if (parse_possible_directive(parser, "foreign")) {
global_node->foreign_module = expect_token(parser, Token_Type_Literal_String);
global_node->foreign_name = expect_token(parser, Token_Type_Literal_String);
- global_node->base.flags |= Ast_Flag_Foreign;
+ global_node->flags |= Ast_Flag_Foreign;
}
else if (parse_possible_directive(parser, "export")) {
- global_node->base.flags |= Ast_Flag_Exported;
+ global_node->flags |= Ast_Flag_Exported;
if (parser->curr->type == Token_Type_Literal_String) {
OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
}
}
- global_node->base.type_node = parse_type(parser);
- global_node->base.flags |= Ast_Flag_Lval;
+ global_node->type_node = parse_type(parser);
+ global_node->flags |= Ast_Flag_Lval;
bh_arr_push(parser->results.nodes_to_process, (AstNode *) global_node);
case Token_Type_Keyword_Use:
{
AstUse* use_node = make_node(AstUse, Ast_Kind_Use);
- use_node->base.token = expect_token(parser, Token_Type_Keyword_Use);
+ use_node->token = expect_token(parser, Token_Type_Keyword_Use);
use_node->filename = expect_token(parser, Token_Type_Literal_String);
return (AstNode *) use_node;
}
AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
- binding->base.token = symbol;
+ binding->token = symbol;
binding->node = (AstNode *) node;
return (AstNode *) binding;
#include "onyxsempass.h"
#include "onyxutils.h"
-OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMessages* msgs) {
- OnyxSemPassState state = {
+SemState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMessages* msgs) {
+ SemState state = {
.allocator = alloc,
.node_allocator = node_alloc,
// WASM, this function may not be needed. It brings all of the locals
// defined in sub-scopes up to the function-block level. This is a
// requirement of WASM, but not of other targets.
-static void collapse_scopes(ParserOutput* program) {
+static void hoist_locals(ParserOutput* program) {
bh_arr(AstBlock*) traversal_queue = NULL;
bh_arr_new(global_scratch_allocator, traversal_queue, 4);
bh_arr_set_length(traversal_queue, 0);
bh_arr_each(AstFunction *, func, program->functions) {
- if ((*func)->base.flags & Ast_Flag_Intrinsic) continue;
+ if ((*func)->flags & Ast_Flag_Intrinsic) continue;
AstLocalGroup* top_locals = (*func)->body->locals;
while (!bh_arr_is_empty(traversal_queue)) {
AstBlock* block = traversal_queue[0];
- if (block->base.kind == Ast_Kind_If) {
+ if (block->kind == Ast_Kind_If) {
AstIf* if_node = (AstIf *) block;
if (if_node->true_block.as_block != NULL)
bh_arr_push(traversal_queue, if_node->true_block.as_block);
}
}
-void onyx_sempass(OnyxSemPassState* state, ParserOutput* program) {
+void onyx_sempass(SemState* state, ParserOutput* program) {
onyx_resolve_symbols(state, program);
if (onyx_message_has_errors(state->msgs)) return;
onyx_type_check(state, program);
if (onyx_message_has_errors(state->msgs)) return;
- collapse_scopes(program);
+ hoist_locals(program);
}
#define BH_DEBUG
#include "onyxsempass.h"
-static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol);
-static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* basic_type);
-static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol);
-static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn);
-static AstNode* symbol_resolve(OnyxSemPassState* state, OnyxToken* tkn);
-static void local_group_enter(OnyxSemPassState* state, AstLocalGroup* local_group);
-static void local_group_leave(OnyxSemPassState* state);
-
-static AstType* symres_type(OnyxSemPassState* state, AstType* type);
-static void symres_local(OnyxSemPassState* state, AstLocal** local);
-static void symres_call(OnyxSemPassState* state, AstCall* call);
-static void symres_expression(OnyxSemPassState* state, AstTyped** expr);
-static void symres_assignment(OnyxSemPassState* state, AstAssign* assign);
-static void symres_return(OnyxSemPassState* state, AstReturn* ret);
-static void symres_if(OnyxSemPassState* state, AstIf* ifnode);
-static void symres_while(OnyxSemPassState* state, AstWhile* whilenode);
-static void symres_statement_chain(OnyxSemPassState* state, AstNode* walker, AstNode** trailer);
-static b32 symres_statement(OnyxSemPassState* state, AstNode* stmt);
-static void symres_block(OnyxSemPassState* state, AstBlock* block);
-static void symres_function(OnyxSemPassState* state, AstFunction* func);
-static void symres_global(OnyxSemPassState* state, AstGlobal* global);
-
-static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) {
+static void symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol);
+static void symbol_basic_type_introduce(SemState* state, AstBasicType* basic_type);
+static b32 symbol_unique_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol);
+static void symbol_remove(SemState* state, OnyxToken* tkn);
+static AstNode* symbol_resolve(SemState* state, OnyxToken* tkn);
+static void local_group_enter(SemState* state, AstLocalGroup* local_group);
+static void local_group_leave(SemState* state);
+
+static AstType* symres_type(SemState* state, AstType* type);
+static void symres_local(SemState* state, AstLocal** local);
+static void symres_call(SemState* state, AstCall* call);
+static void symres_expression(SemState* state, AstTyped** expr);
+static void symres_assignment(SemState* state, AstAssign* assign);
+static void symres_return(SemState* state, AstReturn* ret);
+static void symres_if(SemState* state, AstIf* ifnode);
+static void symres_while(SemState* state, AstWhile* whilenode);
+static void symres_statement_chain(SemState* state, AstNode* walker, AstNode** trailer);
+static b32 symres_statement(SemState* state, AstNode* stmt);
+static void symres_block(SemState* state, AstBlock* block);
+static void symres_function(SemState* state, AstFunction* func);
+static void symres_global(SemState* state, AstGlobal* global);
+
+static void symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol) {
token_toggle_end(tkn);
- SemPassSymbol* sp_sym = (SemPassSymbol *) bh_alloc_item(state->allocator, SemPassSymbol);
+ SemSymbol* sp_sym = (SemSymbol *) bh_alloc_item(state->allocator, SemSymbol);
sp_sym->node = symbol;
sp_sym->shadowed = NULL;
- if (bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
- sp_sym->shadowed = bh_table_get(SemPassSymbol *, state->symbols, tkn->text);
+ if (bh_table_has(SemSymbol *, state->symbols, tkn->text)) {
+ sp_sym->shadowed = bh_table_get(SemSymbol *, state->symbols, tkn->text);
}
- bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym);
+ bh_table_put(SemSymbol *, state->symbols, tkn->text, sp_sym);
if (symbol->kind == Ast_Kind_Local) {
AstLocal* local = (AstLocal *) symbol;
token_toggle_end(tkn);
}
-static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn) {
+static void symbol_remove(SemState* state, OnyxToken* tkn) {
token_toggle_end(tkn);
- SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, tkn->text);
+ SemSymbol* sp_sym = bh_table_get(SemSymbol *, state->symbols, tkn->text);
if (sp_sym->shadowed) {
- bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym->shadowed);
+ bh_table_put(SemSymbol *, state->symbols, tkn->text, sp_sym->shadowed);
} else {
- bh_table_delete(SemPassSymbol *, state->symbols, tkn->text);
+ bh_table_delete(SemSymbol *, state->symbols, tkn->text);
}
token_toggle_end(tkn);
}
-static AstNode* symbol_resolve(OnyxSemPassState* state, OnyxToken* tkn) {
+static AstNode* symbol_resolve(SemState* state, OnyxToken* tkn) {
AstNode* res = NULL;
while (res == NULL || res->kind == Ast_Kind_Symbol) {
token_toggle_end(tkn);
- if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
+ if (!bh_table_has(SemSymbol *, state->symbols, tkn->text)) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
tkn->pos,
return NULL;
}
- res = bh_table_get(SemPassSymbol *, state->symbols, tkn->text)->node;
+ res = bh_table_get(SemSymbol *, state->symbols, tkn->text)->node;
token_toggle_end(tkn);
tkn = res->token;
return res;
}
-static void local_group_enter(OnyxSemPassState* state, AstLocalGroup* local_group) {
+static void local_group_enter(SemState* state, AstLocalGroup* local_group) {
local_group->prev_group = state->curr_local_group;
state->curr_local_group = local_group;
}
-static void local_group_leave(OnyxSemPassState* state) {
+static void local_group_leave(SemState* state) {
assert(state->curr_local_group != NULL);
for (AstLocal *walker = state->curr_local_group->last_local; walker != NULL; walker = walker->prev_local) {
- symbol_remove(state, walker->base.token);
+ symbol_remove(state, walker->token);
}
state->curr_local_group = state->curr_local_group->prev_group;
}
-static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* basic_type) {
- SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol);
+static void symbol_basic_type_introduce(SemState* state, AstBasicType* basic_type) {
+ SemSymbol* sp_sym = bh_alloc_item(state->allocator, SemSymbol);
sp_sym->node = (AstNode *) basic_type;
sp_sym->shadowed = NULL;
- bh_table_put(SemPassSymbol *, state->symbols, basic_type->base.name, sp_sym);
+ bh_table_put(SemSymbol *, state->symbols, basic_type->name, sp_sym);
}
-static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) {
+static b32 symbol_unique_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol) {
token_toggle_end(tkn);
// NOTE: If the function hasn't already been defined
- if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
- SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol);
+ if (!bh_table_has(SemSymbol *, state->symbols, tkn->text)) {
+ SemSymbol* sp_sym = bh_alloc_item(state->allocator, SemSymbol);
sp_sym->node = symbol;
sp_sym->shadowed = NULL;
- bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym);
+ bh_table_put(SemSymbol *, state->symbols, tkn->text, sp_sym);
} else {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_CONFLICTING_GLOBALS,
return 1;
}
-static AstType* symres_type(OnyxSemPassState* state, AstType* type) {
+static AstType* symres_type(SemState* state, AstType* type) {
if (type == NULL) return NULL;
if (type->kind == Ast_Kind_Symbol) {
return NULL;
}
-static void symres_local(OnyxSemPassState* state, AstLocal** local) {
- (*local)->base.type_node = symres_type(state, (*local)->base.type_node);
- symbol_introduce(state, (*local)->base.token, (AstNode *) *local);
+static void symres_local(SemState* state, AstLocal** local) {
+ (*local)->type_node = symres_type(state, (*local)->type_node);
+ symbol_introduce(state, (*local)->token, (AstNode *) *local);
}
-static void symres_call(OnyxSemPassState* state, AstCall* call) {
+static void symres_call(SemState* state, AstCall* call) {
AstNode* callee = symbol_resolve(state, call->callee->token);
if (callee)
call->callee = callee;
symres_statement_chain(state, (AstNode *) call->arguments, (AstNode **) &call->arguments);
}
-static void symres_unaryop(OnyxSemPassState* state, AstUnaryOp** unaryop) {
+static void symres_unaryop(SemState* state, AstUnaryOp** unaryop) {
if ((*unaryop)->operation == Unary_Op_Cast) {
- (*unaryop)->base.type_node = symres_type(state, (*unaryop)->base.type_node);
+ (*unaryop)->type_node = symres_type(state, (*unaryop)->type_node);
}
symres_expression(state, &(*unaryop)->expr);
}
-static void symres_expression(OnyxSemPassState* state, AstTyped** expr) {
+static void symres_expression(SemState* state, AstTyped** expr) {
switch ((*expr)->kind) {
case Ast_Kind_Binary_Op:
symres_expression(state, &((AstBinaryOp *)(*expr))->left);
}
}
-static void symres_assignment(OnyxSemPassState* state, AstAssign* assign) {
+static void symres_assignment(SemState* state, AstAssign* assign) {
AstTyped* lval = (AstTyped *) symbol_resolve(state, assign->lval->token);
if (lval == NULL) return;
assign->lval = lval;
symres_expression(state, &assign->expr);
}
-static void symres_return(OnyxSemPassState* state, AstReturn* ret) {
+static void symres_return(SemState* state, AstReturn* ret) {
if (ret->expr)
symres_expression(state, &ret->expr);
}
-static void symres_if(OnyxSemPassState* state, AstIf* ifnode) {
+static void symres_if(SemState* state, AstIf* ifnode) {
symres_expression(state, &ifnode->cond);
if (ifnode->true_block.as_if != NULL) {
- if (ifnode->true_block.as_if->base.kind == Ast_Kind_Block)
+ if (ifnode->true_block.as_if->kind == Ast_Kind_Block)
symres_block(state, ifnode->true_block.as_block);
- else if (ifnode->true_block.as_if->base.kind == Ast_Kind_If)
+ else if (ifnode->true_block.as_if->kind == Ast_Kind_If)
symres_if(state, ifnode->true_block.as_if);
else DEBUG_HERE;
}
if (ifnode->false_block.as_if != NULL) {
- if (ifnode->false_block.as_if->base.kind == Ast_Kind_Block)
+ if (ifnode->false_block.as_if->kind == Ast_Kind_Block)
symres_block(state, ifnode->false_block.as_block);
- else if (ifnode->false_block.as_if->base.kind == Ast_Kind_If)
+ else if (ifnode->false_block.as_if->kind == Ast_Kind_If)
symres_if(state, ifnode->false_block.as_if);
else DEBUG_HERE;
}
}
-static void symres_while(OnyxSemPassState* state, AstWhile* whilenode) {
+static void symres_while(SemState* state, AstWhile* whilenode) {
symres_expression(state, &whilenode->cond);
symres_block(state, whilenode->body);
}
// NOTE: Returns 1 if the statment should be removed
-static b32 symres_statement(OnyxSemPassState* state, AstNode* stmt) {
+static b32 symres_statement(SemState* state, AstNode* stmt) {
switch (stmt->kind) {
case Ast_Kind_Local: symres_local(state, (AstLocal **) &stmt); return 1;
case Ast_Kind_Assignment: symres_assignment(state, (AstAssign *) stmt); return 0;
}
}
-static void symres_statement_chain(OnyxSemPassState* state, AstNode* walker, AstNode** trailer) {
+static void symres_statement_chain(SemState* state, AstNode* walker, AstNode** trailer) {
while (walker) {
if (symres_statement(state, walker)) {
*trailer = walker->next;
}
}
-static void symres_block(OnyxSemPassState* state, AstBlock* block) {
+static void symres_block(SemState* state, AstBlock* block) {
local_group_enter(state, block->locals);
if (block->body)
symres_statement_chain(state, block->body, &block->body);
local_group_leave(state);
}
-static void symres_function(OnyxSemPassState* state, AstFunction* func) {
- for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) {
- param->base.type_node = symres_type(state, param->base.type_node);
+static void symres_function(SemState* state, AstFunction* func) {
+ for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
+ param->type_node = symres_type(state, param->type_node);
- symbol_introduce(state, param->base.token, (AstNode *) param);
+ symbol_introduce(state, param->token, (AstNode *) param);
}
- if (func->base.type_node != NULL) {
- func->base.type_node = symres_type(state, func->base.type_node);
+ if (func->type_node != NULL) {
+ func->type_node = symres_type(state, func->type_node);
}
symres_block(state, func->body);
- for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) {
- symbol_remove(state, param->base.token);
+ for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
+ symbol_remove(state, param->token);
}
}
-static void symres_global(OnyxSemPassState* state, AstGlobal* global) {
- global->base.type_node = symres_type(state, global->base.type_node);
+static void symres_global(SemState* state, AstGlobal* global) {
+ global->type_node = symres_type(state, global->type_node);
}
-static void symres_top_node(OnyxSemPassState* state, AstNode** node) {
+static void symres_top_node(SemState* state, AstNode** node) {
switch ((*node)->kind) {
case Ast_Kind_Call:
case Ast_Kind_Unary_Op:
}
}
-void onyx_resolve_symbols(OnyxSemPassState* state, ParserOutput* program) {
+void onyx_resolve_symbols(SemState* state, ParserOutput* program) {
// NOTE: Add types to global scope
symbol_basic_type_introduce(state, &basic_type_void);
symbol_basic_type_introduce(state, &basic_type_rawptr);
bh_arr_each(AstBinding *, binding, program->top_level_bindings)
- if (!symbol_unique_introduce(state, (*binding)->base.token, (*binding)->node)) return;
+ if (!symbol_unique_introduce(state, (*binding)->token, (*binding)->node)) return;
bh_arr_each(AstNode *, node, program->nodes_to_process)
symres_top_node(state, node);
if (if_node->true_block.as_if) {
// NOTE: This is kind of gross, but making a function for this doesn't feel right
- if (if_node->true_block.as_if->base.kind == Ast_Kind_If) {
+ if (if_node->true_block.as_if->kind == Ast_Kind_If) {
forll (AstNode, stmt, (AstNode *) if_node->true_block.as_if, next) {
compile_statement(mod, &code, stmt);
}
- } else if (if_node->true_block.as_if->base.kind == Ast_Kind_Block) {
+ } else if (if_node->true_block.as_if->kind == Ast_Kind_Block) {
forll (AstNode, stmt, if_node->true_block.as_block->body, next) {
compile_statement(mod, &code, stmt);
}
if (if_node->false_block.as_if) {
WI(WI_ELSE);
- if (if_node->false_block.as_if->base.kind == Ast_Kind_If) {
+ if (if_node->false_block.as_if->kind == Ast_Kind_If) {
forll (AstNode, stmt, (AstNode *) if_node->false_block.as_if, next) {
compile_statement(mod, &code, stmt);
}
- } else if (if_node->false_block.as_if->base.kind == Ast_Kind_Block) {
+ } else if (if_node->false_block.as_if->kind == Ast_Kind_Block) {
forll (AstNode, stmt, if_node->false_block.as_block->body, next) {
compile_statement(mod, &code, stmt);
}
switch (unop->operation) {
case Unary_Op_Negate:
{
- TypeBasic* type = &unop->base.type->Basic;
+ TypeBasic* type = &unop->type->Basic;
if (type->kind == Basic_Kind_I32
|| type->kind == Basic_Kind_I16
for (AstArgument *arg = call->arguments;
arg != NULL;
- arg = (AstArgument *) arg->base.next) {
+ arg = (AstArgument *) arg->next) {
compile_expression(mod, &code, arg->value);
}
if (place_arguments_normally) {
for (AstArgument *arg = call->arguments;
arg != NULL;
- arg = (AstArgument *) arg->base.next) {
+ arg = (AstArgument *) arg->next) {
compile_expression(mod, &code, arg->value);
}
}
case Ast_Kind_Literal:
{
AstNumLit* lit = (AstNumLit *) expr;
- WasmType lit_type = onyx_type_to_wasm_type(lit->base.type);
+ WasmType lit_type = onyx_type_to_wasm_type(lit->type);
WasmInstruction instr = { WI_NOP, 0 };
if (lit_type == WASM_TYPE_INT32) {
compile_expression(mod, &code, cast->expr);
Type* from = cast->expr->type;
- Type* to = cast->base.type;
+ Type* to = cast->type;
i32 fromidx = 0, toidx = 0;
if (from->Basic.flags & Basic_Flag_Integer) {
static char type_repr_buf[128];
char* t = type_repr_buf;
- Type** param_type = fd->base.type->Function.params;
- i32 param_count = fd->base.type->Function.param_count;
+ Type** param_type = fd->type->Function.params;
+ i32 param_count = fd->type->Function.param_count;
i32 params_left = param_count;
while (params_left-- > 0) {
// HACK: Using these directly as part of a string feels weird but they are
}
*(t++) = ':';
- WasmType return_type = onyx_type_to_wasm_type(fd->base.type->Function.return_type);
+ WasmType return_type = onyx_type_to_wasm_type(fd->type->Function.return_type);
*(t++) = (char) return_type;
*t = '\0';
static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
// NOTE: Don't compile intrinsics
- if (fd->base.flags & Ast_Flag_Intrinsic) return;
+ if (fd->flags & Ast_Flag_Intrinsic) return;
i32 type_idx = generate_type_idx(mod, fd);
- if (fd->base.flags & Ast_Flag_Foreign) {
+ if (fd->flags & Ast_Flag_Foreign) {
WasmImport import = {
.kind = WASM_FOREIGN_FUNCTION,
.idx = type_idx,
bh_arr_new(mod->allocator, wasm_func.code, 4);
- if (fd->base.flags & Ast_Flag_Exported) {
+ if (fd->flags & Ast_Flag_Exported) {
token_toggle_end(fd->exported_name);
i32 func_idx = (i32) bh_imap_get(&mod->func_map, (u64) fd);
if (fd->body != NULL) {
// NOTE: Generate the local map
i32 localidx = 0;
- for (AstLocal *param = fd->params; param != NULL; param = (AstLocal *) param->base.next) {
+ for (AstLocal *param = fd->params; param != NULL; param = (AstLocal *) param->next) {
bh_imap_put(&mod->local_map, (u64) param, localidx++);
}
u8* count = &wasm_func.locals.i32_count;
fori (ti, 0, 3) {
forll (AstLocal, local, fd->body->locals->last_local, prev_local) {
- if (onyx_type_to_wasm_type(local->base.type) == local_types[ti]) {
+ if (onyx_type_to_wasm_type(local->type) == local_types[ti]) {
bh_imap_put(&mod->local_map, (u64) local, localidx++);
(*count)++;
}
static void compile_global_declaration(OnyxWasmModule* module, AstGlobal* global) {
- WasmType global_type = onyx_type_to_wasm_type(global->base.type);
+ WasmType global_type = onyx_type_to_wasm_type(global->type);
- if (global->base.flags & Ast_Flag_Foreign) {
+ if (global->flags & Ast_Flag_Foreign) {
WasmImport import = {
.kind = WASM_FOREIGN_GLOBAL,
.idx = global_type,
WasmGlobal glob = {
.type = global_type,
- .mutable = (global->base.flags & Ast_Flag_Const) == 0,
+ .mutable = (global->flags & Ast_Flag_Const) == 0,
.initial_value = NULL,
};
- if ((global->base.flags & Ast_Flag_Exported) != 0) {
+ if ((global->flags & Ast_Flag_Exported) != 0) {
token_toggle_end(global->exported_name);
i32 global_idx = (i32) bh_imap_get(&module->func_map, (u64) global);
void onyx_wasm_module_compile(OnyxWasmModule* module, ParserOutput* program) {
bh_arr_each(AstFunction *, function, program->functions) {
- if ((*function)->base.flags & Ast_Flag_Foreign) {
+ if ((*function)->flags & Ast_Flag_Foreign) {
bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++);
}
}
bh_arr_each(AstGlobal *, global, program->globals) {
- if ((*global)->base.flags & Ast_Flag_Foreign) {
+ if ((*global)->flags & Ast_Flag_Foreign) {
bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++);
}
}
bh_arr_each(AstFunction *, function, program->functions) {
- if ((*function)->base.flags & Ast_Flag_Foreign) continue;
+ if ((*function)->flags & Ast_Flag_Foreign) continue;
- if (((*function)->base.flags & Ast_Flag_Intrinsic) == 0)
+ if (((*function)->flags & Ast_Flag_Intrinsic) == 0)
bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++);
}
bh_arr_each(AstGlobal *, global, program->globals) {
- if ((*global)->base.flags & Ast_Flag_Foreign) continue;
+ if ((*global)->flags & Ast_Flag_Foreign) continue;
bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++);
}