diff --git a/_docs/mod/core.md b/_docs/mod/core.md index 6b9e3a7..37bdbbe 100644 --- a/_docs/mod/core.md +++ b/_docs/mod/core.md @@ -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. + diff --git a/ucl/inst.go b/ucl/inst.go index a3ea956..d07bcc6 100644 --- a/ucl/inst.go +++ b/ucl/inst.go @@ -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)) diff --git a/ucl/inst_test.go b/ucl/inst_test.go index 1faa97c..931c924 100644 --- a/ucl/inst_test.go +++ b/ucl/inst_test.go @@ -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` diff --git a/ucl/testbuiltins_test.go b/ucl/testbuiltins_test.go index f843150..7aa5644 100644 --- a/ucl/testbuiltins_test.go +++ b/ucl/testbuiltins_test.go @@ -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 { diff --git a/ucl/userbuiltin_test.go b/ucl/userbuiltin_test.go index 149e988..816cd48 100644 --- a/ucl/userbuiltin_test.go +++ b/ucl/userbuiltin_test.go @@ -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 {