Remove support for the "local:", "up:" and ":" special namespaces.

This fixes #1409.
This commit is contained in:
Qi Xiao 2022-01-03 00:37:28 +00:00
parent 3dd3b780b9
commit be1e144b45
5 changed files with 6 additions and 60 deletions

View File

@ -56,8 +56,6 @@ func TestVar(t *testing.T) {
// Shadowing. // Shadowing.
That("var x = old; fn f { put $x }", "var x = new; put $x; f"). That("var x = old; fn f { put $x }", "var x = new; put $x; f").
Puts("new", "old"), 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. // Concurrently creating a new variable and accessing existing variable.
// Run with "go test -race". // Run with "go test -race".

View File

@ -174,16 +174,6 @@ func TestCommand_LegacyTemporaryAssignmentSyntaxIsDeprecated(t *testing.T) {
"the legacy temporary assignment syntax is deprecated", 18) "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) { func TestCommand_Redir(t *testing.T) {
setup := func(ev *Evaler) { setup := func(ev *Evaler) {
ev.ExtendGlobal(BuildNs().AddNs("file", file.Ns)) ev.ExtendGlobal(BuildNs().AddNs("file", file.Ns))

View File

@ -87,16 +87,6 @@ func (cp *compiler) parseIndexingLValue(n *parse.Indexing, f lvalueFlag) lvalues
name := segs[0] name := segs[0]
ref = &varRef{localScope, ref = &varRef{localScope,
staticVarInfo{name, false, false}, cp.thisScope().add(name), nil} 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 { } else {
cp.errorpf(n, "cannot create variable $%s; new variables can only be created in the local scope", qname) cp.errorpf(n, "cannot create variable $%s; new variables can only be created in the local scope", qname)
} }

View File

@ -135,20 +135,15 @@ func TestVariableUse(t *testing.T) {
// Variable namespace // Variable namespace
// ------------------ // ------------------
// Pseudo-namespace local: accesses the local scope. // Unqualified name resolves to local name before upvalue.
That("var x = outer; { var local:x = inner; put $local:x }").Puts("inner"), That("var x = outer; { var x = inner; put $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 upvalue if no local name exists. // Unqualified name resolves to upvalue if no local name exists.
That("var x = outer; { put $x }").Puts("outer"), That("var x = outer; { put $x }").Puts("outer"),
// Unqualified name resolves to builtin if no local name or upvalue // Unqualified name resolves to builtin if no local name or upvalue
// exists. // exists.
That("put $true").Puts(true), That("put $true").Puts(true),
// A name can be explicitly unqualified by having a leading colon. // Names like $:foo are reserved for now.
That("var x = val; put $:x").Puts("val"), That("var x = val; put $:x").DoesNotCompile(),
That("put $:true").Puts(true),
// Pseudo-namespace E: provides read-write access to environment // Pseudo-namespace E: provides read-write access to environment
// variables. Colons inside the name are supported. // 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"), That("var ns: = (ns [&a= val]); put $ns:a").Puts("val"),
// Multi-level namespace access is supported. // Multi-level namespace access is supported.
That("var ns: = (ns [&a:= (ns [&b= val])]); put $ns:a:b").Puts("val"), 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) { func TestClosure(t *testing.T) {
Test(t, Test(t,
That("{|| }").DoesNothing(), That("{|| }").DoesNothing(),

View File

@ -52,10 +52,8 @@ type scopeSearcher interface {
// Resolves a qname into a varRef. // Resolves a qname into a varRef.
func resolveVarRef(s scopeSearcher, qname string, r diag.Ranger) *varRef { func resolveVarRef(s scopeSearcher, qname string, r diag.Ranger) *varRef {
if strings.HasPrefix(qname, ":") { if strings.HasPrefix(qname, ":") {
qname = qname[1:] // $:foo is reserved for fully-qualified names in future
if cp, ok := s.(*compiler); ok { return nil
cp.deprecate(r, "the empty namespace is deprecated; use the variable directly instead", 17)
}
} }
if ref := resolveVarRefLocal(s, qname); ref != nil { if ref := resolveVarRefLocal(s, qname); ref != nil {
return ref return ref
@ -90,16 +88,6 @@ func resolveVarRefBuiltin(s scopeSearcher, qname string, r diag.Ranger) *varRef
if rest != "" { if rest != "" {
// Try special namespace first. // Try special namespace first.
switch 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:": case "e:":
if strings.HasSuffix(rest, FnSuffix) { if strings.HasSuffix(rest, FnSuffix) {
return &varRef{scope: externalScope, subNames: []string{rest[:len(rest)-1]}} return &varRef{scope: externalScope, subNames: []string{rest[:len(rest)-1]}}