diff --git a/pkg/eval/compiler.go b/pkg/eval/compiler.go index 5489ef42..e0e273ea 100644 --- a/pkg/eval/compiler.go +++ b/pkg/eval/compiler.go @@ -7,6 +7,7 @@ import ( "github.com/elves/elvish/pkg/diag" "github.com/elves/elvish/pkg/eval/vars" "github.com/elves/elvish/pkg/parse" + "github.com/elves/elvish/pkg/prog" ) // compiler maintains the set of states needed when compiling a single source @@ -124,3 +125,53 @@ func (cp *compiler) popScope() { cp.captures[len(cp.captures)-1] = nil cp.captures = cp.captures[:len(cp.captures)-1] } + +func (cp *compiler) checkDeprecatedBuiltin(name string, r diag.Ranger) { + msg := "" + minLevel := 15 + switch name { + case "-source~": + msg = `the "source" command is deprecated; use "eval" instead` + case "ord~": + msg = `the "ord" command is deprecated; use "str:to-codepoints" instead` + case "chr~": + msg = `the "chr" command is deprecated; use "str:from-codepoints" instead` + case "has-prefix~": + msg = `the "has-prefix" command is deprecated; use "str:has-prefix" instead` + case "has-suffix~": + msg = `the "has-suffix" command is deprecated; use "str:has-suffix" instead` + case "esleep~": + msg = `the "esleep" command is deprecated; use "sleep" instead` + case "eval-symlinks~": + msg = `the "eval-symlinks" command is deprecated; use "path:eval-symlinks" instead` + case "path-abs~": + msg = `the "path-abs" command is deprecated; use "path:abs" instead` + case "path-base~": + msg = `the "path-base" command is deprecated; use "path:base" instead` + case "path-clean~": + msg = `the "path-clean" command is deprecated; use "path:clean" instead` + case "path-dir~": + msg = `the "path-dir" command is deprecated; use "path:dir" instead` + case "path-ext~": + msg = `the "path-ext" command is deprecated; use "path:ext" instead` + case "-is-dir~": + msg = `the "-is-dir" command is deprecated; use "path:is-dir" instead` + default: + return + } + cp.deprecate(r, msg, minLevel) +} + +func (cp *compiler) deprecate(r diag.Ranger, msg string, minLevel int) { + if cp.warn == nil || r == nil { + return + } + dep := deprecation{cp.srcMeta.Name, r.Range(), msg} + if prog.DeprecationLevel >= minLevel && cp.deprecations.register(dep) { + err := diag.Error{ + Type: "deprecation", Message: msg, + Context: diag.Context{ + Name: cp.srcMeta.Name, Source: cp.srcMeta.Code, Ranging: r.Range()}} + fmt.Fprintln(cp.warn, err.Show("")) + } +} diff --git a/pkg/eval/compiler_test.go b/pkg/eval/compiler_test.go new file mode 100644 index 00000000..7ef1df84 --- /dev/null +++ b/pkg/eval/compiler_test.go @@ -0,0 +1,38 @@ +package eval_test + +import ( + "bytes" + "strings" + "testing" + + . "github.com/elves/elvish/pkg/eval" + "github.com/elves/elvish/pkg/parse" + "github.com/elves/elvish/pkg/prog" +) + +func TestDeprecatedBuiltin(t *testing.T) { + testCompileTimeDeprecation(t, "ord a", `the "ord" command is deprecated`, 15) + // Deprecations of other builtins are implemented in the same way, so we + // don't test them repeatedly +} + +func testCompileTimeDeprecation(t *testing.T, code, wantWarning string, level int) { + restore := prog.SetDeprecationLevel(level) + defer restore() + + ev := NewEvaler() + errOutput := new(bytes.Buffer) + + parseErr, compileErr := ev.Check(parse.Source{Code: code}, errOutput) + if parseErr != nil { + t.Errorf("got parse err %v", parseErr) + } + if compileErr != nil { + t.Errorf("got compile err %v", compileErr) + } + + warning := errOutput.String() + if !strings.Contains(warning, wantWarning) { + t.Errorf("got warning %q, want warning containing %q", warning, wantWarning) + } +} diff --git a/pkg/eval/eval_test.go b/pkg/eval/eval_test.go index 1e6d13d1..f27ae122 100644 --- a/pkg/eval/eval_test.go +++ b/pkg/eval/eval_test.go @@ -1,9 +1,7 @@ package eval_test import ( - "bytes" "strconv" - "strings" "sync" "syscall" "testing" @@ -57,28 +55,6 @@ func TestEvalTimeDeprecate(t *testing.T) { ) } -func TestCompileTimeDeprecation(t *testing.T) { - restore := prog.SetDeprecationLevel(15) - defer restore() - - ev := NewEvaler() - errOutput := new(bytes.Buffer) - - parseErr, compileErr := ev.Check(parse.Source{Code: "ord a"}, errOutput) - if parseErr != nil { - t.Errorf("got parse err %v", parseErr) - } - if compileErr != nil { - t.Errorf("got compile err %v", compileErr) - } - - warning := errOutput.String() - wantWarning := `the "ord" command is deprecated` - if !strings.Contains(warning, wantWarning) { - t.Errorf("got warning %q, want warning containing %q", warning, wantWarning) - } -} - func TestMultipleEval(t *testing.T) { Test(t, That("x = hello").Then("put $x").Puts("hello"), diff --git a/pkg/eval/var_ref.go b/pkg/eval/var_ref.go index 4d856a92..a74bd7f0 100644 --- a/pkg/eval/var_ref.go +++ b/pkg/eval/var_ref.go @@ -1,12 +1,10 @@ package eval import ( - "fmt" "strings" "github.com/elves/elvish/pkg/diag" "github.com/elves/elvish/pkg/eval/vars" - "github.com/elves/elvish/pkg/prog" ) // This file implements variable resolution. Elvish has fully static lexical @@ -187,52 +185,6 @@ func (cp *compiler) searchBuiltin(k string, r diag.Ranger) int { return index } -func (cp *compiler) checkDeprecatedBuiltin(name string, r diag.Ranger) { - if cp.warn == nil || r == nil { - return - } - msg := "" - minLevel := 15 - switch name { - case "-source~": - msg = `the "source" command is deprecated; use "eval" instead` - case "ord~": - msg = `the "ord" command is deprecated; use "str:to-codepoints" instead` - case "chr~": - msg = `the "chr" command is deprecated; use "str:from-codepoints" instead` - case "has-prefix~": - msg = `the "has-prefix" command is deprecated; use "str:has-prefix" instead` - case "has-suffix~": - msg = `the "has-suffix" command is deprecated; use "str:has-suffix" instead` - case "esleep~": - msg = `the "esleep" command is deprecated; use "sleep" instead` - case "eval-symlinks~": - msg = `the "eval-symlinks" command is deprecated; use "path:eval-symlinks" instead` - case "path-abs~": - msg = `the "path-abs" command is deprecated; use "path:abs" instead` - case "path-base~": - msg = `the "path-base" command is deprecated; use "path:base" instead` - case "path-clean~": - msg = `the "path-clean" command is deprecated; use "path:clean" instead` - case "path-dir~": - msg = `the "path-dir" command is deprecated; use "path:dir" instead` - case "path-ext~": - msg = `the "path-ext" command is deprecated; use "path:ext" instead` - case "-is-dir~": - msg = `the "-is-dir" command is deprecated; use "path:is-dir" instead` - default: - return - } - dep := deprecation{cp.srcMeta.Name, r.Range(), msg} - if prog.DeprecationLevel >= minLevel && cp.deprecations.register(dep) { - err := diag.Error{ - Type: "deprecation", Message: msg, - Context: diag.Context{ - Name: cp.srcMeta.Name, Source: cp.srcMeta.Code, Ranging: r.Range()}} - fmt.Fprintln(cp.warn, err.Show("")) - } -} - func (fm *Frame) searchLocal(k string) int { return fm.local.lookup(k) }