mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-04 02:37:50 +08:00
d7fe04414b
This removes the need for various "use-foo" setups for the standard library modules - test code can just call "use foo" like normal Elvish code.
897 lines
20 KiB
Plaintext
897 lines
20 KiB
Plaintext
//////////
|
|
# pragma #
|
|
//////////
|
|
|
|
~> pragma unknown-command
|
|
Compilation error: need literal =
|
|
[tty]:1:23: pragma unknown-command
|
|
~> pragma unknown-command =
|
|
Compilation error: need pragma value
|
|
[tty]:1:25: pragma unknown-command =
|
|
~> pragma unknown-command x
|
|
Compilation error: must be literal =
|
|
[tty]:1:24-24: pragma unknown-command x
|
|
~> pragma bad-name = some-value
|
|
Compilation error: unknown pragma bad-name
|
|
[tty]:1:8-15: pragma bad-name = some-value
|
|
~> pragma unknown-command = bad
|
|
Compilation error: invalid value for unknown-command: bad
|
|
[tty]:1:26-28: pragma unknown-command = bad
|
|
|
|
// Actual effect of the unknown-command pragma is tested along with external
|
|
// command resolution in compile_effect_test.elvts.
|
|
|
|
///////
|
|
# var #
|
|
///////
|
|
|
|
// Interaction between assignment and variable scoping is tested as part of
|
|
// closure behavior in compile_value_test.elvts.
|
|
|
|
## declaring without assigning ##
|
|
~> var x
|
|
put $x
|
|
▶ $nil
|
|
## Quoted variable name ##
|
|
~> var 'a/b'
|
|
put $'a/b'
|
|
▶ $nil
|
|
## declaring one variable whose name ends in ":" ##
|
|
~> var a:
|
|
## declaring a variable whose name ends in "~" initializes it to the builtin nop ##
|
|
~> var cmd~
|
|
cmd &ignored-opt ignored-arg
|
|
is $cmd~ $nop~
|
|
▶ $true
|
|
## declaring multiple variables ##
|
|
~> var x y
|
|
put $x $y
|
|
▶ $nil
|
|
▶ $nil
|
|
## declaring one variable with initial value ##
|
|
~> var x = foo
|
|
put $x
|
|
▶ foo
|
|
## declaring multiple variables with initial values ##
|
|
~> var x y = foo bar
|
|
put $x $y
|
|
▶ foo
|
|
▶ bar
|
|
## rest variable ##
|
|
~> var x @y z = a b c d
|
|
put $x $y $z
|
|
▶ a
|
|
▶ [b c]
|
|
▶ d
|
|
## rest variable with empty RHS ##
|
|
~> var @x =
|
|
put $x
|
|
▶ []
|
|
## shadowing ##
|
|
~> var x = old
|
|
fn f { put $x }
|
|
var x = new
|
|
put $x
|
|
f
|
|
▶ new
|
|
▶ old
|
|
|
|
## concurrent creation and access ##
|
|
// Ensure that there is no race with "go test -race"
|
|
~> var x = 1
|
|
put $x | var y = (all)
|
|
|
|
## assignment errors when the RHS errors ##
|
|
~> var x = [][1]
|
|
Exception: out of range: index must be from 0 to -1, but is 1
|
|
[tty]:1:9-13: var x = [][1]
|
|
|
|
## arity mismatch ##
|
|
~> var x = 1 2
|
|
Exception: arity mismatch: assignment right-hand-side must be 1 value, but is 2 values
|
|
[tty]:1:1-11: var x = 1 2
|
|
~> var x y = 1
|
|
Exception: arity mismatch: assignment right-hand-side must be 2 values, but is 1 value
|
|
[tty]:1:1-11: var x y = 1
|
|
~> var x y @z = 1
|
|
Exception: arity mismatch: assignment right-hand-side must be 2 or more values, but is 1 value
|
|
[tty]:1:1-14: var x y @z = 1
|
|
|
|
## variable name must not be empty ##
|
|
~> var ''
|
|
Compilation error: variable name must not be empty
|
|
[tty]:1:5-6: var ''
|
|
|
|
## variable name that must be quoted after $ must be quoted ##
|
|
~> var a/b
|
|
Compilation error: lvalue must be valid literal variable names
|
|
[tty]:1:5-7: var a/b
|
|
|
|
## multiple @ not allowed ##
|
|
~> var x @y @z = a b c d
|
|
Compilation error: at most one rest variable is allowed
|
|
[tty]:1:10-11: var x @y @z = a b c d
|
|
|
|
## non-local not allowed ##
|
|
~> var ns:a
|
|
Compilation error: cannot create variable $ns:a; new variables can only be created in the current scope
|
|
[tty]:1:5-8: var ns:a
|
|
|
|
## index not allowed ##
|
|
~> var a[0]
|
|
Compilation error: new variable $a must not have indices
|
|
[tty]:1:5-8: var a[0]
|
|
|
|
## composite expression not allowed ##
|
|
~> var a'b'
|
|
Compilation error: lvalue may not be composite expressions
|
|
[tty]:1:5-8: var a'b'
|
|
|
|
## braced lists must not have any indices when used as a lvalue ##
|
|
~> var {a b}[0] = x y
|
|
Compilation error: braced list may not have indices when used as lvalue
|
|
[tty]:1:5-12: var {a b}[0] = x y
|
|
|
|
///////
|
|
# set #
|
|
///////
|
|
|
|
## setting one variable ##
|
|
~> var x
|
|
set x = foo
|
|
put $x
|
|
▶ foo
|
|
|
|
## empty RHS is allowed ##
|
|
~> var x
|
|
set @x =
|
|
put $x
|
|
▶ []
|
|
|
|
## variable must already exist ##
|
|
~> set x = foo
|
|
Compilation error: cannot find variable $x
|
|
[tty]:1:5-5: set x = foo
|
|
|
|
## list element assignment ##
|
|
~> var li = [foo bar]; set li[0] = 233; put $@li
|
|
▶ 233
|
|
▶ bar
|
|
|
|
## variable in list assignment must already be defined ##
|
|
// Regression test for b.elv.sh/889
|
|
~> set y[0] = a
|
|
Compilation error: cannot find variable $y
|
|
[tty]:1:5-8: set y[0] = a
|
|
|
|
## map element assignment ##
|
|
~> var di = [&k=v]
|
|
set di[k] = lorem
|
|
set di[k2] = ipsum
|
|
put $di[k] $di[k2]
|
|
▶ lorem
|
|
▶ ipsum
|
|
|
|
## nested map element assignment ##
|
|
~> var d = [&a=[&b=v]]
|
|
put $d[a][b]
|
|
set d[a][b] = u
|
|
put $d[a][b]
|
|
▶ v
|
|
▶ u
|
|
|
|
## setting a non-exist environment variable ##
|
|
//unset-env X
|
|
~> has-env X
|
|
set E:X = x
|
|
get-env X
|
|
▶ $false
|
|
▶ x
|
|
|
|
## map element assignment errors ##
|
|
~> var li = [foo]; set li[(fail foo)] = bar
|
|
Exception: foo
|
|
[tty]:1:25-32: var li = [foo]; set li[(fail foo)] = bar
|
|
~> var li = [foo]; set li[0 1] = foo bar
|
|
Exception: multi indexing not implemented
|
|
[tty]:1:21-27: var li = [foo]; set li[0 1] = foo bar
|
|
~> var li = [[]]; set li[1][2] = bar
|
|
Exception: out of range: index must be from 0 to 0, but is 1
|
|
[tty]:1:20-27: var li = [[]]; set li[1][2] = bar
|
|
|
|
## assignment to read-only var is a compile-time error ##
|
|
~> set nil = 1
|
|
Compilation error: variable $nil is read-only
|
|
[tty]:1:5-7: set nil = 1
|
|
~> var a b
|
|
set a true b = 1 2 3
|
|
Compilation error: variable $true is read-only
|
|
[tty]:2:7-10: set a true b = 1 2 3
|
|
~> set @true = 1
|
|
Compilation error: variable $true is read-only
|
|
[tty]:1:5-9: set @true = 1
|
|
~> var r
|
|
set true @r = 1
|
|
Compilation error: variable $true is read-only
|
|
[tty]:2:5-8: set true @r = 1
|
|
~> var r
|
|
set @r true = 1
|
|
Compilation error: variable $true is read-only
|
|
[tty]:2:8-11: set @r true = 1
|
|
|
|
// Error conditions already covered by tests for var above are not repeated.
|
|
|
|
## = is required ##
|
|
~> var x; set x
|
|
Compilation error: need = and right-hand-side
|
|
[tty]:1:13: var x; set x
|
|
|
|
//////////////////////
|
|
# error from Var.Set #
|
|
//////////////////////
|
|
|
|
//add-bad-var bad 0
|
|
|
|
~> set bad = foo
|
|
Exception: bad var
|
|
[tty]:1:5-7: set bad = foo
|
|
~> var a; set bad @a = foo
|
|
Exception: bad var
|
|
[tty]:1:12-14: var a; set bad @a = foo
|
|
~> var a; set a @bad = foo
|
|
Exception: bad var
|
|
[tty]:1:14-17: var a; set a @bad = foo
|
|
~> var a; set @a bad = foo
|
|
Exception: bad var
|
|
[tty]:1:15-17: var a; set @a bad = foo
|
|
|
|
///////
|
|
# tmp #
|
|
///////
|
|
|
|
~> var x = foo
|
|
put $x
|
|
{ tmp x = bar; put $x }
|
|
put $x
|
|
▶ foo
|
|
▶ bar
|
|
▶ foo
|
|
|
|
## use outside function ##
|
|
~> var x; tmp x = y
|
|
Compilation error: tmp may only be used inside a function
|
|
[tty]:1:8-16: var x; tmp x = y
|
|
|
|
## non-existent variable ##
|
|
~> { tmp x = y }
|
|
Compilation error: cannot find variable $x
|
|
[tty]:1:7-7: { tmp x = y }
|
|
|
|
## used on unset environment variable ##
|
|
//unset-env X
|
|
~> has-env X
|
|
{ tmp E:X = y; put $E:X }
|
|
has-env X
|
|
put $E:X
|
|
▶ $false
|
|
▶ y
|
|
▶ $false
|
|
▶ ''
|
|
|
|
## used on set environment variable ##
|
|
//unset-env X
|
|
~> set-env X x
|
|
{ tmp E:X = y; put $E:X }
|
|
get-env X
|
|
put $E:X
|
|
▶ y
|
|
▶ x
|
|
▶ x
|
|
|
|
## error setting ##
|
|
//add-bad-var bad 0
|
|
~> { tmp bad = foo }
|
|
Exception: bad var
|
|
[tty]:1:7-9: { tmp bad = foo }
|
|
[tty]:1:1-17: { tmp bad = foo }
|
|
|
|
# error restoring #
|
|
//add-bad-var bad 1
|
|
~> { tmp bad = foo; put after }
|
|
▶ after
|
|
Exception: restore variable: bad var
|
|
[tty]:1:7-9: { tmp bad = foo; put after }
|
|
[tty]:1:1-28: { tmp bad = foo; put after }
|
|
|
|
///////
|
|
# del #
|
|
///////
|
|
|
|
~> var x = 1
|
|
del x
|
|
|
|
## variable can't be used after deleted ##
|
|
~> var x = 1
|
|
del x
|
|
echo $x
|
|
Compilation error: variable $x not found
|
|
[tty]:3:6-7: echo $x
|
|
|
|
## deleting environment variable ##
|
|
//set-env TEST_ENV test_value
|
|
~> has-env TEST_ENV
|
|
del E:TEST_ENV
|
|
has-env TEST_ENV
|
|
▶ $true
|
|
▶ $false
|
|
|
|
## deleting variable whose name contains special characters ##
|
|
~> var 'a/b' = foo
|
|
del 'a/b'
|
|
|
|
## deleting element ##
|
|
~> var x = [&k=v &k2=v2]
|
|
del x[k2]
|
|
keys $x
|
|
▶ k
|
|
~> var x = [[&k=v &k2=v2]];
|
|
del x[0][k2]
|
|
keys $x[0]
|
|
▶ k
|
|
|
|
## deleting nonexistent variable ##
|
|
~> del x
|
|
Compilation error: no variable $x
|
|
[tty]:1:5-5: del x
|
|
|
|
## deleting element of nonexistent variable ##
|
|
~> del x[0]
|
|
Compilation error: no variable $x
|
|
[tty]:1:5-8: del x[0]
|
|
|
|
## deleting non-local variable ##
|
|
~> var a: = (ns [&b=$nil])
|
|
del a:b
|
|
Compilation error: only variables in the local scope or E: can be deleted
|
|
[tty]:2:5-7: del a:b
|
|
|
|
## variable name given with $ ##
|
|
~> var x = 1
|
|
del $x
|
|
Compilation error: arguments to del must omit the dollar sign
|
|
[tty]:2:5-6: del $x
|
|
|
|
## variable name not given as a single primary expression ##
|
|
~> var ab = 1
|
|
del a'b'
|
|
Compilation error: arguments to del must be variable or variable elements
|
|
[tty]:2:5-8: del a'b'
|
|
|
|
## variable name not a string ##
|
|
~> del [a]
|
|
Compilation error: arguments to del must be variable or variable elements
|
|
[tty]:1:5-7: del [a]
|
|
|
|
## variable name has sigil ##
|
|
~> var x = []; del @x
|
|
Compilation error: arguments to del must be variable or variable elements
|
|
[tty]:1:17-18: var x = []; del @x
|
|
|
|
## variable name not quoted when it should be ##
|
|
~> var 'a/b' = foo
|
|
del a/b
|
|
Compilation error: arguments to del must be variable or variable elements
|
|
[tty]:2:5-7: del a/b
|
|
|
|
## index is multiple values ##
|
|
~> var x = [&k1=v1 &k2=v2]
|
|
del x[k1 k2]
|
|
Exception: index must evaluate to a single value in argument to del
|
|
[tty]:2:7-11: del x[k1 k2]
|
|
|
|
## index expression throws ##
|
|
~> var x = [&k]
|
|
del x[(fail x)]
|
|
Exception: x
|
|
[tty]:2:8-13: del x[(fail x)]
|
|
|
|
## value does not support element removal ##
|
|
~> var x = (num 1)
|
|
del x[k]
|
|
Exception: value does not support element removal
|
|
[tty]:2:5-7: del x[k]
|
|
// TODO: Fix the stack trace so that it points to "x[k]" instead of "x[k"
|
|
|
|
## intermediate element does not exist ##
|
|
~> var x = [&]
|
|
del x[k][0]
|
|
Exception: no such key: k
|
|
[tty]:2:5-5: del x[k][0]
|
|
|
|
///////
|
|
# and #
|
|
///////
|
|
|
|
~> and $true $false
|
|
▶ $false
|
|
~> and a b
|
|
▶ b
|
|
~> and $false b
|
|
▶ $false
|
|
~> and $true b
|
|
▶ b
|
|
|
|
## short circuit ##
|
|
~> var x = a
|
|
and $false (x = b)
|
|
put $x
|
|
▶ $false
|
|
▶ a
|
|
|
|
## exception propagation ##
|
|
~> and a (fail x)
|
|
Exception: x
|
|
[tty]:1:8-13: and a (fail x)
|
|
|
|
## output error is bubbled ##
|
|
~> and a >&-
|
|
Exception: port does not support value output
|
|
[tty]:1:1-9: and a >&-
|
|
|
|
//////
|
|
# or #
|
|
//////
|
|
|
|
~> or $true $false
|
|
▶ $true
|
|
~> or a b
|
|
▶ a
|
|
~> or $false b
|
|
▶ b
|
|
~> or $true b
|
|
▶ $true
|
|
|
|
## short circuit ##
|
|
~> var x = a; or $true (x = b); put $x
|
|
▶ $true
|
|
▶ a
|
|
|
|
## exception ##
|
|
~> or $false (fail x)
|
|
Exception: x
|
|
[tty]:1:12-17: or $false (fail x)
|
|
|
|
## output error is bubbled ##
|
|
~> or a >&-
|
|
Exception: port does not support value output
|
|
[tty]:1:1-8: or a >&-
|
|
|
|
////////////
|
|
# coalesce #
|
|
////////////
|
|
|
|
~> coalesce a b
|
|
▶ a
|
|
~> coalesce $nil b
|
|
▶ b
|
|
~> coalesce $nil $nil
|
|
▶ $nil
|
|
~> coalesce
|
|
▶ $nil
|
|
|
|
## short circuit ##
|
|
~> coalesce a (fail foo)
|
|
▶ a
|
|
|
|
## exception propagation ##
|
|
~> coalesce $nil (fail foo)
|
|
Exception: foo
|
|
[tty]:1:16-23: coalesce $nil (fail foo)
|
|
|
|
## output error is bubbled ##
|
|
~> coalesce a >&-
|
|
Exception: port does not support value output
|
|
[tty]:1:1-14: coalesce a >&-
|
|
|
|
////////////////////////////////
|
|
# special forms require thunks #
|
|
////////////////////////////////
|
|
|
|
// Regression test for b.elv.sh/1456.
|
|
//
|
|
// This only tests "for"; the other special forms use the same utility under the
|
|
// hood and are not repeated.
|
|
|
|
~> for x [] {|arg| }
|
|
Compilation error: for body must not have arguments
|
|
[tty]:1:10-17: for x [] {|arg| }
|
|
~> for x [] {|&opt=val| }
|
|
Compilation error: for body must not have options
|
|
[tty]:1:10-22: for x [] {|&opt=val| }
|
|
|
|
//////
|
|
# if #
|
|
//////
|
|
|
|
~> if true { put then }
|
|
▶ then
|
|
~> if $false { put then } else { put else }
|
|
▶ else
|
|
~> if $false { put 1 } elif $false { put 2 } else { put 3 }
|
|
▶ 3
|
|
~> if $false { put 2 } elif true { put 2 } else { put 3 }
|
|
▶ 2
|
|
|
|
## exception in condition expression ##
|
|
~> if (fail x) { }
|
|
Exception: x
|
|
[tty]:1:5-10: if (fail x) { }
|
|
|
|
///////
|
|
# try #
|
|
///////
|
|
|
|
~> try { nop } catch { put bad } else { put good }
|
|
▶ good
|
|
~> try { fail tr } catch - { put bad } else { put good }
|
|
▶ bad
|
|
~> try { fail tr } finally { put final }
|
|
▶ final
|
|
Exception: tr
|
|
[tty]:1:7-14: try { fail tr } finally { put final }
|
|
~> try { fail tr } catch { fail ex } finally { put final }
|
|
▶ final
|
|
Exception: ex
|
|
[tty]:1:25-32: try { fail tr } catch { fail ex } finally { put final }
|
|
~> try { fail tr } catch { put ex } finally { fail final }
|
|
▶ ex
|
|
Exception: final
|
|
[tty]:1:44-54: try { fail tr } catch { put ex } finally { fail final }
|
|
~> try { fail tr } catch { fail ex } finally { fail final }
|
|
Exception: final
|
|
[tty]:1:45-55: try { fail tr } catch { fail ex } finally { fail final }
|
|
|
|
## must have catch or finally ##
|
|
~> try { fail tr }
|
|
Compilation error: try must be followed by a catch block or a finally block
|
|
[tty]:1:1-15: try { fail tr }
|
|
|
|
## rest variable not allowed ##
|
|
~> try { nop } catch @a { }
|
|
Compilation error: rest variable not allowed
|
|
[tty]:1:19-20: try { nop } catch @a { }
|
|
|
|
## readonly var as a target for the "catch" clause ##
|
|
~> try { fail reason } catch nil { }
|
|
Compilation error: variable $nil is read-only
|
|
[tty]:1:27-29: try { fail reason } catch nil { }
|
|
|
|
## quoted var name ##
|
|
~> try { fail hard } catch 'x=' { put $'x='[reason][type] }
|
|
▶ fail
|
|
|
|
## regression test: "try { } catch" is a syntax error, but it should not panic ##
|
|
~> try { } catch
|
|
Compilation error: need variable or body
|
|
[tty]:1:14: try { } catch
|
|
|
|
/////////
|
|
# while #
|
|
/////////
|
|
|
|
~> var x = (num 0)
|
|
while (< $x 4) { put $x; set x = (+ $x 1) }
|
|
▶ (num 0)
|
|
▶ (num 1)
|
|
▶ (num 2)
|
|
▶ (num 3)
|
|
|
|
## break ##
|
|
~> var x = (num 0)
|
|
while (< $x 4) { put $x; break }
|
|
▶ (num 0)
|
|
|
|
## continue ##
|
|
~> var x = (num 0)
|
|
while (< $x 4) { put $x; set x = (+ $x 1); continue; put bad }
|
|
▶ (num 0)
|
|
▶ (num 1)
|
|
▶ (num 2)
|
|
▶ (num 3)
|
|
|
|
## exception in body ##
|
|
~> var x = 0; while (< $x 4) { fail haha }
|
|
Exception: haha
|
|
[tty]:1:29-38: var x = 0; while (< $x 4) { fail haha }
|
|
|
|
## exception in condition ##
|
|
~> while (fail x) { }
|
|
Exception: x
|
|
[tty]:1:8-13: while (fail x) { }
|
|
|
|
## else branch - not taken ##
|
|
~> var x = 0; while (< $x 4) { put $x; set x = (+ $x 1) } else { put bad }
|
|
▶ 0
|
|
▶ (num 1)
|
|
▶ (num 2)
|
|
▶ (num 3)
|
|
|
|
## else branch - taken ##
|
|
~> while $false { put bad } else { put good }
|
|
▶ good
|
|
|
|
///////
|
|
# for #
|
|
///////
|
|
|
|
~> for x [tempora mores] { put 'O '$x }
|
|
▶ 'O tempora'
|
|
▶ 'O mores'
|
|
|
|
## break ##
|
|
~> for x [a] { break } else { put $x }
|
|
|
|
## else ##
|
|
~> for x [a] { put $x } else { put $x }
|
|
▶ a
|
|
|
|
## continue ##
|
|
~> for x [a b] { put $x; continue; put $x; }
|
|
▶ a
|
|
▶ b
|
|
|
|
## else ##
|
|
~> for x [] { } else { put else }
|
|
▶ else
|
|
~> for x [a] { } else { put else }
|
|
|
|
## propagating exception ##
|
|
~> for x [a] { fail foo }
|
|
Exception: foo
|
|
[tty]:1:13-21: for x [a] { fail foo }
|
|
|
|
## more than one iterator ##
|
|
~> for {x,y} [] { }
|
|
Compilation error: must be exactly one lvalue
|
|
[tty]:1:5-9: for {x,y} [] { }
|
|
|
|
## can't create new variable non-local variable ##
|
|
~> for no-such-namespace:x [a b] { }
|
|
Compilation error: cannot create variable $no-such-namespace:x; new variables can only be created in the current scope
|
|
[tty]:1:5-23: for no-such-namespace:x [a b] { }
|
|
|
|
## can't use non-existent variable ##
|
|
~> var a: = (ns [&])
|
|
for a:b [] { }
|
|
Exception: no variable $a:b
|
|
[tty]:2:5-7: for a:b [] { }
|
|
|
|
## exception when evaluating iterable ##
|
|
~> for x [][0] { }
|
|
Exception: out of range: index must be from 0 to -1, but is 0
|
|
[tty]:1:7-11: for x [][0] { }
|
|
|
|
## more than one iterable ##
|
|
~> for x (put a b) { }
|
|
Exception: arity mismatch: value being iterated must be 1 value, but is 2 values
|
|
[tty]:1:7-15: for x (put a b) { }
|
|
|
|
## non-iterable value ##
|
|
~> for x (num 0) { }
|
|
Exception: cannot iterate number
|
|
[tty]:1:1-17: for x (num 0) { }
|
|
|
|
//////
|
|
# fn #
|
|
//////
|
|
|
|
~> fn f {|x| put x=$x'.' }; f lorem; f ipsum
|
|
▶ 'x=lorem.'
|
|
▶ 'x=ipsum.'
|
|
|
|
## recursive functions with fn ##
|
|
// Regression test for b.elv.sh/1206.
|
|
~> fn f {|n| if (== $n 0) { num 1 } else { * $n (f (- $n 1)) } }; f 3
|
|
▶ (num 6)
|
|
|
|
## swallowing exception thrown by return ##
|
|
~> fn f { put a; return; put b }; f
|
|
▶ a
|
|
|
|
## error when evaluating the lambda ##
|
|
~> fn f {|&opt=(fail x)| }
|
|
Exception: x
|
|
[tty]:1:14-19: fn f {|&opt=(fail x)| }
|
|
|
|
///////
|
|
# use #
|
|
///////
|
|
|
|
## basic usage ##
|
|
//tmp-lib-dir
|
|
~> echo 'var name = ipsum' > $lib/lorem.elv
|
|
~> use lorem
|
|
put $lorem:name
|
|
▶ ipsum
|
|
|
|
## imports are lexically scoped ##
|
|
//tmp-lib-dir
|
|
~> echo 'var name = ipsum' > $lib/lorem.elv
|
|
~> { use lorem }
|
|
put $lorem:name
|
|
Compilation error: variable $lorem:name not found
|
|
[tty]:2:5-15: put $lorem:name
|
|
|
|
## prefers lib dir that appear earlier ##
|
|
//two-tmp-lib-dirs
|
|
~> echo 'echo lib1/shadow' > $lib1/shadow.elv
|
|
~> echo 'echo lib2/shadow' > $lib2/shadow.elv
|
|
~> use shadow
|
|
lib1/shadow
|
|
|
|
## use of imported variable is captured in upvalue ##
|
|
//tmp-lib-dir
|
|
~> echo 'var name = ipsum' > $lib/lorem.elv
|
|
~> use lorem
|
|
{ put $lorem:name }
|
|
▶ ipsum
|
|
|
|
## use of imported function is also captured in upvalue ##
|
|
//tmp-lib-dir
|
|
~> echo 'var name = ipsum; fn put-name { put $name }' > $lib/lorem.elv
|
|
~> { use lorem; { lorem:put-name } }
|
|
▶ ipsum
|
|
|
|
## use of module in subdirectory ##
|
|
//tmp-lib-dir
|
|
// TODO: Use os:mkdir-all when it's available.
|
|
~> use os
|
|
os:mkdir $lib/a
|
|
os:mkdir $lib/a/b
|
|
echo 'var name = a/b/c' > $lib/a/b/c.elv
|
|
~> use a/b/c
|
|
put $c:name
|
|
▶ a/b/c
|
|
|
|
## module is cached after first use ##
|
|
//tmp-lib-dir
|
|
~> echo 'put has-init' > $lib/has-init.elv
|
|
~> use has-init
|
|
▶ has-init
|
|
~> use has-init
|
|
// Init code is not run again
|
|
|
|
## renaming module ##
|
|
//tmp-lib-dir
|
|
// TODO: Use os:mkdir-all when it's available.
|
|
~> use os
|
|
os:mkdir $lib/a
|
|
os:mkdir $lib/a/b
|
|
echo 'var name = a/b/c' > $lib/a/b/c.elv
|
|
~> use a/b/c mod
|
|
put $mod:name
|
|
▶ a/b/c
|
|
|
|
## modules can be used multiple times with different aliases ##
|
|
//tmp-lib-dir
|
|
~> echo 'var name = ipsum' > $lib/lorem.elv
|
|
~> use lorem
|
|
use lorem lorem2
|
|
put $lorem:name $lorem2:name
|
|
▶ ipsum
|
|
▶ ipsum
|
|
|
|
## variable referencing a module can be shadowed ##
|
|
//tmp-lib-dir
|
|
// TODO: Use os:mkdir-all when it's available.
|
|
~> use os
|
|
os:mkdir $lib/a
|
|
os:mkdir $lib/a/b
|
|
echo 'var name = c' > $lib/c.elv
|
|
echo 'var name = a/b/c' > $lib/a/b/c.elv
|
|
~> use c
|
|
put $c:name
|
|
use a/b/c
|
|
put $c:name
|
|
▶ c
|
|
▶ a/b/c
|
|
|
|
## relative uses ##
|
|
//tmp-lib-dir
|
|
~> use os
|
|
os:mkdir $lib/a
|
|
os:mkdir $lib/a/b
|
|
echo 'var name = ipsum' > $lib/lorem.elv
|
|
echo 'var name = a/b/c' > $lib/a/b/c.elv
|
|
echo 'use ./c; var c = $c:name; use ../../lorem; var lorem = $lorem:name' > $lib/a/b/x.elv
|
|
~> use a/b/x; put $x:c $x:lorem
|
|
▶ a/b/c
|
|
▶ ipsum
|
|
|
|
## relative uses from the REPL ##
|
|
// Relative uses from the REPL is relative to the working directory.
|
|
//in-temp-dir
|
|
~> echo 'var name = ipsum' > lorem.elv
|
|
~> use ./lorem
|
|
put $lorem:name
|
|
▶ ipsum
|
|
|
|
## variables in the REPL scope is invisible from modules ##
|
|
//tmp-lib-dir
|
|
~> echo 'put $x' > $lib/put-x.elv
|
|
// We have to do this since the exception stack trace contains $lib, which is a
|
|
// temporary directory that changes across runs.
|
|
//
|
|
// TODO: Print the whole error message (but without the filename) when
|
|
// exceptions support that level of introspection.
|
|
~> try {
|
|
use put-x
|
|
} catch e {
|
|
echo has exception
|
|
}
|
|
has exception
|
|
|
|
## invalid UTF-8 in module file ##
|
|
//tmp-lib-dir
|
|
~> echo "\xff" > $lib/invalid-utf8.elv
|
|
// We have to do this since the exception stack trace contains $lib, which is a
|
|
// temporary directory that changes across runs.
|
|
//
|
|
// TODO: Print the whole error message (but without the filename) when
|
|
// exceptions support that level of introspection.
|
|
~> try {
|
|
use invalid-utf8
|
|
} catch e {
|
|
echo has exception
|
|
}
|
|
has exception
|
|
|
|
## unknown module spec ##
|
|
~> use unknown
|
|
Exception: no such module: unknown
|
|
[tty]:1:1-11: use unknown
|
|
~> use ./unknown
|
|
Exception: no such module: ./unknown
|
|
[tty]:1:1-13: use ./unknown
|
|
~> use ../unknown
|
|
Exception: no such module: ../unknown
|
|
[tty]:1:1-14: use ../unknown
|
|
|
|
## wrong number of arguments ##
|
|
~> use
|
|
Compilation error: need module spec
|
|
[tty]:1:4: use
|
|
~> use a b c
|
|
Compilation error: superfluous arguments
|
|
[tty]:1:9-9: use a b c
|
|
|
|
## circular dependency ##
|
|
//tmp-lib-dir
|
|
~> echo 'var pre = apre; use b; put $b:pre $b:post; var post = apost' > $lib/a.elv
|
|
echo "var pre = bpre; use a; put $a:pre $a:post; var post = bpost" > $lib/b.elv
|
|
~> use a
|
|
▶ apre
|
|
▶ $nil
|
|
▶ bpre
|
|
▶ bpost
|
|
|
|
## importing module triggers check for deprecated features ##
|
|
// Regression test for b.elv.sh/1072
|
|
//tmp-lib-dir
|
|
~> echo 'a=b nop $a' > $lib/dep.elv
|
|
// Only show the first line to avoid showing the file path, which contains $lib
|
|
// and changes across runs.
|
|
~> use dep 2>&1 | take 1 | to-lines
|
|
Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
|
|
|
|
## module may mutate REPL namespace ##
|
|
// Regression test for b.elv.sh/1225
|
|
//tmp-lib-dir
|
|
//add-var-in-builtin
|
|
~> echo 'var foo = bar; add-var foo $foo' > $lib/a.elv
|
|
~> use a
|
|
~> keys $a:
|
|
▶ foo
|
|
~> put $foo
|
|
▶ bar
|