mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-12 17:27:50 +08:00
combine Error and error into an error in eval functions
This commit is contained in:
parent
c2507ad73b
commit
c1b7701a68
53
eval/eval.go
53
eval/eval.go
|
@ -70,8 +70,8 @@ func NewEvaler(st *store.Store) *Evaler {
|
|||
return &Evaler{global, map[string]ns{}, searchPaths, st, nil}
|
||||
}
|
||||
|
||||
func pprintError(e Error) {
|
||||
switch e := e.inner.(type) {
|
||||
func PprintError(e error) {
|
||||
switch e := e.(type) {
|
||||
case nil:
|
||||
fmt.Print("\033[32mok\033[m")
|
||||
case multiError:
|
||||
|
@ -80,7 +80,7 @@ func pprintError(e Error) {
|
|||
if i > 0 {
|
||||
fmt.Print(" | ")
|
||||
}
|
||||
pprintError(c)
|
||||
PprintError(c.inner)
|
||||
}
|
||||
fmt.Print(")")
|
||||
case flow:
|
||||
|
@ -90,15 +90,6 @@ func pprintError(e Error) {
|
|||
}
|
||||
}
|
||||
|
||||
func PprintBadError(ex Error) {
|
||||
if ex.Bool() {
|
||||
return
|
||||
}
|
||||
fmt.Print("⤇ ")
|
||||
pprintError(ex)
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
const (
|
||||
outChanSize = 32
|
||||
outChanLeader = "▶ "
|
||||
|
@ -169,36 +160,36 @@ func makeScope(s ns) scope {
|
|||
|
||||
// Eval evaluates a chunk node n. The supplied name and text are used in
|
||||
// diagnostic messages.
|
||||
func (ev *Evaler) Eval(name, text string, n *parse.Chunk) (Error, error) {
|
||||
func (ev *Evaler) Eval(name, text string, n *parse.Chunk) error {
|
||||
return ev.evalWithOut(name, text, n, nil)
|
||||
}
|
||||
|
||||
func (ev *Evaler) evalWithOut(name, text string, n *parse.Chunk, out *port) (Error, error) {
|
||||
func (ev *Evaler) evalWithOut(name, text string, n *parse.Chunk, out *port) error {
|
||||
op, err := compile(name, text, makeScope(ev.global), n)
|
||||
if err != nil {
|
||||
return GenericFailure, err
|
||||
return err
|
||||
}
|
||||
|
||||
ec, outdone := newTopEvalCtx(ev, name, text)
|
||||
if out != nil {
|
||||
outdone = nil
|
||||
ec.ports[1] = out
|
||||
}
|
||||
ex, err := ec.eval(op)
|
||||
if err == nil && outdone != nil {
|
||||
// XXX maybe the out channel is always closed regardless of the error? need some checking
|
||||
ex := ec.peval(op)
|
||||
ec.closePorts()
|
||||
if outdone != nil {
|
||||
<-outdone
|
||||
}
|
||||
return ex, err
|
||||
|
||||
return ex.inner
|
||||
}
|
||||
|
||||
// eval evaluates an Op.
|
||||
func (ec *evalCtx) eval(op exitusOp) (ex Error, err error) {
|
||||
if op == nil {
|
||||
return OK, nil
|
||||
}
|
||||
defer ec.closePorts()
|
||||
defer errutil.Catch(&err)
|
||||
return op(ec), nil
|
||||
// peval evaluates an exitusOp in a protected environment so that calls to
|
||||
// errorf are wrapped in an Error.
|
||||
func (ec *evalCtx) peval(op exitusOp) (ex Error) {
|
||||
// defer ec.closePorts()
|
||||
defer errutil.Catch(&ex.inner)
|
||||
return op(ec)
|
||||
}
|
||||
|
||||
// errorf stops the ec.eval immediately by panicking with a diagnostic message.
|
||||
|
@ -223,10 +214,10 @@ func (ec *evalCtx) mustSingleString(vs []Value, what string, p int) String {
|
|||
}
|
||||
|
||||
// SourceText evaluates a chunk of elvish source.
|
||||
func (ev *Evaler) SourceText(name, src, dir string) (Error, error) {
|
||||
func (ev *Evaler) SourceText(name, src, dir string) error {
|
||||
n, err := parse.Parse(name, src)
|
||||
if err != nil {
|
||||
return GenericFailure, err
|
||||
return err
|
||||
}
|
||||
return ev.Eval(name, src, n)
|
||||
}
|
||||
|
@ -243,10 +234,10 @@ func readFileUTF8(fname string) (string, error) {
|
|||
}
|
||||
|
||||
// Source evaluates the content of a file.
|
||||
func (ev *Evaler) Source(fname string) (Error, error) {
|
||||
func (ev *Evaler) Source(fname string) error {
|
||||
src, err := readFileUTF8(fname)
|
||||
if err != nil {
|
||||
return GenericFailure, err
|
||||
return err
|
||||
}
|
||||
return ev.SourceText(fname, src, path.Dir(fname))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eval
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
@ -26,10 +27,11 @@ func strs(ss ...string) []Value {
|
|||
return vs
|
||||
}
|
||||
|
||||
var anyerror = errors.New("")
|
||||
|
||||
type more struct {
|
||||
wantBytesOut []byte
|
||||
wantExit Error
|
||||
wantError bool
|
||||
wantError error
|
||||
}
|
||||
|
||||
var nomore more
|
||||
|
@ -45,7 +47,7 @@ var evalTests = []struct {
|
|||
// Outputs of pipelines in a chunk are concatenated
|
||||
{"put x; put y; put z", strs("x", "y", "z"), nomore},
|
||||
// A failed pipeline cause the whole chunk to fail
|
||||
{"put a; false; put b", strs("a"), more{wantExit: NewFailure("1")}},
|
||||
{"put a; false; put b", strs("a"), more{wantError: errors.New("1")}},
|
||||
|
||||
// Pipelines
|
||||
// Pure byte pipeline
|
||||
|
@ -142,7 +144,7 @@ func mustParse(t *testing.T, name, text string) *parse.Chunk {
|
|||
return n
|
||||
}
|
||||
|
||||
func evalAndCollect(t *testing.T, texts []string, chsize int) ([]Value, []byte, Error, error) {
|
||||
func evalAndCollect(t *testing.T, texts []string, chsize int) ([]Value, []byte, error) {
|
||||
name := "<eval test>"
|
||||
ev := NewEvaler(nil)
|
||||
|
||||
|
@ -166,7 +168,7 @@ func evalAndCollect(t *testing.T, texts []string, chsize int) ([]Value, []byte,
|
|||
outs := []Value{}
|
||||
|
||||
// Exit. Only the exit of the last text is saved.
|
||||
var ex Error
|
||||
var ex error
|
||||
|
||||
for _, text := range texts {
|
||||
n := mustParse(t, name, text)
|
||||
|
@ -180,21 +182,19 @@ func evalAndCollect(t *testing.T, texts []string, chsize int) ([]Value, []byte,
|
|||
exhausted <- struct{}{}
|
||||
}()
|
||||
|
||||
var err error
|
||||
ex, err = ev.evalWithOut(name, text, n, &port{ch: out, closeCh: true, f: pw})
|
||||
if err != nil {
|
||||
return outs, outBytes, ex, err
|
||||
}
|
||||
ex = ev.evalWithOut(name, text, n, &port{ch: out, closeCh: true, f: pw})
|
||||
<-exhausted
|
||||
}
|
||||
pw.Close()
|
||||
<-bytesExhausted
|
||||
return outs, outBytes, ex, nil
|
||||
return outs, outBytes, ex
|
||||
}
|
||||
|
||||
func TestEval(t *testing.T) {
|
||||
for _, tt := range evalTests {
|
||||
out, bytesOut, ex, err := evalAndCollect(t, []string{tt.text}, len(tt.wantOut))
|
||||
// fmt.Printf("eval %q\n", tt.text)
|
||||
|
||||
out, bytesOut, err := evalAndCollect(t, []string{tt.text}, len(tt.wantOut))
|
||||
|
||||
good := true
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
|
@ -205,21 +205,11 @@ func TestEval(t *testing.T) {
|
|||
t.Errorf(format, args...)
|
||||
}
|
||||
|
||||
if tt.wantError != (err != nil) {
|
||||
wantError := "nil"
|
||||
if tt.wantError {
|
||||
wantError = "non-nil"
|
||||
}
|
||||
errorf("got err=%v, want %s", err, wantError)
|
||||
}
|
||||
if tt.wantBytesOut != nil && !reflect.DeepEqual(tt.wantBytesOut, bytesOut) {
|
||||
errorf("got bytesOut=%q, want %q", bytesOut, tt.wantBytesOut)
|
||||
}
|
||||
if tt.wantExit != OK && !reflect.DeepEqual(tt.wantExit, ex) {
|
||||
errorf("got exitus=%v, want %v", ex, tt.wantExit)
|
||||
}
|
||||
if tt.wantExit == OK && !ex.Bool() {
|
||||
errorf("got exitus=%v, want all ok", ex)
|
||||
if !(tt.wantError == anyerror && err != nil) && !reflect.DeepEqual(tt.wantError, err) {
|
||||
errorf("got err=%v, want %v", err, tt.wantError)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.wantOut, out) {
|
||||
errorf("got out=%v, want %v", out, tt.wantOut)
|
||||
|
@ -231,7 +221,7 @@ func TestEval(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMultipleEval(t *testing.T) {
|
||||
outs, _, _, err := evalAndCollect(t, []string{"set x = hello", "put $x"}, 1)
|
||||
outs, _, err := evalAndCollect(t, []string{"set x = hello", "put $x"}, 1)
|
||||
wanted := strs("hello")
|
||||
if err != nil {
|
||||
t.Errorf("eval %q => %v, want nil", err)
|
||||
|
|
11
eval/exec.go
11
eval/exec.go
|
@ -4,8 +4,6 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/elves/elvish/errutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -76,13 +74,10 @@ func (c *Closure) Call(ec *evalCtx, args []Value) Error {
|
|||
// TODO(xiaq): Also change ec.name and ec.text since the closure being
|
||||
// called can come from another source.
|
||||
|
||||
ex, err := ec.eval(c.Op)
|
||||
if err != nil {
|
||||
fmt.Print(err.(*errutil.ContextualError).Pprint())
|
||||
return evalFailure
|
||||
}
|
||||
|
||||
ex := ec.peval(c.Op)
|
||||
ec.closePorts()
|
||||
return ex
|
||||
// return ec.peval(c.Op)
|
||||
}
|
||||
|
||||
// waitStatusToError converts syscall.WaitStatus to an Error.
|
||||
|
|
21
main.go
21
main.go
|
@ -42,12 +42,14 @@ func newEvalerAndStore() (*eval.Evaler, *store.Store) {
|
|||
}
|
||||
|
||||
func printError(err error) {
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if ce, ok := err.(*errutil.ContextualError); ok {
|
||||
fmt.Fprint(os.Stderr, ce.Pprint())
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
eval.PprintError(err)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,13 +60,10 @@ func interact() {
|
|||
printError(err)
|
||||
if err == nil {
|
||||
// XXX
|
||||
ex, err := ev.Source(datadir + "/rc.elv")
|
||||
err := ev.Source(datadir + "/rc.elv")
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
printError(err)
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
eval.PprintBadError(ex)
|
||||
}
|
||||
}
|
||||
|
||||
cmdNum := 0
|
||||
|
@ -110,19 +109,17 @@ func interact() {
|
|||
printError(err)
|
||||
|
||||
if err == nil {
|
||||
ex, err := ev.Eval(name, lr.Line, n)
|
||||
err := ev.Eval(name, lr.Line, n)
|
||||
printError(err)
|
||||
eval.PprintBadError(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func script(fname string) {
|
||||
ev, _ := newEvalerAndStore()
|
||||
ex, err := ev.Source(fname)
|
||||
err := ev.Source(fname)
|
||||
if err != nil {
|
||||
printError(err)
|
||||
eval.PprintBadError(ex)
|
||||
if err != nil || !ex.Bool() {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user