Renamed foreach to for
All checks were successful
Build / build (push) Successful in 1m51s

This commit is contained in:
Leon Mika 2025-02-04 09:04:11 +11:00
parent d1a9bb86c7
commit 67671ce475
5 changed files with 51 additions and 43 deletions

View file

@ -50,10 +50,10 @@ If COL is a list, `first` will consume from index 0 and will continue until eith
satisfies the predicate, or until the end of the list is reached. If COL is an iterator, `first` will continue
consuming values until a value satisfying the predicate is found, or until the iterator is exhausted.
### foreach
### for
```
foreach COL BLOCK
for COL BLOCK
```
Iterates BLOCK over every element of the sequence.
@ -63,16 +63,16 @@ If COL is a hash, BLOCK receives both the key and value of each element.
BLOCK can call `break` and `continue` which will exit out of the loop, or jump to the start of the next iteration
respectively.
The return value of `foreach` will be the result of the last iteration, unless `break` is called with a value.
The return value of `for` will be the result of the last iteration, unless `break` is called with a value.
This is implemented as a macro but can be used in a pipeline.
```
foreach [1 2 3] { |e|
for [1 2 3] { |e|
echo "Element = $e"
}
[a:"one" b:"two"] | foreach { |k v|
[a:"one" b:"two"] | for { |k v|
echo "Key $k = $v"
}
```
@ -167,7 +167,7 @@ If FROM and TO are equal, or if FROM is unspecified and TO is 0, then the sequen
If -inc is specified, then the sequence will step towards TO inclusively.
```
foreach (seq 5) { |i|
for (seq 5) { |i|
echo $i
}
```
@ -182,3 +182,11 @@ Sets the value of variable NAME to VALUE. Any variable with NAME will be checked
within the scope first, including any parent scopes, before a new variable is defined.
Any new variables will only be defined with the current scope.
### set!
```
set! NAME VALUE
```
Sets the value of variable NAME to VALUE. VALUE must be non-null otherwise `set!` will raise an error.

View file

@ -104,7 +104,7 @@ func New(opts ...InstOption) *Inst {
rootEC.addCmd("error", invokableFunc(errorBuiltin))
rootEC.addMacro("if", macroFunc(ifBuiltin))
rootEC.addMacro("foreach", macroFunc(foreachBuiltin))
rootEC.addMacro("for", macroFunc(foreachBuiltin))
rootEC.addMacro("proc", macroFunc(procBuiltin))
rootEC.addMacro("try", macroFunc(tryBuiltin))

View file

@ -179,7 +179,7 @@ func TestInst_MissingVarHandler(t *testing.T) {
var parseComments1 = `
proc lookup { |file|
foreach { |toks|
for { |toks|
}
# this use to fail
}
@ -187,7 +187,7 @@ var parseComments1 = `
var parseComments2 = `
proc lookup { |file|
foreach { |toks|
for { |toks|
}
# this use to fail
@ -199,7 +199,7 @@ var parseComments2 = `
var parseComments3 = `
proc lookup { |file|
foreach { |toks|
for { |toks|
}
# this use to fail
@ -211,7 +211,7 @@ var parseComments3 = `
var parseComments4 = `
proc lookup { |file|
foreach { |toks|
for { |toks|
}
}
# this use to fail`

View file

@ -129,7 +129,7 @@ func TestBuiltins_Echo(t *testing.T) {
{desc: "interpolated string 3", expr: `echo "separate\nlines\n\tand tabs"`, want: "separate\nlines\n\tand tabs\n"},
{desc: "interpolated string 4", expr: `set what "Hello" ; set where "world" ; echo "$what, $where"`, want: "Hello, world\n"},
{desc: "interpolated string 5", expr: `
foreach [123 "foo" true ()] { |x|
for [123 "foo" true ()] { |x|
echo "[[$x]]"
}
`, want: "[[123]]\n[[foo]]\n[[true]]\n[[]]\n"},
@ -210,8 +210,8 @@ func TestBuiltins_If(t *testing.T) {
{desc: "compressed else", expr: `if $x { echo "true" } else { echo "false" }`, want: "false\n(nil)\n"},
{desc: "compressed if", expr: `if $x { echo "x" } elif $y { echo "y" } else { echo "false" }`, want: "false\n(nil)\n"},
{desc: "if of itr 1", expr: `set i (itr) ; if $i { echo "more" } else { echo "none" }`, want: "more\n(nil)\n"},
{desc: "if of itr 2", expr: `set i (itr) ; foreach (seq 1) { head $i } ; if $i { echo "more" } else { echo "none" }`, want: "more\n(nil)\n"},
{desc: "if of itr 3", expr: `set i (itr) ; foreach (seq 3) { head $i } ; if $i { echo "more" } else { echo "none" }`, want: "none\n(nil)\n"},
{desc: "if of itr 2", expr: `set i (itr) ; for (seq 1) { head $i } ; if $i { echo "more" } else { echo "none" }`, want: "more\n(nil)\n"},
{desc: "if of itr 3", expr: `set i (itr) ; for (seq 3) { head $i } ; if $i { echo "more" } else { echo "none" }`, want: "none\n(nil)\n"},
{desc: "if of itr 4", expr: `set i (itr | map { |x| add 2 $x }) ; if $i { echo "more" } else { echo "none" }`, want: "more\n(nil)\n"},
{desc: "if of itr 5", expr: `set i (itr | filter { |x| () }) ; if $i { echo "more" } else { echo "none" }`, want: "none\n(nil)\n"},
{desc: "if of itr 6", expr: `set i (itr | filter { |x| 1 }) ; if $i { echo "more" } else { echo "none" }`, want: "more\n(nil)\n"},
@ -430,26 +430,26 @@ func TestBuiltins_Try(t *testing.T) {
}
}
func TestBuiltins_ForEach(t *testing.T) {
func TestBuiltins_For(t *testing.T) {
tests := []struct {
desc string
expr string
want string
}{
{desc: "iterate over list 1", expr: `
foreach ["1" "2" "3"] { |v|
for ["1" "2" "3"] { |v|
echo $v
}`, want: "1\n2\n3\n(nil)\n"},
{desc: "iterate over list 2",
expr: `foreach ["1" "2" "3"] echo`,
expr: `for ["1" "2" "3"] echo`,
want: "1\n2\n3\n(nil)\n"},
// TODO: hash is not sorted, so need to find a way to sort it
{desc: "iterate over map 1", expr: `
foreach [a:"1"] { |k v| echo $k "=" $v }`, want: "a=1\n(nil)\n"},
for [a:"1"] { |k v| echo $k "=" $v }`, want: "a=1\n(nil)\n"},
{desc: "iterate over map 2", expr: `
foreach [a:"1"] echo`, want: "a1\n(nil)\n"},
{desc: "iterate via pipe", expr: `["2" "4" "6"] | foreach { |x| echo $x }`, want: "2\n4\n6\n(nil)\n"},
{desc: "iterate from iterator 1", expr: `itr | foreach { |x| echo $x }`, want: "1\n2\n3\n(nil)\n"},
for [a:"1"] echo`, want: "a1\n(nil)\n"},
{desc: "iterate via pipe", expr: `["2" "4" "6"] | for { |x| echo $x }`, want: "2\n4\n6\n(nil)\n"},
{desc: "iterate from iterator 1", expr: `itr | for { |x| echo $x }`, want: "1\n2\n3\n(nil)\n"},
}
for _, tt := range tests {
@ -473,29 +473,29 @@ func TestBuiltins_Break(t *testing.T) {
want string
}{
{desc: "break unconditionally returning nothing", expr: `
foreach ["1" "2" "3"] { |v|
for ["1" "2" "3"] { |v|
break
echo $v
}`, want: "(nil)\n"},
{desc: "break conditionally returning nothing", expr: `
foreach ["1" "2" "3"] { |v|
for ["1" "2" "3"] { |v|
echo $v
if (eq $v "2") { break }
}`, want: "1\n2\n(nil)\n"},
{desc: "break inner loop only returning nothing", expr: `
foreach ["a" "b"] { |u|
foreach ["1" "2" "3"] { |v|
for ["a" "b"] { |u|
for ["1" "2" "3"] { |v|
echo $u $v
if (eq $v "2") { break }
}
}`, want: "a1\na2\nb1\nb2\n(nil)\n"},
{desc: "break returning value 1", expr: `
echo (foreach ["1" "2" "3"] { |v|
echo (for ["1" "2" "3"] { |v|
echo $v
if (eq $v "2") { break "hello" }
})`, want: "1\n2\nhello\n(nil)\n"},
{desc: "break returning value 2", expr: `
echo (foreach (itr) { |v|
echo (for (itr) { |v|
echo $v
if (eq $v 2) { break "hello" }
})`, want: "1\n2\nhello\n(nil)\n"},
@ -522,20 +522,20 @@ func TestBuiltins_Continue(t *testing.T) {
want string
}{
{desc: "continue unconditionally", expr: `
foreach ["1" "2" "3"] { |v|
for ["1" "2" "3"] { |v|
echo $v "s"
continue
echo $v "e"
}`, want: "1s\n2s\n3s\n(nil)\n"},
{desc: "conditionally conditionally", expr: `
foreach ["1" "2" "3"] { |v|
for ["1" "2" "3"] { |v|
echo $v "s"
if (eq $v "2") { continue }
echo $v "e"
}`, want: "1s\n1e\n2s\n3s\n3e\n(nil)\n"},
{desc: "continue inner loop only", expr: `
foreach ["a" "b"] { |u|
foreach ["1" "2" "3"] { |v|
for ["a" "b"] { |u|
for ["1" "2" "3"] { |v|
if (eq $v "2") { continue }
echo $u $v
}
@ -726,7 +726,7 @@ func TestBuiltins_Return(t *testing.T) {
`, want: "Greet the\nHello, moon\n(nil)\n"},
{desc: "return in loop", expr: `
proc countdown { |nums|
foreach $nums { |n|
for $nums { |n|
echo $n
if (eq $n 3) {
return "abort"
@ -751,7 +751,7 @@ func TestBuiltins_Return(t *testing.T) {
}
proc test-thing {
foreach [1 2 3] { |x|
for [1 2 3] { |x|
do-thing {
echo $x
}
@ -766,7 +766,7 @@ func TestBuiltins_Return(t *testing.T) {
}
proc test-thing {
foreach [1 2 3] { |x|
for [1 2 3] { |x|
do-thing (proc {
echo $x
})
@ -781,7 +781,7 @@ func TestBuiltins_Return(t *testing.T) {
}
proc test-thing {
foreach [1 2 3] { |x|
for [1 2 3] { |x|
set myClosure (proc { echo $x })
do-thing $myClosure
}
@ -800,7 +800,7 @@ func TestBuiltins_Return(t *testing.T) {
}
}
foreach (test-thing) { |y| call $y }
for (test-thing) { |y| call $y }
`, want: "1\n2\n3\n(nil)\n"},
{desc: "check closure 5", expr: `
proc do-thing { |p|
@ -815,7 +815,7 @@ func TestBuiltins_Return(t *testing.T) {
}
set hello "xx"
foreach (test-thing) { |y| call $y ; echo $hello }
for (test-thing) { |y| call $y ; echo $hello }
`, want: "1\nxx\n2\nxx\n3\nxx\n(nil)\n"},
{desc: "check closure 7", expr: `
proc do-thing { |p|
@ -832,7 +832,7 @@ func TestBuiltins_Return(t *testing.T) {
}
set hello "xx"
foreach (test-thing) { |y| call $y ; echo $hello }
for (test-thing) { |y| call $y ; echo $hello }
`, want: "3\nxx\n3\nxx\n3\nxx\n(nil)\n"},
{desc: "check closure 7", expr: `
proc do-thing { |p|
@ -850,7 +850,7 @@ func TestBuiltins_Return(t *testing.T) {
}
set hello "xx"
foreach (test-thing) { |y| call $y ; echo $hello }
for (test-thing) { |y| call $y ; echo $hello }
`, want: "1\nxx\n2\nxx\n3\nxx\n(nil)\n"},
}
@ -965,7 +965,7 @@ func TestBuiltins_Map(t *testing.T) {
set add2 (proc { |x| add $x 2 })
set l (itr | map $add2)
foreach $l { |x| echo $x }
for $l { |x| echo $x }
`, want: "3\n4\n5\n(nil)\n"},
}
@ -1218,7 +1218,7 @@ func TestBuiltins_Filter(t *testing.T) {
}},
{desc: "filter map 3", expr: `filter [alpha:"hello" bravo:"world"] { |k v| eq $v "alpha" }`, want: map[string]any{}},
{desc: "filter itr 1", expr: `set s "" ; itr | filter { |x| ne $x 2 } | foreach { |x| set s "$s $x" }; $s`, want: " 1 3"},
{desc: "filter itr 1", expr: `set s "" ; itr | filter { |x| ne $x 2 } | for { |x| set s "$s $x" }; $s`, want: " 1 3"},
}
for _, tt := range tests {

View file

@ -187,7 +187,7 @@ func TestInst_SetBuiltin(t *testing.T) {
wantOut string
}{
{descr: "return as is", expr: `countTo3`, want: []string{"1", "2", "3"}},
{descr: "iterate over", expr: `foreach (countTo3) { |x| echo $x }`, wantOut: "1\n2\n3\n"},
{descr: "iterate over", expr: `for (countTo3) { |x| echo $x }`, wantOut: "1\n2\n3\n"},
}
for _, tt := range tests {
@ -222,7 +222,7 @@ func TestInst_SetBuiltin(t *testing.T) {
}{
{descr: "return as is", expr: `getOpaque`, wantErr: false},
{descr: "carry around ok", expr: `set x (getOpaque) ; $x`, wantErr: false},
{descr: "iterate over", expr: `foreach (countTo3) { |x| echo $x }`, wantErr: true},
{descr: "iterate over", expr: `for (countTo3) { |x| echo $x }`, wantErr: true},
}
for _, tt := range tests {