Skip to content

Commit

Permalink
iter: loop for general for-each
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroflag committed Jan 31, 2025
1 parent c8ab45d commit 5b983b3
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 3 deletions.
24 changes: 23 additions & 1 deletion doc/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ drop

### New-Style Loops

Equinox is equipped with four new-style loops as well.
Equinox is equipped with five new-style loops as well.

#### To Loop

Expand Down Expand Up @@ -223,6 +223,28 @@ end
\ k3 30
```

#### Iter Loop

The `iter` loop is a general `for-each` loop used to traverse iterators, such as the result of `gmatch`.

```forth
<iterator> iter: <name>
<body>
end
```

For example:

```forth
alias: gmatch #( string.gmatch 2 )
"1,2,3,4,5" "[^,]+" gmatch iter: each
each >num +
end
```

The previously mentioned `pairs:` and `ipairs:` loops are special cases of this, as they automatically wrap a table into an iterator.

## Word Definition

The single colon (`:`) word is used to define words, while the double colon (`::`) is used for defining words local to the specific file.
Expand Down
6 changes: 6 additions & 0 deletions src/codegen.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,15 @@ function CodeGen:gen(ast)
self:gen(ast.step))
end
if "for_each" == ast.name then
if ast.loop_var1 and ast.loop_var2 then
return string.format(
"for %s,%s in %s do",
ast.loop_var1, ast.loop_var2, self:gen(ast.iterable))
else
return string.format(
"for %s in %s do",
ast.loop_var1, self:gen(ast.iterable))
end
end
if "pairs" == ast.name then
return string.format("pairs(%s)", self:gen(ast.iterable))
Expand Down
1 change: 1 addition & 0 deletions src/dict.lua
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ function Dict:init()
self:def_macro("loop", "macros._loop")
self:def_macro("ipairs:", "macros.for_ipairs")
self:def_macro("pairs:", "macros.for_pairs")
self:def_macro("iter:", "macros.for_each")
self:def_macro("to:", "macros._to")
self:def_macro("step:", "macros._step")
self:def_macro("#(", "macros.arity_call_lua")
Expand Down
16 changes: 15 additions & 1 deletion src/equinox_bundle.lua
Original file line number Diff line number Diff line change
Expand Up @@ -688,9 +688,15 @@ function CodeGen:gen(ast)
self:gen(ast.step))
end
if "for_each" == ast.name then
if ast.loop_var1 and ast.loop_var2 then
return string.format(
"for %s,%s in %s do",
ast.loop_var1, ast.loop_var2, self:gen(ast.iterable))
else
return string.format(
"for %s in %s do",
ast.loop_var1, self:gen(ast.iterable))
end
end
if "pairs" == ast.name then
return string.format("pairs(%s)", self:gen(ast.iterable))
Expand Down Expand Up @@ -1234,6 +1240,7 @@ function Dict:init()
self:def_macro("loop", "macros._loop")
self:def_macro("ipairs:", "macros.for_ipairs")
self:def_macro("pairs:", "macros.for_pairs")
self:def_macro("iter:", "macros.for_each")
self:def_macro("to:", "macros._to")
self:def_macro("step:", "macros._step")
self:def_macro("#(", "macros.arity_call_lua")
Expand Down Expand Up @@ -1932,6 +1939,13 @@ function macros.for_pairs(compiler)
return ast._foreach(var_name1, var_name2, ast._pairs(ast.pop()))
end

function macros.for_each(compiler)
local var_name = compiler:word()
compiler:new_env('ITER_LOOP')
compiler:def_var(var_name)
return ast._foreach(var_name, nil, ast.pop())
end

function macros._to(compiler)
local loop_var = compiler:word()
compiler:new_env('TO_LOOP')
Expand Down Expand Up @@ -2752,7 +2766,7 @@ return utils
end
end

__VERSION__="0.1-25"
__VERSION__="0.1-29"

local Compiler = require("compiler")
local Optimizer = require("ast_optimizer")
Expand Down
7 changes: 7 additions & 0 deletions src/macros.lua
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,13 @@ function macros.for_pairs(compiler)
return ast._foreach(var_name1, var_name2, ast._pairs(ast.pop()))
end

function macros.for_each(compiler)
local var_name = compiler:word()
compiler:new_env('ITER_LOOP')
compiler:def_var(var_name)
return ast._foreach(var_name, nil, ast.pop())
end

function macros._to(compiler)
local loop_var = compiler:word()
compiler:new_env('TO_LOOP')
Expand Down
2 changes: 1 addition & 1 deletion src/version/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1-25
0.1-29
16 changes: 16 additions & 0 deletions tests/test_for_iter.eqx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
depth 0 =assert
adepth 0 =assert

alias: gmatch #( string.gmatch 2 )

0
"1,2,3,4,5" "[^,]+" gmatch iter: each
each >num +
end

dup . cr

15 =assert

depth 0 =assert
adepth 0 =assert

0 comments on commit 5b983b3

Please sign in to comment.