diff --git a/pkg/eval/builtin_special_test.go b/pkg/eval/builtin_special_test.go index 772ac6dd..fdab0ce4 100644 --- a/pkg/eval/builtin_special_test.go +++ b/pkg/eval/builtin_special_test.go @@ -56,8 +56,6 @@ func TestVar(t *testing.T) { // Shadowing. That("var x = old; fn f { put $x }", "var x = new; put $x; f"). Puts("new", "old"), - // Explicit local: is allowed - That("var local:x = foo", "put $x").Puts("foo"), // Concurrently creating a new variable and accessing existing variable. // Run with "go test -race". diff --git a/pkg/eval/compile_effect_test.go b/pkg/eval/compile_effect_test.go index 6c74a92a..ff251369 100644 --- a/pkg/eval/compile_effect_test.go +++ b/pkg/eval/compile_effect_test.go @@ -174,16 +174,6 @@ func TestCommand_LegacyTemporaryAssignmentSyntaxIsDeprecated(t *testing.T) { "the legacy temporary assignment syntax is deprecated", 18) } -func TestCommand_DeprecatedSpecialNamespacesInAssignment(t *testing.T) { - testCompileTimeDeprecation(t, "var local:a = foo", "the local: special namespace is deprecated", 17) - testCompileTimeDeprecation(t, "var a; set local:a = foo", "the local: special namespace is deprecated", 17) - - testCompileTimeDeprecation(t, "var a; { set up:a = foo }", "the up: special namespace is deprecated", 17) - - testCompileTimeDeprecation(t, "var :a = foo", "the empty namespace is deprecated", 17) - testCompileTimeDeprecation(t, "var a; { set :a = foo }", "the empty namespace is deprecated", 17) -} - func TestCommand_Redir(t *testing.T) { setup := func(ev *Evaler) { ev.ExtendGlobal(BuildNs().AddNs("file", file.Ns)) diff --git a/pkg/eval/compile_lvalue.go b/pkg/eval/compile_lvalue.go index d937fd7d..91bef567 100644 --- a/pkg/eval/compile_lvalue.go +++ b/pkg/eval/compile_lvalue.go @@ -87,16 +87,6 @@ func (cp *compiler) parseIndexingLValue(n *parse.Indexing, f lvalueFlag) lvalues name := segs[0] ref = &varRef{localScope, staticVarInfo{name, false, false}, cp.thisScope().add(name), nil} - } else if len(segs) == 2 && (segs[0] == "local:" || segs[0] == ":") { - if segs[0] == "local:" { - cp.deprecate(n, "the local: special namespace is deprecated; use the variable directly", 17) - } else { - cp.deprecate(n, "the empty namespace is deprecated; use the variable directly", 17) - } - name := segs[1] - // Qualified local name - ref = &varRef{localScope, - staticVarInfo{name, false, false}, cp.thisScope().add(name), nil} } else { cp.errorpf(n, "cannot create variable $%s; new variables can only be created in the local scope", qname) } diff --git a/pkg/eval/compile_value_test.go b/pkg/eval/compile_value_test.go index a56989e9..04fc6c39 100644 --- a/pkg/eval/compile_value_test.go +++ b/pkg/eval/compile_value_test.go @@ -135,20 +135,15 @@ func TestVariableUse(t *testing.T) { // Variable namespace // ------------------ - // Pseudo-namespace local: accesses the local scope. - That("var x = outer; { var local:x = inner; put $local:x }").Puts("inner"), - // Pseudo-namespace up: accesses upvalues. - That("var x = outer; { var local:x = inner; put $up:x }").Puts("outer"), - // Unqualified name prefers local: to up:. - That("var x = outer; { var local:x = inner; put $x }").Puts("inner"), + // Unqualified name resolves to local name before upvalue. + That("var x = outer; { var x = inner; put $x }").Puts("inner"), // Unqualified name resolves to upvalue if no local name exists. That("var x = outer; { put $x }").Puts("outer"), // Unqualified name resolves to builtin if no local name or upvalue // exists. That("put $true").Puts(true), - // A name can be explicitly unqualified by having a leading colon. - That("var x = val; put $:x").Puts("val"), - That("put $:true").Puts(true), + // Names like $:foo are reserved for now. + That("var x = val; put $:x").DoesNotCompile(), // Pseudo-namespace E: provides read-write access to environment // variables. Colons inside the name are supported. @@ -165,24 +160,9 @@ func TestVariableUse(t *testing.T) { That("var ns: = (ns [&a= val]); put $ns:a").Puts("val"), // Multi-level namespace access is supported. That("var ns: = (ns [&a:= (ns [&b= val])]); put $ns:a:b").Puts("val"), - // Multi-level namespace access can have a leading colon to signal that - // the first component is unqualified. - That("var ns: = (ns [&a:= (ns [&b= val])]); put $:ns:a:b").Puts("val"), - // Multi-level namespace access can be combined with the local: - // pseudo-namespaces. - That("var ns: = (ns [&a:= (ns [&b= val])]); put $local:ns:a:b").Puts("val"), - // Multi-level namespace access can be combined with the up: - // pseudo-namespaces. - That("var ns: = (ns [&a:= (ns [&b= val])]); { put $up:ns:a:b }").Puts("val"), ) } -func TestVariableUse_DeprecatedSpecialNamespaces(t *testing.T) { - testCompileTimeDeprecation(t, "var a; put $local:a", "the local: special namespace is deprecated", 17) - testCompileTimeDeprecation(t, "var a; { put $up:a }", "the up: special namespace is deprecated", 17) - testCompileTimeDeprecation(t, "var a; { put $:a }", "the empty namespace is deprecated", 17) -} - func TestClosure(t *testing.T) { Test(t, That("{|| }").DoesNothing(), diff --git a/pkg/eval/var_ref.go b/pkg/eval/var_ref.go index 233ff377..542c39d2 100644 --- a/pkg/eval/var_ref.go +++ b/pkg/eval/var_ref.go @@ -52,10 +52,8 @@ type scopeSearcher interface { // Resolves a qname into a varRef. func resolveVarRef(s scopeSearcher, qname string, r diag.Ranger) *varRef { if strings.HasPrefix(qname, ":") { - qname = qname[1:] - if cp, ok := s.(*compiler); ok { - cp.deprecate(r, "the empty namespace is deprecated; use the variable directly instead", 17) - } + // $:foo is reserved for fully-qualified names in future + return nil } if ref := resolveVarRefLocal(s, qname); ref != nil { return ref @@ -90,16 +88,6 @@ func resolveVarRefBuiltin(s scopeSearcher, qname string, r diag.Ranger) *varRef if rest != "" { // Try special namespace first. switch first { - case "local:": - if cp, ok := s.(*compiler); ok { - cp.deprecate(r, "the local: special namespace is deprecated; use the variable directly instead", 17) - } - return resolveVarRefLocal(s, rest) - case "up:": - if cp, ok := s.(*compiler); ok { - cp.deprecate(r, "the up: special namespace is deprecated; use the variable directly if it is not shadowed", 17) - } - return resolveVarRefCapture(s, rest) case "e:": if strings.HasSuffix(rest, FnSuffix) { return &varRef{scope: externalScope, subNames: []string{rest[:len(rest)-1]}}