pkg/eval: Move implementation of compile-time deprecation to compiler.go.

This commit is contained in:
Qi Xiao 2021-01-19 23:17:56 +00:00
parent 47d9766f5c
commit fbfbef8531
4 changed files with 89 additions and 72 deletions

View File

@ -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(""))
}
}

38
pkg/eval/compiler_test.go Normal file
View File

@ -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)
}
}

View File

@ -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"),

View File

@ -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)
}