From 94fc3a4dada6434e55868f12ca466fe8d453a49b Mon Sep 17 00:00:00 2001 From: Niels Bross Date: Sat, 30 Aug 2025 22:58:51 +0200 Subject: [PATCH] Added basic for i loops. Missing some breaking tests and more tests. Also want to add for each at some point and it_index. --- AST.jai | 24 ++++++++++++++++++++++++ Codegen.jai | 20 ++++++++++++++++++++ Lexing.jai | 6 +++++- Parsing.jai | 31 ++++++++++++++++++++++++++++++- Semantic_Analysis.jai | 27 +++++++++++++++++++++++++++ test/for_i_loop.ink | 6 ++++++ test/for_i_one_liner.ink | 4 ++++ 7 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 test/for_i_loop.ink create mode 100644 test/for_i_one_liner.ink diff --git a/AST.jai b/AST.jai index a65c791..adbc878 100644 --- a/AST.jai +++ b/AST.jai @@ -21,6 +21,7 @@ AST_Kind :: enum { Call; Struct; If; + For; CBuffer; FieldList; ArgList; @@ -309,6 +310,26 @@ pretty_print_if :: (node : *AST_Node, indentation : int, builder : *String_Build append(builder, ")"); } +pretty_print_for :: (node : *AST_Node, indentation : int, builder : *String_Builder, skip_indent := false) { + if !skip_indent { + indent(builder, indentation); + } + + append(builder, "(for "); + + loop_iterator := node.token; + print_to_builder(builder, "% : ", loop_iterator.ident_value); + + pretty_print_node(node.children[0], 0, builder); + append(builder, ".."); + pretty_print_node(node.children[1], 0, builder); + append(builder, "\n"); + + pretty_print_node(node.children[2], indentation + 4, builder); + + append(builder, ")"); +} + print_expression_statement :: (node : *AST_Node, indentation : int, builder : *String_Builder, skip_indent := false) { if !skip_indent { indent(builder, indentation); @@ -327,6 +348,9 @@ pretty_print_node :: (node : *AST_Node, indentation : int, builder : *String_Bui case .If; { pretty_print_if(node, indentation, builder, skip_indent); } + case .For; { + pretty_print_for(node, indentation, builder, skip_indent); + } case .Struct; case .ArgList; { pretty_print_arglist(node, indentation + 2, builder, skip_indent); diff --git a/Codegen.jai b/Codegen.jai index a35ca5b..158b053 100644 --- a/Codegen.jai +++ b/Codegen.jai @@ -494,6 +494,26 @@ emit_node :: (state : *Codegen_State, node : *AST_Node, indentation : int) { emit_node(state, node.children[0], 0); append(*state.builder, ";"); } + case .For; { + if node.parent.kind != .For { + indent(*state.builder, indentation); + } + + append(*state.builder, "for "); + + loop_ident := node.token.ident_value; + begin_val := node.children[0].integer_value; + end_val := node.children[1].integer_value; + print_to_builder(*state.builder, "(int % = %; % < %; %++)\n", loop_ident, begin_val, loop_ident, end_val, loop_ident); + + indent(*state.builder, indentation); + append(*state.builder, "{\n"); + + emit_block(state, node.children[2], indentation + 1); + + indent(*state.builder, indentation); + append(*state.builder, "}\n"); + } case .If; { if node.parent.kind != .If { indent(*state.builder, indentation); diff --git a/Lexing.jai b/Lexing.jai index 88a4584..eb297c5 100644 --- a/Lexing.jai +++ b/Lexing.jai @@ -54,6 +54,7 @@ Token_Kind :: enum { TOKEN_SEMICOLON; TOKEN_COMMA; TOKEN_DOT; + TOKEN_DOTDOT; TOKEN_IDENTIFIER; @@ -491,7 +492,10 @@ scan_next_token :: (lexer : *Lexer) -> *Token { } case #char ";"; return make_token(lexer, .TOKEN_SEMICOLON); case #char ","; return make_token(lexer, .TOKEN_COMMA); - case #char "."; return make_token(lexer, .TOKEN_DOT); + case #char "."; { + if match_character(lexer, #char ".") return make_token(lexer, .TOKEN_DOTDOT); + return make_token(lexer, .TOKEN_DOT); + } } s : string = .{ count = 1, data = *c }; diff --git a/Parsing.jai b/Parsing.jai index 9d31b9f..1c1b74d 100644 --- a/Parsing.jai +++ b/Parsing.jai @@ -887,7 +887,36 @@ statement :: (parse_state : *Parse_State) -> *AST_Node { } return error_node(parse_state, "'else' without 'if'."); - } + } + } else if match(parse_state, .TOKEN_FOR) { + if check(parse_state, .TOKEN_IDENTIFIER) { + node := make_node(parse_state, .For); + + source_location : Source_Range; + source_location.begin = parse_state.previous; + + loop_iterator := parse_state.current; + node.token = loop_iterator; + advance(parse_state); + consume(parse_state, .TOKEN_COLON, "Expect ':' after for loop iterator."); + + begin_iter := expression(parse_state); + add_child(node, begin_iter); + + consume(parse_state, .TOKEN_DOTDOT, "Expect '..' after for loop iter left hand side."); + + end_iter := expression(parse_state); + add_child(node, end_iter); + + for_body := block(parse_state); + add_child(node, for_body); + + // consume(parse_state, .TOKEN_RIGHTBRACE, "Expect '}' after for body."); + + node.source_location = source_location; + + return node; + } } else { return expression_statement(parse_state); } diff --git a/Semantic_Analysis.jai b/Semantic_Analysis.jai index 71adf51..8c89191 100644 --- a/Semantic_Analysis.jai +++ b/Semantic_Analysis.jai @@ -1485,6 +1485,33 @@ check_node :: (checker : *Semantic_Checker, node : *AST_Node) -> Type_Variable_H case .Return; { return check_node(checker, node.children[0]); } + case .For; { + loop_iterator := node.token; + + symbol : Defined_Symbol; + symbol.name = loop_iterator.ident_value; + symbol.source_node = node; + variable, handle := new_type_variable(checker); + variable.name = symbol.name; + typename : string; + variable.type = .Int; + symbol.type_variable = handle; + add_symbol_to_scope(checker.state, *checker.result.scope_stack, checker.current_scope, symbol.name, symbol); + + begin_iter := check_node(checker, node.children[0]); + begin_var := from_handle(checker, begin_iter); + if begin_var.type != .Int { + + } + + end_iter := check_node(checker, node.children[1]); + end_var := from_handle(checker, end_iter); + if end_var.type != .Int { + + } + + check_block(checker, node.children[2]); + } case .If; { cond_var := check_node(checker, node.children[0]); diff --git a/test/for_i_loop.ink b/test/for_i_loop.ink new file mode 100644 index 0000000..c5928ee --- /dev/null +++ b/test/for_i_loop.ink @@ -0,0 +1,6 @@ +vertex main :: () { + x := 0; + for i : 0..10 { + x += 1.0; + } +} diff --git a/test/for_i_one_liner.ink b/test/for_i_one_liner.ink new file mode 100644 index 0000000..75d0401 --- /dev/null +++ b/test/for_i_one_liner.ink @@ -0,0 +1,4 @@ +vertex main :: () { + x := 0.0; + for i : 0..10 x += 2.0; +}