This commit is contained in:
parent
d1a9bb86c7
commit
67671ce475
|
@ -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.
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue