@@ -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.
236236for_content <- for_manual / for_each
237237for_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
0 commit comments