typedef struct AstBlock AstBlock;
typedef struct AstIf AstIf;
+typedef struct AstFor AstFor;
typedef struct AstWhile AstWhile;
typedef struct AstType AstType;
Ast_Kind_Array_Access,
Ast_Kind_If,
+ Ast_Kind_For,
Ast_Kind_While,
Ast_Kind_Break,
Ast_Kind_Continue,
struct AstCall { AstTyped_base; AstArgument *arguments; u64 arg_count; AstNode *callee; };
struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; u64 arg_count; OnyxIntrinsic intrinsic; };
struct AstArgument { AstTyped_base; AstTyped *value; };
-struct AstAddressOf { AstTyped_base; AstTyped *expr; };
+struct AstAddressOf { AstTyped_base; AstTyped *expr; };
struct AstDereference { AstTyped_base; AstTyped *expr; };
struct AstArrayAccess { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
// Structure Nodes
struct AstBlock { AstNode_base; AstNode *body; Scope *scope; };
struct AstWhile { AstNode_base; AstTyped *cond; AstNode *stmt; };
+struct AstFor {
+ AstNode_base;
+
+ // NOTE: Stores the iteration variable
+ Scope *scope;
+
+ // NOTE: Local defining the iteration variable
+ AstLocal* var;
+
+ AstTyped *start, *end, *step;
+
+ AstNode *stmt;
+};
struct AstIf {
AstNode_base;
AstTyped *cond;
Token_Type_Keyword_Proc = 267,
Token_Type_Keyword_Cast = 268,
Token_Type_Keyword_While = 269,
- Token_Type_Keyword_Break = 270,
- Token_Type_Keyword_Continue = 271,
-
- Token_Type_Right_Arrow = 272,
- Token_Type_Left_Arrow = 273,
- Token_Type_Empty_Block = 274,
-
- Token_Type_Greater_Equal = 275,
- Token_Type_Less_Equal = 276,
- Token_Type_Equal_Equal = 277,
- Token_Type_Not_Equal = 278,
- Token_Type_Plus_Equal = 279,
- Token_Type_Minus_Equal = 280,
- Token_Type_Star_Equal = 281,
- Token_Type_Fslash_Equal = 282,
- Token_Type_Percent_Equal = 283,
-
- Token_Type_Symbol = 284,
- Token_Type_Literal_String = 285,
- Token_Type_Literal_Numeric = 286,
- Token_Type_Literal_True = 287,
- Token_Type_Literal_False = 288,
-
- Token_Type_Count = 289,
+ Token_Type_Keyword_For = 270,
+ Token_Type_Keyword_Break = 271,
+ Token_Type_Keyword_Continue = 272,
+
+ Token_Type_Right_Arrow = 273,
+ Token_Type_Left_Arrow = 274,
+ Token_Type_Empty_Block = 275,
+
+ Token_Type_Greater_Equal = 276,
+ Token_Type_Less_Equal = 277,
+ Token_Type_Equal_Equal = 278,
+ Token_Type_Not_Equal = 279,
+ Token_Type_Plus_Equal = 280,
+ Token_Type_Minus_Equal = 281,
+ Token_Type_Star_Equal = 282,
+ Token_Type_Fslash_Equal = 283,
+ Token_Type_Percent_Equal = 284,
+
+ Token_Type_Symbol = 285,
+ Token_Type_Literal_String = 286,
+ Token_Type_Literal_Numeric = 287,
+ Token_Type_Literal_True = 288,
+ Token_Type_Literal_False = 289,
+
+ Token_Type_Count = 290,
} TokenType;
typedef struct OnyxFilePos {
const char* filename;
char* line_start;
u32 line;
-
+
// NOTE: This assumes that no line is no longer than 2^16 chars
u16 column, length;
} OnyxFilePos;
}
}
-other_str :: "I can't believe this \n actually fricken worked!";
+for_test :: proc {
+ // 0 to 9
+ for i: 0, 10 print(i);
+}
-str_test :: proc {
+str_test :: proc #export "main" {
hello_str :: "Hello World!";
// Address of and dereference cancel each other out
print(^*hello_str);
- print("This is a test"[10] as i32);
+ print(hello_str, 5);
+
+ for i: 0, 10, 2 print(i);
+
+ for y: 0, 5 for x: 0, 5 print(x + y * 5);
}
// Don't need to bind this function to a symbol
-proc #export "main" {
+proc #export "main2" {
print(min(10.0, 12.0));
global_arr = 128 as ^i32;
}
}
+print_str_len :: proc (str: ^u8, len: i32) {
+ for i: 0, len print(str[i] as i32);
+}
+
print :: proc #overloaded {
print_bool,
print_i32,
print_f64arr,
print_str,
+ print_str_len,
}
CHECK(return, AstReturn* retnode);
CHECK(if, AstIf* ifnode);
CHECK(while, AstWhile* whilenode);
+CHECK(for, AstFor* fornode);
CHECK(call, AstCall* call);
CHECK(binaryop, AstBinaryOp* binop);
CHECK(expression, AstTyped* expr);
return check_statement(whilenode->stmt);
}
+CHECK(for, AstFor* fornode) {
+ check_expression(fornode->start);
+ check_expression(fornode->end);
+ if (fornode->step) check_expression(fornode->step);
+
+ // HACK
+ if (fornode->start->type != &basic_types[Basic_Kind_I32]) {
+ onyx_message_add(Msg_Type_Literal,
+ fornode->start->token->pos,
+ "expected expression of type i32 for start");
+ return 1;
+ }
+
+ if (fornode->end->type != &basic_types[Basic_Kind_I32]) {
+ onyx_message_add(Msg_Type_Literal,
+ fornode->end->token->pos,
+ "expected expression of type i32 for end");
+ return 1;
+ }
+
+ check_statement(fornode->stmt);
+
+ return 0;
+}
+
static AstTyped* match_overloaded_function(AstCall* call, AstOverloadedFunction* ofunc) {
bh_arr_each(AstTyped *, node, ofunc->overloads) {
AstFunction* overload = (AstFunction *) *node;
case Ast_Kind_Return: return check_return((AstReturn *) stmt);
case Ast_Kind_If: return check_if((AstIf *) stmt);
case Ast_Kind_While: return check_while((AstWhile *) stmt);
+ case Ast_Kind_For: return check_for((AstFor *) stmt);
case Ast_Kind_Call: return check_call((AstCall *) stmt);
case Ast_Kind_Block: return check_block((AstBlock *) stmt);
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("for", 1, Token_Type_Keyword_For);
LITERAL_TOKEN("break", 1, Token_Type_Keyword_Break);
LITERAL_TOKEN("continue", 1, Token_Type_Keyword_Continue);
LITERAL_TOKEN("true", 1, Token_Type_Literal_True);
static AstTyped* parse_expression(OnyxParser* parser);
static AstIf* parse_if_stmt(OnyxParser* parser);
static AstWhile* parse_while_stmt(OnyxParser* parser);
+static AstFor* parse_for_stmt(OnyxParser* parser);
static b32 parse_symbol_declaration(OnyxParser* parser, AstNode** ret);
static AstReturn* parse_return_statement(OnyxParser* parser);
static AstBlock* parse_block(OnyxParser* parser);
return while_node;
}
+static AstFor* parse_for_stmt(OnyxParser* parser) {
+ AstFor* for_node = make_node(AstFor, Ast_Kind_For);
+ for_node->token = expect_token(parser, Token_Type_Keyword_For);
+
+ AstLocal* var_node = make_node(AstLocal, Ast_Kind_Local);
+ var_node->token = expect_token(parser, Token_Type_Symbol);
+ var_node->type_node = (AstType *) &basic_type_i32;
+
+ for_node->var = var_node;
+
+ expect_token(parser, ':');
+ for_node->start = parse_expression(parser);
+ expect_token(parser, ',');
+ for_node->end = parse_expression(parser);
+
+ if (parser->curr->type == ',') {
+ consume_token(parser);
+ for_node->step = parse_expression(parser);
+ }
+
+ for_node->stmt = parse_statement(parser);
+
+ return for_node;
+}
+
// Returns 1 if the symbol was consumed. Returns 0 otherwise
// ret is set to the statement to insert
// <symbol> : <type> = <expr>
retval = (AstNode *) parse_while_stmt(parser);
break;
+ case Token_Type_Keyword_For:
+ needs_semicolon = 0;
+ retval = (AstNode *) parse_for_stmt(parser);
+ break;
+
case Token_Type_Keyword_Break:
retval = make_node(AstNode, Ast_Kind_Break);
retval->token = expect_token(parser, Token_Type_Keyword_Break);
static void symres_return(AstReturn* ret);
static void symres_if(AstIf* ifnode);
static void symres_while(AstWhile* whilenode);
+static void symres_for(AstFor* fornode);
static void symres_statement_chain(AstNode* walker, AstNode** trailer);
static b32 symres_statement(AstNode* stmt);
static void symres_block(AstBlock* block);
symres_statement(whilenode->stmt);
}
+static void symres_for(AstFor* fornode) {
+ fornode->scope = scope_create(semstate.node_allocator, semstate.curr_scope);
+ scope_enter(fornode->scope);
+
+ symbol_introduce(fornode->var->token, (AstNode *) fornode->var);
+
+ symres_expression(&fornode->start);
+ symres_expression(&fornode->end);
+ if (fornode->step) symres_expression(&fornode->step);
+
+ symres_statement(fornode->stmt);
+
+ scope_leave();
+}
+
// NOTE: Returns 1 if the statment should be removed
static b32 symres_statement(AstNode* stmt) {
switch (stmt->kind) {
case Ast_Kind_Return: symres_return((AstReturn *) stmt); return 0;
case Ast_Kind_If: symres_if((AstIf *) stmt); return 0;
case Ast_Kind_While: symres_while((AstWhile *) stmt); return 0;
+ case Ast_Kind_For: symres_for((AstFor *) stmt); return 0;
case Ast_Kind_Call: symres_call((AstCall *) stmt); return 0;
case Ast_Kind_Argument: symres_expression((AstTyped **) &((AstArgument *)stmt)->value); return 0;
case Ast_Kind_Block: symres_block((AstBlock *) stmt); return 0;
"ARRAY_ACCESS",
"IF",
+ "FOR",
"WHILE",
"BREAK",
"CONTINUE",
COMPILE_FUNC(assignment, AstBinaryOp* assign);
COMPILE_FUNC(if, AstIf* if_node);
COMPILE_FUNC(while, AstWhile* while_node);
+COMPILE_FUNC(for, AstFor* for_node);
COMPILE_FUNC(binop, AstBinaryOp* binop);
COMPILE_FUNC(unaryop, AstUnaryOp* unop);
COMPILE_FUNC(call, AstCall* call);
case Ast_Kind_Return: compile_return(mod, &code, (AstReturn *) stmt); break;
case Ast_Kind_If: compile_if(mod, &code, (AstIf *) stmt); break;
case Ast_Kind_While: compile_while(mod, &code, (AstWhile *) stmt); break;
+ case Ast_Kind_For: compile_for(mod, &code, (AstFor *) stmt); break;
case Ast_Kind_Break: compile_structured_jump(mod, &code, 0); break;
case Ast_Kind_Continue: compile_structured_jump(mod, &code, 1); break;
case Ast_Kind_Block: compile_block(mod, &code, (AstBlock *) stmt); break;
*pcode = code;
}
+COMPILE_FUNC(for, AstFor* for_node) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ i32 it_idx = (i32) bh_imap_get(&mod->local_map, (u64) for_node->var);
+
+ compile_expression(mod, &code, for_node->start);
+ WID(WI_LOCAL_SET, it_idx);
+
+ WID(WI_BLOCK_START, 0x40);
+ WID(WI_LOOP_START, 0x40);
+
+ bh_arr_push(mod->structured_jump_target, 1);
+ bh_arr_push(mod->structured_jump_target, 2);
+
+ WID(WI_LOCAL_GET, it_idx);
+ compile_expression(mod, &code, for_node->end);
+ WI(WI_I32_GE_S);
+ WID(WI_COND_JUMP, 0x01);
+
+ if (for_node->stmt->kind == Ast_Kind_Block) {
+ forll (AstNode, stmt, ((AstBlock *) for_node->stmt)->body, next) {
+ compile_statement(mod, &code, stmt);
+ }
+ } else {
+ compile_statement(mod, &code, for_node->stmt);
+ }
+
+ if (for_node->step == NULL)
+ WID(WI_I32_CONST, 0x01);
+ else
+ compile_expression(mod, &code, for_node->step);
+ WID(WI_LOCAL_GET, it_idx);
+ WI(WI_I32_ADD);
+ WID(WI_LOCAL_SET, it_idx);
+
+ bh_arr_pop(mod->structured_jump_target);
+ bh_arr_pop(mod->structured_jump_target);
+
+ WID(WI_JUMP, 0x00);
+
+ WI(WI_LOOP_END);
+ WI(WI_BLOCK_END);
+
+ *pcode = code;
+}
+
// NOTE: These need to be in the same order as
// the OnyxBinaryOp enum
static const WasmInstructionType binop_map[][4] = {
switch (instr->type) {
case WI_LOCAL_GET:
case WI_LOCAL_SET:
+ case WI_LOCAL_TEE:
case WI_GLOBAL_GET:
case WI_GLOBAL_SET:
case WI_CALL: