"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/onyx",
- "args": ["progs/test.onyx"],
+ "args": ["progs/other.onyx", "progs/test.onyx"],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
INCLUDES=-I./include
LIBS=
FLAGS=-g
+TARGET=./onyx
build/%.o: src/%.c include/bh.h
$(CC) $(FLAGS) -c $< -o $@ $(INCLUDES)
-onyx: $(OBJ_FILES)
+$(TARGET): $(OBJ_FILES)
$(CC) $(FLAGS) $(OBJ_FILES) -o $@ $(LIBS)
+install: $(TARGET)
+ cp $(TARGET) /usr/bin/
+
clean:
rm -f $(OBJ_FILES) 2>&1 >/dev/null
[X] Comparison operators
[X] Proper boolean type
[X] Conditional branching works as expected
- [ ] Simple while loop is functioning as expected
+ XX] Simple while loop is functioning as expected
[ ] break and continue semantics
[X] Function calling works for the builtin types
[X] Function return values are type checked
TOKEN_TYPE_KEYWORD_IF,
TOKEN_TYPE_KEYWORD_ELSE,
TOKEN_TYPE_KEYWORD_ELSEIF,
- TOKEN_TYPE_KEYWORD_FOR,
- TOKEN_TYPE_KEYWORD_DO,
TOKEN_TYPE_KEYWORD_RETURN,
TOKEN_TYPE_KEYWORD_FOREIGN,
TOKEN_TYPE_KEYWORD_PROC,
- TOKEN_TYPE_KEYWORD_GLOBAL,
TOKEN_TYPE_KEYWORD_CAST,
TOKEN_TYPE_KEYWORD_WHILE,
+ TOKEN_TYPE_KEYWORD_BREAK,
+ TOKEN_TYPE_KEYWORD_CONTINUE,
TOKEN_TYPE_RIGHT_ARROW,
TOKEN_TYPE_LEFT_ARROW,
#include "onyxmsgs.h"
typedef union OnyxAstNode OnyxAstNode;
+typedef struct OnyxAstNodeUnaryOp OnyxAstNodeUnaryOp;
+typedef struct OnyxAstNodeBinOp OnyxAstNodeBinOp;
typedef struct OnyxAstNodeNumLit OnyxAstNodeNumLit;
typedef struct OnyxAstNodeLocal OnyxAstNodeLocal;
typedef struct OnyxAstNodeScope OnyxAstNodeScope;
ONYX_AST_NODE_KIND_LOCAL,
ONYX_AST_NODE_KIND_SYMBOL,
- ONYX_AST_NODE_KIND_ADD,
- ONYX_AST_NODE_KIND_MINUS,
- ONYX_AST_NODE_KIND_MULTIPLY,
- ONYX_AST_NODE_KIND_DIVIDE,
- ONYX_AST_NODE_KIND_MODULUS,
- ONYX_AST_NODE_KIND_NEGATE,
+ ONYX_AST_NODE_KIND_UNARY_OP,
+ ONYX_AST_NODE_KIND_BIN_OP,
ONYX_AST_NODE_KIND_TYPE,
ONYX_AST_NODE_KIND_LITERAL,
- ONYX_AST_NODE_KIND_CAST,
ONYX_AST_NODE_KIND_PARAM,
ONYX_AST_NODE_KIND_ARGUMENT,
ONYX_AST_NODE_KIND_CALL,
ONYX_AST_NODE_KIND_ASSIGNMENT,
ONYX_AST_NODE_KIND_RETURN,
- ONYX_AST_NODE_KIND_EQUAL,
- ONYX_AST_NODE_KIND_NOT_EQUAL,
- ONYX_AST_NODE_KIND_LESS,
- ONYX_AST_NODE_KIND_LESS_EQUAL,
- ONYX_AST_NODE_KIND_GREATER,
- ONYX_AST_NODE_KIND_GREATER_EQUAL,
- ONYX_AST_NODE_KIND_NOT,
-
ONYX_AST_NODE_KIND_IF,
ONYX_AST_NODE_KIND_WHILE,
+ ONYX_AST_NODE_KIND_BREAK,
+ ONYX_AST_NODE_KIND_CONTINUE,
ONYX_AST_NODE_KIND_COUNT
} OnyxAstNodeKind;
ONYX_AST_FLAG_COMPTIME = BH_BIT(3),
} OnyxAstFlags;
+typedef enum OnyxUnaryOp {
+ ONYX_UNARY_OP_NEGATE,
+ ONYX_UNARY_OP_NOT,
+ ONYX_UNARY_OP_CAST,
+} OnyxUnaryOp;
+
+typedef enum OnyxBinaryOp {
+ ONYX_BINARY_OP_ADD,
+ ONYX_BINARY_OP_MINUS,
+ ONYX_BINARY_OP_MULTIPLY,
+ ONYX_BINARY_OP_DIVIDE,
+ ONYX_BINARY_OP_MODULUS,
+
+ ONYX_BINARY_OP_EQUAL,
+ ONYX_BINARY_OP_NOT_EQUAL,
+ ONYX_BINARY_OP_LESS,
+ ONYX_BINARY_OP_LESS_EQUAL,
+ ONYX_BINARY_OP_GREATER,
+ ONYX_BINARY_OP_GREATER_EQUAL,
+} OnyxBinaryOp;
+
+struct OnyxAstNodeBinOp {
+ OnyxAstNodeKind kind;
+ u32 flags;
+ OnyxToken *token;
+ OnyxTypeInfo *type;
+ OnyxBinaryOp operation;
+ OnyxAstNode *next;
+ OnyxAstNode *left;
+ OnyxAstNode *right;
+};
+
+struct OnyxAstNodeUnaryOp {
+ OnyxAstNodeKind kind;
+ u32 flags;
+ OnyxToken *token;
+ OnyxTypeInfo *type;
+ OnyxUnaryOp operation;
+ OnyxAstNode *next;
+ OnyxAstNode *left;
+};
+
struct OnyxAstNodeNumLit {
OnyxAstNodeKind kind;
u32 flags;
u32 flags;
OnyxToken *token;
OnyxTypeInfo *type;
+ u64 data; // NOTE: Unused
OnyxAstNode *next;
OnyxAstNodeLocal *prev_local;
};
struct OnyxAstNodeParam {
OnyxAstNodeKind kind;
u32 flags;
- OnyxToken *token; // Symbol name i.e. 'a', 'b'
+ OnyxToken *token; // NOTE: Symbol name i.e. 'a', 'b'
OnyxTypeInfo *type;
+ u64 data; // NOTE: UNUSED
OnyxAstNodeParam *next;
OnyxAstNodeLocal *prev_local;
};
u32 flags;
OnyxToken *token; // NOTE: UNUSED
OnyxTypeInfo *type; // NOTE: UNUSED
+ u64 data; // NOTE: UNUSED
OnyxAstNodeScope *prev_scope;
OnyxAstNodeLocal *last_local;
};
u32 flags;
OnyxToken *token;
OnyxTypeInfo *return_type;
+ u64 data; // NOTE: UNUSED
OnyxAstNode *next;
OnyxAstNode *body;
OnyxAstNodeScope *scope;
OnyxAstNodeKind kind;
u32 flags;
OnyxToken *token; // NOTE: UNUSED
+ u64 data; // NOTE: UNUSED
OnyxAstNode *false_block;
OnyxAstNode *next;
OnyxAstNode *cond;
u32 flags;
OnyxToken *token; // NOTE: UNUSED
OnyxTypeInfo *type;
+ u64 data;
OnyxAstNode *next;
OnyxAstNode *cond;
OnyxAstNodeBlock *body;
u32 flags;
OnyxToken *token; // This will point to the symbol token to identify it
OnyxTypeInfo *return_type;
+ u64 data;
OnyxAstNode *next;
OnyxAstNodeBlock *body;
OnyxAstNodeParam *params;
u32 flags;
OnyxToken *mod_token;
OnyxTypeInfo *type;
+ u64 data;
OnyxAstNode *next;
OnyxToken *name_token;
OnyxAstNode *import;
struct OnyxAstNodeCall {
OnyxAstNodeKind kind;
u32 flags;
- OnyxToken *token; // NOTE: Not specified (undefined)
+ OnyxToken *token;
OnyxTypeInfo *type; // NOTE: The type that the function returns
+ u64 data;
OnyxAstNode *next;
OnyxAstNode *callee; // NOTE: Function definition node
OnyxAstNode *arguments; // NOTE: Expressions that form the actual param list
u32 flags;
OnyxToken *token; // NOTE: unused
OnyxTypeInfo *type; // NOTE: unused
+ u64 data;
OnyxAstNodeFile *next; // NOTE: next file
OnyxAstNode *contents; // NOTE: the first top-level element
};
u32 flags;
OnyxToken *token;
OnyxTypeInfo *type;
+ u64 data;
OnyxAstNode *next;
OnyxAstNode *left;
OnyxAstNode *right;
OnyxAstNodeScope as_scope;
OnyxAstNodeCall as_call;
OnyxAstNodeNumLit as_numlit;
+ OnyxAstNodeBinOp as_binop;
+ OnyxAstNodeUnaryOp as_unaryop;
OnyxAstNodeForeign as_foreign;
OnyxAstNodeIf as_if;
OnyxAstNodeWhile as_while;
};
const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind);
-OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind);
+void* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind);
OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs);
void onyx_parser_free(OnyxParser* parser);
OnyxAstNodeFile* onyx_parse(OnyxParser *parser);
export main :: proc {
i := 0;
while i < 10 {
- print_i32(fib(i));
+ res :: fib(i);
+ print_i32(res);
i = i + 1;
}
i = 0;
while i < 10 {
- print_i32(factorial(i));
+ res :: factorial(i);
+ print_i32(res);
i = i + 1;
}
compiler_state_free(&compile_state);
- return compiler_progress == ONYX_COMPILER_PROGRESS_SUCCESS;
+ return compiler_progress != ONYX_COMPILER_PROGRESS_SUCCESS;
}
// NOTE: Old bits of code that may be useful again at some point.
"if", //"TOKEN_TYPE_KEYWORD_IF",
"else", //"TOKEN_TYPE_KEYWORD_ELSE",
"elseif", //"TOKEN_TYPE_KEYWORD_ELSEIF",
- "for", //"TOKEN_TYPE_KEYWORD_FOR",
- "do", //"TOKEN_TYPE_KEYWORD_DO",
"return", //"TOKEN_TYPE_KEYWORD_RETURN",
"foreign", //"TOKEN_TYPE_KEYWORD_FOREIGN",
"proc", //"TOKEN_TYPE_KEYWORD_PROC",
- "global", //"TOKEN_TYPE_KEYWORD_GLOBAL",
"as", //"TOKEN_TYPE_KEYWORD_CAST",
"while", //"TOKEN_TYPE_KEYWORD_WHILE",
+ "break", //"TOKEN_TYPE_KEYWORD_BREAK",
+ "continue", //"TOKEN_TYPE_KEYWORD_CONTINUE,
"->", //"TOKEN_TYPE_RIGHT_ARROW",
"<-", //"TOKEN_TYPE_LEFT_ARROW",
goto token_parsed;
}
- LITERAL_TOKEN("struct", 1, TOKEN_TYPE_KEYWORD_STRUCT);
- LITERAL_TOKEN("export", 1, TOKEN_TYPE_KEYWORD_EXPORT);
- LITERAL_TOKEN("use", 1, TOKEN_TYPE_KEYWORD_USE);
- LITERAL_TOKEN("if", 1, TOKEN_TYPE_KEYWORD_IF);
- LITERAL_TOKEN("elseif", 1, TOKEN_TYPE_KEYWORD_ELSEIF);
- LITERAL_TOKEN("else", 1, TOKEN_TYPE_KEYWORD_ELSE);
- LITERAL_TOKEN("foreign", 1, TOKEN_TYPE_KEYWORD_FOREIGN);
- LITERAL_TOKEN("for", 1, TOKEN_TYPE_KEYWORD_FOR);
- LITERAL_TOKEN("return", 1, TOKEN_TYPE_KEYWORD_RETURN);
- LITERAL_TOKEN("do", 1, TOKEN_TYPE_KEYWORD_DO);
- LITERAL_TOKEN("proc", 1, TOKEN_TYPE_KEYWORD_PROC);
- LITERAL_TOKEN("global", 1, TOKEN_TYPE_KEYWORD_GLOBAL);
- LITERAL_TOKEN("as", 1, TOKEN_TYPE_KEYWORD_CAST);
- LITERAL_TOKEN("while", 1, TOKEN_TYPE_KEYWORD_WHILE);
- LITERAL_TOKEN("true", 1, TOKEN_TYPE_LITERAL_BOOL_TRUE);
- LITERAL_TOKEN("false", 1, TOKEN_TYPE_LITERAL_BOOL_FALSE);
- LITERAL_TOKEN("->", 0, TOKEN_TYPE_RIGHT_ARROW);
- LITERAL_TOKEN("<-", 0, TOKEN_TYPE_RIGHT_ARROW);
- LITERAL_TOKEN("<=", 0, TOKEN_TYPE_SYM_LESS_EQUAL);
- LITERAL_TOKEN(">=", 0, TOKEN_TYPE_SYM_GREATER_EQUAL);
- LITERAL_TOKEN("==", 0, TOKEN_TYPE_SYM_EQUAL_EQUAL);
- LITERAL_TOKEN("!=", 0, TOKEN_TYPE_SYM_NOT_EQUAL);
- LITERAL_TOKEN("(", 0, TOKEN_TYPE_OPEN_PAREN);
- LITERAL_TOKEN(")", 0, TOKEN_TYPE_CLOSE_PAREN);
- LITERAL_TOKEN("{", 0, TOKEN_TYPE_OPEN_BRACE);
- LITERAL_TOKEN("}", 0, TOKEN_TYPE_CLOSE_BRACE);
- LITERAL_TOKEN("[", 0, TOKEN_TYPE_OPEN_BRACKET);
- LITERAL_TOKEN("]", 0, TOKEN_TYPE_CLOSE_BRACKET);
- LITERAL_TOKEN("+", 0, TOKEN_TYPE_SYM_PLUS);
- LITERAL_TOKEN("-", 0, TOKEN_TYPE_SYM_MINUS);
- LITERAL_TOKEN("*", 0, TOKEN_TYPE_SYM_STAR);
- LITERAL_TOKEN(".", 0, TOKEN_TYPE_SYM_DOT);
- LITERAL_TOKEN("%", 0, TOKEN_TYPE_SYM_PERCENT);
- LITERAL_TOKEN("/", 0, TOKEN_TYPE_SYM_FSLASH);
- LITERAL_TOKEN("\\", 0, TOKEN_TYPE_SYM_BSLASH);
- LITERAL_TOKEN(":", 0, TOKEN_TYPE_SYM_COLON);
- LITERAL_TOKEN(";", 0, TOKEN_TYPE_SYM_SEMICOLON);
- LITERAL_TOKEN(",", 0, TOKEN_TYPE_SYM_COMMA);
- LITERAL_TOKEN(">", 0, TOKEN_TYPE_SYM_GREATER);
- LITERAL_TOKEN("<", 0, TOKEN_TYPE_SYM_LESS);
- LITERAL_TOKEN("=", 0, TOKEN_TYPE_SYM_EQUALS);
- LITERAL_TOKEN("~", 0, TOKEN_TYPE_SYM_TILDE);
- LITERAL_TOKEN("!", 0, TOKEN_TYPE_SYM_BANG);
- LITERAL_TOKEN("^", 0, TOKEN_TYPE_SYM_CARET);
- LITERAL_TOKEN("&", 0, TOKEN_TYPE_SYM_AMPERSAND);
+ LITERAL_TOKEN("struct", 1, TOKEN_TYPE_KEYWORD_STRUCT);
+ LITERAL_TOKEN("export", 1, TOKEN_TYPE_KEYWORD_EXPORT);
+ LITERAL_TOKEN("use", 1, TOKEN_TYPE_KEYWORD_USE);
+ LITERAL_TOKEN("if", 1, TOKEN_TYPE_KEYWORD_IF);
+ LITERAL_TOKEN("elseif", 1, TOKEN_TYPE_KEYWORD_ELSEIF);
+ LITERAL_TOKEN("else", 1, TOKEN_TYPE_KEYWORD_ELSE);
+ LITERAL_TOKEN("foreign", 1, TOKEN_TYPE_KEYWORD_FOREIGN);
+ LITERAL_TOKEN("return", 1, TOKEN_TYPE_KEYWORD_RETURN);
+ LITERAL_TOKEN("proc", 1, TOKEN_TYPE_KEYWORD_PROC);
+ LITERAL_TOKEN("as", 1, TOKEN_TYPE_KEYWORD_CAST);
+ LITERAL_TOKEN("while", 1, TOKEN_TYPE_KEYWORD_WHILE);
+ LITERAL_TOKEN("break", 1, TOKEN_TYPE_KEYWORD_BREAK);
+ LITERAL_TOKEN("continue", 1, TOKEN_TYPE_KEYWORD_CONTINUE);
+ LITERAL_TOKEN("true", 1, TOKEN_TYPE_LITERAL_BOOL_TRUE);
+ LITERAL_TOKEN("false", 1, TOKEN_TYPE_LITERAL_BOOL_FALSE);
+ LITERAL_TOKEN("->", 0, TOKEN_TYPE_RIGHT_ARROW);
+ LITERAL_TOKEN("<-", 0, TOKEN_TYPE_RIGHT_ARROW);
+ LITERAL_TOKEN("<=", 0, TOKEN_TYPE_SYM_LESS_EQUAL);
+ LITERAL_TOKEN(">=", 0, TOKEN_TYPE_SYM_GREATER_EQUAL);
+ LITERAL_TOKEN("==", 0, TOKEN_TYPE_SYM_EQUAL_EQUAL);
+ LITERAL_TOKEN("!=", 0, TOKEN_TYPE_SYM_NOT_EQUAL);
+ LITERAL_TOKEN("(", 0, TOKEN_TYPE_OPEN_PAREN);
+ LITERAL_TOKEN(")", 0, TOKEN_TYPE_CLOSE_PAREN);
+ LITERAL_TOKEN("{", 0, TOKEN_TYPE_OPEN_BRACE);
+ LITERAL_TOKEN("}", 0, TOKEN_TYPE_CLOSE_BRACE);
+ LITERAL_TOKEN("[", 0, TOKEN_TYPE_OPEN_BRACKET);
+ LITERAL_TOKEN("]", 0, TOKEN_TYPE_CLOSE_BRACKET);
+ LITERAL_TOKEN("+", 0, TOKEN_TYPE_SYM_PLUS);
+ LITERAL_TOKEN("-", 0, TOKEN_TYPE_SYM_MINUS);
+ LITERAL_TOKEN("*", 0, TOKEN_TYPE_SYM_STAR);
+ LITERAL_TOKEN(".", 0, TOKEN_TYPE_SYM_DOT);
+ LITERAL_TOKEN("%", 0, TOKEN_TYPE_SYM_PERCENT);
+ LITERAL_TOKEN("/", 0, TOKEN_TYPE_SYM_FSLASH);
+ LITERAL_TOKEN("\\", 0, TOKEN_TYPE_SYM_BSLASH);
+ LITERAL_TOKEN(":", 0, TOKEN_TYPE_SYM_COLON);
+ LITERAL_TOKEN(";", 0, TOKEN_TYPE_SYM_SEMICOLON);
+ LITERAL_TOKEN(",", 0, TOKEN_TYPE_SYM_COMMA);
+ LITERAL_TOKEN(">", 0, TOKEN_TYPE_SYM_GREATER);
+ LITERAL_TOKEN("<", 0, TOKEN_TYPE_SYM_LESS);
+ LITERAL_TOKEN("=", 0, TOKEN_TYPE_SYM_EQUALS);
+ LITERAL_TOKEN("~", 0, TOKEN_TYPE_SYM_TILDE);
+ LITERAL_TOKEN("!", 0, TOKEN_TYPE_SYM_BANG);
+ LITERAL_TOKEN("^", 0, TOKEN_TYPE_SYM_CARET);
+ LITERAL_TOKEN("&", 0, TOKEN_TYPE_SYM_AMPERSAND);
// Symbols
if (char_is_alpha(*tk.token)) {
"LOCAL",
"SYMBOL",
- "ADD",
- "MINUS",
- "MULTIPLY",
- "DIVIDE",
- "MODULUS",
- "NEGATE",
+ "UN_OP",
+ "BIN_OP",
"TYPE",
"LITERAL",
"ASSIGN",
"RETURN",
- "EQUAL",
- "NOT_EQUAL",
- "GREATER",
- "GREATER_EQUAL",
- "LESS",
- "LESS_EQUAL",
- "NOT",
-
"IF",
"WHILE",
{ 0xffffffff } // Sentinel
};
-static OnyxAstNode error_node = { { ONYX_AST_NODE_KIND_ERROR, 0, NULL, &builtin_types[0], NULL, NULL, NULL } };
+static OnyxAstNode error_node = { { ONYX_AST_NODE_KIND_ERROR, 0, NULL, &builtin_types[0], 0, NULL, NULL, NULL } };
// NOTE: Forward declarations
static void parser_next_token(OnyxParser* parser);
}
static OnyxAstNode* parse_factor(OnyxParser* parser) {
+ OnyxAstNode* retval = NULL;
+
switch (parser->curr_token->type) {
case TOKEN_TYPE_OPEN_PAREN:
{
parser_next_token(parser);
OnyxAstNode* expr = parse_expression(parser);
expect(parser, TOKEN_TYPE_CLOSE_PAREN);
- return expr;
+ retval = expr;
+ break;
}
case TOKEN_TYPE_SYM_MINUS:
parser_next_token(parser);
OnyxAstNode* factor = parse_factor(parser);
- OnyxAstNode* negate_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_NEGATE);
+ OnyxAstNodeUnaryOp* negate_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_UNARY_OP);
+ negate_node->operation = ONYX_UNARY_OP_NEGATE;
negate_node->left = factor;
negate_node->type = factor->type;
negate_node->flags |= ONYX_AST_FLAG_COMPTIME;
}
- return negate_node;
+ retval = (OnyxAstNode *) negate_node;
+ break;
}
case TOKEN_TYPE_SYMBOL:
sym_node->token = sym_token;
if (parser->curr_token->type != TOKEN_TYPE_OPEN_PAREN) {
- return sym_node;
+ retval = sym_node;
+ break;
}
// NOTE: Function call
}
parser_next_token(parser);
- return (OnyxAstNode *) call_node;
+ retval = (OnyxAstNode *) call_node;
+ break;
}
- case TOKEN_TYPE_LITERAL_NUMERIC: return (OnyxAstNode *) parse_numeric_literal(parser);
+ case TOKEN_TYPE_LITERAL_NUMERIC:
+ retval = (OnyxAstNode *) parse_numeric_literal(parser);
+ break;
case TOKEN_TYPE_LITERAL_BOOL_TRUE:
{
bool_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_BOOL];
bool_node->token = expect(parser, TOKEN_TYPE_LITERAL_BOOL_TRUE);
bool_node->value.i = 1;
- return (OnyxAstNode *) bool_node;
+ retval = (OnyxAstNode *) bool_node;
+ break;
}
case TOKEN_TYPE_LITERAL_BOOL_FALSE:
bool_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_BOOL];
bool_node->token = expect(parser, TOKEN_TYPE_LITERAL_BOOL_FALSE);
bool_node->value.i = 0;
- return (OnyxAstNode *) bool_node;
+ retval = (OnyxAstNode *) bool_node;
+ break;
}
default:
ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
parser->curr_token->pos,
onyx_get_token_type_name(parser->curr_token->type));
+ return NULL;
}
- return NULL;
+ if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_CAST) {
+ OnyxAstNodeUnaryOp* cast_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_UNARY_OP);
+ cast_node->operation = ONYX_UNARY_OP_CAST;
+ cast_node->type = parse_type(parser);
+ cast_node->left = retval;
+ retval = (OnyxAstNode *) cast_node;
+ }
+
+ return retval;
}
-static inline i32 get_precedence(OnyxAstNodeKind kind) {
+static inline i32 get_precedence(OnyxBinaryOp kind) {
switch (kind) {
- case ONYX_AST_NODE_KIND_EQUAL: return 3;
- case ONYX_AST_NODE_KIND_NOT_EQUAL: return 3;
+ case ONYX_BINARY_OP_EQUAL: return 3;
+ case ONYX_BINARY_OP_NOT_EQUAL: return 3;
- case ONYX_AST_NODE_KIND_LESS_EQUAL: return 4;
- case ONYX_AST_NODE_KIND_LESS: return 4;
- case ONYX_AST_NODE_KIND_GREATER_EQUAL: return 4;
- case ONYX_AST_NODE_KIND_GREATER: return 4;
+ case ONYX_BINARY_OP_LESS_EQUAL: return 4;
+ case ONYX_BINARY_OP_LESS: return 4;
+ case ONYX_BINARY_OP_GREATER_EQUAL: return 4;
+ case ONYX_BINARY_OP_GREATER: return 4;
- case ONYX_AST_NODE_KIND_ADD: return 5;
- case ONYX_AST_NODE_KIND_MINUS: return 5;
+ case ONYX_BINARY_OP_ADD: return 5;
+ case ONYX_BINARY_OP_MINUS: return 5;
- case ONYX_AST_NODE_KIND_MULTIPLY: return 6;
- case ONYX_AST_NODE_KIND_DIVIDE: return 6;
+ case ONYX_BINARY_OP_MULTIPLY: return 6;
+ case ONYX_BINARY_OP_DIVIDE: return 6;
- case ONYX_AST_NODE_KIND_MODULUS: return 7;
-
- case ONYX_AST_NODE_KIND_CAST: return 8;
+ case ONYX_BINARY_OP_MODULUS: return 7;
default: return -1;
}
}
static OnyxAstNode* parse_expression(OnyxParser* parser) {
- bh_arr(OnyxAstNode*) tree_stack = NULL;
+ bh_arr(OnyxAstNodeBinOp*) tree_stack = NULL;
bh_arr_new(global_scratch_allocator, tree_stack, 4);
bh_arr_set_length(tree_stack, 0);
OnyxAstNode* right;
OnyxAstNode* root = left;
- i32 bin_op_kind;
+ OnyxBinaryOp bin_op_kind;
OnyxToken* bin_op_tok;
while (1) {
bin_op_kind = -1;
switch (parser->curr_token->type) {
- case TOKEN_TYPE_SYM_EQUAL_EQUAL: bin_op_kind = ONYX_AST_NODE_KIND_EQUAL; break;
- case TOKEN_TYPE_SYM_NOT_EQUAL: bin_op_kind = ONYX_AST_NODE_KIND_NOT_EQUAL; break;
- case TOKEN_TYPE_SYM_LESS_EQUAL: bin_op_kind = ONYX_AST_NODE_KIND_LESS_EQUAL; break;
- case TOKEN_TYPE_SYM_LESS: bin_op_kind = ONYX_AST_NODE_KIND_LESS; break;
- case TOKEN_TYPE_SYM_GREATER_EQUAL: bin_op_kind = ONYX_AST_NODE_KIND_GREATER_EQUAL; break;
- case TOKEN_TYPE_SYM_GREATER: bin_op_kind = ONYX_AST_NODE_KIND_GREATER; break;
-
- case TOKEN_TYPE_SYM_PLUS: bin_op_kind = ONYX_AST_NODE_KIND_ADD; break;
- case TOKEN_TYPE_SYM_MINUS: bin_op_kind = ONYX_AST_NODE_KIND_MINUS; break;
- case TOKEN_TYPE_SYM_STAR: bin_op_kind = ONYX_AST_NODE_KIND_MULTIPLY; break;
- case TOKEN_TYPE_SYM_FSLASH: bin_op_kind = ONYX_AST_NODE_KIND_DIVIDE; break;
- case TOKEN_TYPE_SYM_PERCENT: bin_op_kind = ONYX_AST_NODE_KIND_MODULUS; break;
- case TOKEN_TYPE_KEYWORD_CAST: bin_op_kind = ONYX_AST_NODE_KIND_CAST; break;
+ case TOKEN_TYPE_SYM_EQUAL_EQUAL: bin_op_kind = ONYX_BINARY_OP_EQUAL; break;
+ case TOKEN_TYPE_SYM_NOT_EQUAL: bin_op_kind = ONYX_BINARY_OP_NOT_EQUAL; break;
+ case TOKEN_TYPE_SYM_LESS_EQUAL: bin_op_kind = ONYX_BINARY_OP_LESS_EQUAL; break;
+ case TOKEN_TYPE_SYM_LESS: bin_op_kind = ONYX_BINARY_OP_LESS; break;
+ case TOKEN_TYPE_SYM_GREATER_EQUAL: bin_op_kind = ONYX_BINARY_OP_GREATER_EQUAL; break;
+ case TOKEN_TYPE_SYM_GREATER: bin_op_kind = ONYX_BINARY_OP_GREATER; break;
+
+ case TOKEN_TYPE_SYM_PLUS: bin_op_kind = ONYX_BINARY_OP_ADD; break;
+ case TOKEN_TYPE_SYM_MINUS: bin_op_kind = ONYX_BINARY_OP_MINUS; break;
+ case TOKEN_TYPE_SYM_STAR: bin_op_kind = ONYX_BINARY_OP_MULTIPLY; break;
+ case TOKEN_TYPE_SYM_FSLASH: bin_op_kind = ONYX_BINARY_OP_DIVIDE; break;
+ case TOKEN_TYPE_SYM_PERCENT: bin_op_kind = ONYX_BINARY_OP_MODULUS; break;
default: goto expression_done;
}
bin_op_tok = parser->curr_token;
parser_next_token(parser);
- OnyxAstNode* bin_op = onyx_ast_node_new(parser->allocator, bin_op_kind);
+ OnyxAstNodeBinOp* bin_op = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_BIN_OP);
+ bin_op->operation = bin_op_kind;
bin_op->token = bin_op_tok;
while ( !bh_arr_is_empty(tree_stack) &&
- get_precedence(bh_arr_last(tree_stack)->kind) >= get_precedence(bin_op_kind))
+ get_precedence(bh_arr_last(tree_stack)->operation) >= get_precedence(bin_op_kind))
bh_arr_pop(tree_stack);
if (bh_arr_is_empty(tree_stack)) {
// NOTE: new is now the root node
bin_op->left = root;
- root = bin_op;
+ root = (OnyxAstNode *) bin_op;
} else {
bin_op->left = bh_arr_last(tree_stack)->right;
- bh_arr_last(tree_stack)->right = bin_op;
+ bh_arr_last(tree_stack)->right = (OnyxAstNode *) bin_op;
}
bh_arr_push(tree_stack, bin_op);
- if (bin_op_kind == ONYX_AST_NODE_KIND_CAST) {
- bin_op->type = parse_type(parser);
- } else {
- right = parse_factor(parser);
- bin_op->right = right;
- bin_op->type = right->type;
+ right = parse_factor(parser);
+ bin_op->right = right;
+ bin_op->type = right->type;
- if ((left->flags & ONYX_AST_FLAG_COMPTIME) != 0 && (right->flags & ONYX_AST_FLAG_COMPTIME) != 0) {
- bin_op->flags |= ONYX_AST_FLAG_COMPTIME;
- }
+ if ((left->flags & ONYX_AST_FLAG_COMPTIME) != 0 && (right->flags & ONYX_AST_FLAG_COMPTIME) != 0) {
+ bin_op->flags |= ONYX_AST_FLAG_COMPTIME;
}
}
}
retval = (OnyxAstNode *) parse_while_stmt(parser);
break;
+ case TOKEN_TYPE_KEYWORD_BREAK:
+ retval = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_BREAK);
+ retval->token = expect(parser, TOKEN_TYPE_KEYWORD_BREAK);
+ break;
+
+ case TOKEN_TYPE_KEYWORD_CONTINUE:
+ retval = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_CONTINUE);
+ retval->token = expect(parser, TOKEN_TYPE_KEYWORD_CONTINUE);
+ break;
+
default:
break;
}
return ast_node_names[kind];
}
-OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\
- OnyxAstNode* node = (OnyxAstNode *) bh_alloc(alloc, sizeof(OnyxAstNode));
+// NOTE: This returns a void* so I don't need to cast it everytime I use it
+void* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\
+ OnyxAstNode* node = bh_alloc_item(alloc, OnyxAstNode);
node->kind = kind;
node->flags = 0;
node->token = NULL;
node->type = NULL;
+ node->data = 0;
node->next = NULL;
node->left = NULL;
node->right = NULL;
static void symres_expression(OnyxSemPassState* state, OnyxAstNode** expr) {
switch ((*expr)->kind) {
- case ONYX_AST_NODE_KIND_ADD:
- case ONYX_AST_NODE_KIND_MINUS:
- case ONYX_AST_NODE_KIND_MULTIPLY:
- case ONYX_AST_NODE_KIND_DIVIDE:
- case ONYX_AST_NODE_KIND_MODULUS:
- case ONYX_AST_NODE_KIND_EQUAL:
- case ONYX_AST_NODE_KIND_NOT_EQUAL:
- case ONYX_AST_NODE_KIND_LESS:
- case ONYX_AST_NODE_KIND_LESS_EQUAL:
- case ONYX_AST_NODE_KIND_GREATER:
- case ONYX_AST_NODE_KIND_GREATER_EQUAL:
+ case ONYX_AST_NODE_KIND_BIN_OP:
symres_expression(state, &(*expr)->left);
symres_expression(state, &(*expr)->right);
break;
- case ONYX_AST_NODE_KIND_NEGATE:
- symres_expression(state, &(*expr)->left);
- break;
-
- case ONYX_AST_NODE_KIND_CAST:
- if ((*expr)->type == NULL) {
- DEBUG_HERE;
- return;
- }
+ case ONYX_AST_NODE_KIND_UNARY_OP:
symres_expression(state, &(*expr)->left);
break;
static void typecheck_expression(OnyxSemPassState* state, OnyxAstNode* expr) {
switch (expr->kind) {
- case ONYX_AST_NODE_KIND_ADD:
- case ONYX_AST_NODE_KIND_MINUS:
- case ONYX_AST_NODE_KIND_MULTIPLY:
- case ONYX_AST_NODE_KIND_DIVIDE:
- case ONYX_AST_NODE_KIND_MODULUS:
- case ONYX_AST_NODE_KIND_EQUAL:
- case ONYX_AST_NODE_KIND_NOT_EQUAL:
- case ONYX_AST_NODE_KIND_LESS:
- case ONYX_AST_NODE_KIND_LESS_EQUAL:
- case ONYX_AST_NODE_KIND_GREATER:
- case ONYX_AST_NODE_KIND_GREATER_EQUAL:
+ case ONYX_AST_NODE_KIND_BIN_OP:
expr->type = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN];
typecheck_expression(state, expr->left);
return;
}
- if (expr->kind >= ONYX_AST_NODE_KIND_EQUAL
- && expr->kind <= ONYX_AST_NODE_KIND_GREATER_EQUAL) {
+ if (expr->as_binop.operation >= ONYX_BINARY_OP_EQUAL
+ && expr->as_binop.operation <= ONYX_BINARY_OP_GREATER_EQUAL) {
expr->type = &builtin_types[ONYX_TYPE_INFO_KIND_BOOL];
} else {
expr->type = expr->left->type;
break;
- case ONYX_AST_NODE_KIND_NEGATE:
- typecheck_expression(state, expr->left);
- expr->type = expr->left->type;
- break;
-
- case ONYX_AST_NODE_KIND_CAST:
- // NOTE: Do nothing. The resulting type from the cast
- // is already in the cast expression.
+ case ONYX_AST_NODE_KIND_UNARY_OP:
+ if (expr->as_unaryop.operation != ONYX_UNARY_OP_CAST) {
+ typecheck_expression(state, expr->left);
+ expr->type = expr->left->type;
+ }
break;
case ONYX_AST_NODE_KIND_CALL:
static void compile_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign);
static void compile_if(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeIf* if_node);
static void compile_while(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeWhile* while_node);
+static void compile_binop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBinOp* binop);
+static void compile_unaryop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* unop);
static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr);
-static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* cast);
+static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* cast);
static void compile_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret);
static void compile_function_body(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeFuncDef* fd) {
compile_assign_lval(mod, func, assign->left);
}
-#define BIN_OP_PROCESS(ast_binop, wasm_binop) \
- case ONYX_AST_NODE_KIND_##ast_binop: \
- { \
- WasmInstructionType instr_type; \
- switch (expr->left->type->kind) { \
- case ONYX_TYPE_INFO_KIND_BOOL: \
- case ONYX_TYPE_INFO_KIND_UINT32: \
- case ONYX_TYPE_INFO_KIND_INT32: instr_type = WI_I32_##wasm_binop; break; \
- case ONYX_TYPE_INFO_KIND_UINT64: \
- case ONYX_TYPE_INFO_KIND_INT64: instr_type = WI_I64_##wasm_binop; break; \
- case ONYX_TYPE_INFO_KIND_FLOAT32: instr_type = WI_F32_##wasm_binop; break; \
- case ONYX_TYPE_INFO_KIND_FLOAT64: instr_type = WI_F64_##wasm_binop; break; \
- default: assert(("Invalid type", 0)); \
- } \
- \
- compile_expression(mod, func, expr->left); \
- compile_expression(mod, func, expr->right); \
- bh_arr_push(func->code, ((WasmInstruction){ instr_type, 0x00 })); \
- break; \
- }
+// NOTE: These need to be in the same order as
+// the OnyxBinaryOp enum
+static const WasmInstructionType binop_map[][4] = {
+ // I32 I64 F32 F64
+ /* ADD */ { WI_I32_ADD, WI_I64_ADD, WI_F32_ADD, WI_F64_ADD },
+ /* SUB */ { WI_I32_SUB, WI_I64_SUB, WI_F32_SUB, WI_F64_SUB },
+ /* MUL */ { WI_I32_MUL, WI_I64_MUL, WI_F32_MUL, WI_F64_MUL },
+ /* DIV */ { WI_I32_DIV_S, WI_I64_DIV_S, WI_F32_DIV, WI_F64_DIV },
+ /* REM */ { WI_I32_REM_S, WI_I64_REM_S, WI_NOP, WI_NOP },
+
+ /* EQ */ { WI_I32_EQ, WI_I64_EQ, WI_F32_EQ, WI_F64_EQ },
+ /* NEQ */ { WI_NOP, WI_NOP, WI_F32_NE , WI_F64_NE },
+ /* LT */ { WI_I32_LT_S, WI_I64_LT_S, WI_F32_LT, WI_F64_LT },
+ /* LTE */ { WI_I32_LE_S, WI_I64_LE_S, WI_F32_LE, WI_F64_LE },
+ /* GT */ { WI_I32_GT_S, WI_I64_GT_S, WI_F32_GT, WI_F64_GT },
+ /* GTE */ { WI_I32_GE_S, WI_I64_GE_S, WI_F32_GE, WI_F64_GE },
+};
-#define BIN_OP_SIGNED_PROCESS(ast_binop, wasm_binop) \
- case ONYX_AST_NODE_KIND_##ast_binop: \
- { \
- WasmInstructionType instr_type; \
- switch (expr->left->type->kind) { \
- case ONYX_TYPE_INFO_KIND_BOOL: \
- case ONYX_TYPE_INFO_KIND_UINT32: \
- case ONYX_TYPE_INFO_KIND_INT32: \
- if (expr->left->type->is_unsigned) instr_type = WI_I32_##wasm_binop##_U; \
- else instr_type = WI_I32_##wasm_binop##_S; \
- break; \
- case ONYX_TYPE_INFO_KIND_UINT64: \
- case ONYX_TYPE_INFO_KIND_INT64: \
- if (expr->left->type->is_unsigned) instr_type = WI_I64_##wasm_binop##_U; \
- else instr_type = WI_I64_##wasm_binop##_S; \
- break; \
- case ONYX_TYPE_INFO_KIND_FLOAT32: instr_type = WI_F32_##wasm_binop; break; \
- case ONYX_TYPE_INFO_KIND_FLOAT64: instr_type = WI_F64_##wasm_binop; break; \
- default: assert(("Invalid type", 0)); \
- } \
- \
- compile_expression(mod, func, expr->left); \
- compile_expression(mod, func, expr->right); \
- bh_arr_push(func->code, ((WasmInstruction){ instr_type, 0x00 })); \
- break; \
- }
+static void compile_binop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBinOp* binop) {
+ b32 is_sign_significant = 0;
-static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr) {
- switch (expr->kind) {
- BIN_OP_PROCESS(ADD, ADD);
- BIN_OP_PROCESS(MINUS, SUB);
- BIN_OP_PROCESS(MULTIPLY, MUL);
- BIN_OP_SIGNED_PROCESS(DIVIDE, DIV);
-
- BIN_OP_SIGNED_PROCESS(LESS, LT);
- BIN_OP_SIGNED_PROCESS(LESS_EQUAL, LE);
- BIN_OP_SIGNED_PROCESS(GREATER, GT);
- BIN_OP_SIGNED_PROCESS(GREATER_EQUAL, GE);
- BIN_OP_PROCESS(EQUAL, EQ);
- BIN_OP_PROCESS(NOT_EQUAL, NE);
-
- case ONYX_AST_NODE_KIND_MODULUS:
- {
- WasmInstructionType instr_type;
- switch (expr->type->kind) {
- case ONYX_TYPE_INFO_KIND_INT32:
- if (expr->type->is_unsigned) instr_type = WI_I32_REM_U;
- else instr_type = WI_I32_REM_S;
- break;
- case ONYX_TYPE_INFO_KIND_INT64:
- if (expr->type->is_unsigned) instr_type = WI_I64_REM_U;
- else instr_type = WI_I64_REM_S;
- break;
- default: assert(("Invalid type", 0));
- }
+ switch (binop->operation) {
+ case ONYX_BINARY_OP_DIVIDE:
+ case ONYX_BINARY_OP_MODULUS:
+ case ONYX_BINARY_OP_LESS:
+ case ONYX_BINARY_OP_LESS_EQUAL:
+ case ONYX_BINARY_OP_GREATER:
+ case ONYX_BINARY_OP_GREATER_EQUAL:
+ is_sign_significant = 1;
- compile_expression(mod, func, expr->left);
- compile_expression(mod, func, expr->right);
- bh_arr_push(func->code, ((WasmInstruction){ instr_type, 0x00 }));
- break;
- }
+ default: break;
+ }
+
+ WasmType operator_type = onyx_type_to_wasm_type(binop->left->type);
+ WasmInstructionType binop_instr = binop_map[binop->operation][operator_type];
+
+ if (binop_instr == WI_NOP) {
+ assert(("Invalid type and operation", 0));
+ }
+
+ // NOTE: Use unsigned variant if needed
+ // Unsigned instructions are always right after
+ // the signed equivalent
+ if (is_sign_significant) {
+ if (binop->left->type->is_unsigned) {
+ binop_instr += 1;
+ }
+ }
- case ONYX_AST_NODE_KIND_NEGATE:
+ compile_expression(mod, func, binop->left);
+ compile_expression(mod, func, binop->right);
+
+ bh_arr_push(func->code, ((WasmInstruction){ binop_instr, 0x00 }));
+}
+
+static void compile_unaryop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* unop) {
+ switch (unop->operation) {
+ case ONYX_UNARY_OP_NEGATE:
{
- OnyxTypeInfoKind type_kind = expr->type->kind;
+ OnyxTypeInfoKind type_kind = unop->type->kind;
if (type_kind == ONYX_TYPE_INFO_KIND_INT32) {
bh_arr_push(func->code, ((WasmInstruction){ WI_I32_CONST, 0x00 }));
- compile_expression(mod, func, expr->left);
+ compile_expression(mod, func, unop->left);
bh_arr_push(func->code, ((WasmInstruction){ WI_I32_SUB, 0x00 }));
} else if (type_kind == ONYX_TYPE_INFO_KIND_INT64) {
bh_arr_push(func->code, ((WasmInstruction){ WI_I64_CONST, 0x00 }));
- compile_expression(mod, func, expr->left);
+ compile_expression(mod, func, unop->left);
bh_arr_push(func->code, ((WasmInstruction){ WI_I64_SUB, 0x00 }));
} else {
- compile_expression(mod, func, expr->left);
+ compile_expression(mod, func, unop->left);
if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT32)
bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT64)
bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
}
+
break;
}
+ case ONYX_UNARY_OP_NOT:
+ compile_expression(mod, func, unop->left);
+ bh_arr_push(func->code, ((WasmInstruction){ WI_I32_EQZ, 0x00 }));
+ break;
+
+ case ONYX_UNARY_OP_CAST: compile_cast(mod, func, unop); break;
+ }
+}
+
+static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr) {
+ switch (expr->kind) {
+ case ONYX_AST_NODE_KIND_BIN_OP:
+ compile_binop(mod, func, &expr->as_binop);
+ break;
+
+ case ONYX_AST_NODE_KIND_UNARY_OP:
+ compile_unaryop(mod, func, &expr->as_unaryop);
+ break;
+
case ONYX_AST_NODE_KIND_LOCAL:
case ONYX_AST_NODE_KIND_PARAM:
{
break;
}
- case ONYX_AST_NODE_KIND_CAST: compile_cast(mod, func, expr); break;
case ONYX_AST_NODE_KIND_LITERAL:
{
OnyxAstNodeNumLit* lit = &expr->as_numlit;
/* F64 */ { WI_I32_FROM_F64_S, WI_I32_FROM_F64_U, WI_I64_FROM_F64_S, WI_I64_FROM_F64_U, WI_F32_FROM_F64, WI_NOP, },
};
-static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* cast) {
+static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* cast) {
compile_expression(mod, func, cast->left);
OnyxTypeInfo* from = cast->left->type;