Skip to content

Commit a252990

Browse files
committed
add range expression range-for
1 parent 6f900e3 commit a252990

3 files changed

Lines changed: 65 additions & 20 deletions

File tree

src/pscript/context.cpp

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ for <- 'for' parens_open for_content parens_close compound
235235
# note that there are two types of for loops: for-each loops and regular 'manual' for loops.
236236
for_content <- for_manual / for_each
237237
for_manual <- declaration semicolon expression semicolon expression
238-
for_each <- 'let ' identifier space colon space expression
238+
for_each <- 'let ' identifier space colon space (range_expression / expression)
239+
range_expression <- expression '..' expression
239240
240241
# ================= comment =================
241242
@@ -470,25 +471,51 @@ ps::value context::execute(peg::Ast const* node, block_scope* scope, std::string
470471
if (node_is_type(node, "for")) {
471472
peg::Ast const* content = find_child_with_type(node, "for_content");
472473
peg::Ast const* compound = find_child_with_type(node, "compound");
473-
// TODO: add range-for
474-
peg::Ast const* initializer = find_child_with_type(content, "declaration");
475-
peg::Ast const* condition = find_child_with_type(content, "expression");
476-
peg::Ast const* on_iterate = nullptr;
477-
for (auto const& child : content->nodes) {
478-
if (child.get() == condition) continue;
479-
if (node_is_type(child.get(), "expression") || node_is_type(child.get(), "statement")) {
480-
on_iterate = child.get();
481-
break;
474+
if (node_is_type(content, "for_each")) {
475+
peg::Ast const* identifier = find_child_with_type(content, "identifier");
476+
peg::Ast const* iterable = find_child_with_type(content, "expression");
477+
peg::Ast const* range = find_child_with_type(content, "range_expression");
478+
// using for (let i : N..M) syntax
479+
if (range) {
480+
peg::Ast const* begin = range->nodes[0].get();
481+
peg::Ast const* end = range->nodes[1].get();
482+
block_scope iterator_scope {};
483+
iterator_scope.parent = scope;
484+
ps::variable& iterator = create_variable(identifier->token_to_string(), evaluate_expression(begin, scope), &iterator_scope);
485+
ps::value& it = iterator.value();
486+
ps::value end_val = evaluate_expression(end, &iterator_scope);
487+
while(it < end_val) {
488+
block_scope local_scope {};
489+
local_scope.parent = &iterator_scope;
490+
execute(compound, &local_scope, namespace_prefix);
491+
// increment iterator
492+
it += ps::value::from(memory(), 1);
493+
}
494+
}
495+
// using for (let i : iterable) syntax
496+
else if (iterable) {
497+
498+
}
499+
} else { // regular for loop
500+
peg::Ast const* initializer = find_child_with_type(content, "declaration");
501+
peg::Ast const* condition = find_child_with_type(content, "expression");
502+
peg::Ast const* on_iterate = nullptr;
503+
for (auto const& child : content->nodes) {
504+
if (child.get() == condition) continue;
505+
if (node_is_type(child.get(), "expression") || node_is_type(child.get(), "statement")) {
506+
on_iterate = child.get();
507+
break;
508+
}
509+
}
510+
block_scope iterator_scope {};
511+
iterator_scope.parent = scope;
512+
execute(initializer, &iterator_scope, namespace_prefix);
513+
while(static_cast<bool>(evaluate_expression(condition, &iterator_scope))) {
514+
block_scope local_scope {};
515+
local_scope.parent = &iterator_scope;
516+
execute(compound, &local_scope, namespace_prefix);
517+
execute(on_iterate, &iterator_scope, namespace_prefix);
482518
}
483-
}
484-
block_scope iterator_scope {};
485-
iterator_scope.parent = scope;
486-
execute(initializer, &iterator_scope, namespace_prefix);
487-
while(static_cast<bool>(evaluate_expression(condition, &iterator_scope))) {
488-
block_scope local_scope {};
489-
local_scope.parent = &iterator_scope;
490-
execute(compound, &local_scope, namespace_prefix);
491-
execute(on_iterate, &iterator_scope, namespace_prefix);
492519
}
493520
}
494521

tests/main.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,3 +1015,21 @@ TEST_CASE("variadics") {
10151015
ctx.execute(script);
10161016
}
10171017
}
1018+
1019+
TEST_CASE("range-for") {
1020+
constexpr size_t memsize = 1024;
1021+
ps::context ctx(memsize);
1022+
1023+
SECTION("range expression syntax") {
1024+
std::string source = R"(
1025+
import std.io;
1026+
1027+
for (let i : 0..10) {
1028+
std.io.print(i);
1029+
}
1030+
)";
1031+
1032+
ps::script script(source, ctx);
1033+
ctx.execute(script);
1034+
}
1035+
}

todo.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
- [X] documentation/tutorial on how to use
1515
- [ ] extend standard library and functions for list/string types
1616
- [X] external functions with no return type
17-
- [ ] command-line interpreter tool
17+
- [X] command-line interpreter tool
1818
- [ ] debugger
1919
- [ ] move test suite to full programs loaded from files instead of small snippets
2020
- [X] benchmarking suite

0 commit comments

Comments
 (0)