eval: Remove all runtime throws.

The only use of throw is in the compiler's error handling, which does
not leak into the exported API.

This fixes almost all of #570; however, part of the edit package still
uses throws for error handling now. I do not intend to migrate those
codes as they will be superseded by the rewritten package.
This commit is contained in:
Qi Xiao 2018-09-27 22:19:47 +01:00
parent 2320106a56
commit a0395f31bc
7 changed files with 52 additions and 47 deletions

View File

@ -198,19 +198,20 @@ func (b *BuiltinFn) Call(f *Frame, args []interface{}, opts map[string]interface
if b.inputs {
var inputs Inputs
if len(args) == len(b.normalArgs) {
inputs = Inputs(f.IterateInputs)
inputs = f.IterateInputs
} else {
// Wrap an iterable argument in Inputs.
iterable := args[len(args)-1]
inputs = Inputs(func(f func(interface{})) {
err := vals.Iterate(iterable, func(v interface{}) bool {
if !vals.CanIterate(iterable) {
return fmt.Errorf("%s cannot be iterated", vals.Kind(iterable))
}
inputs = func(f func(interface{})) {
// CanIterate(iterable) is true
_ = vals.Iterate(iterable, func(v interface{}) bool {
f(v)
return true
})
if err != nil {
throw(err)
}
})
}
}
in = append(in, reflect.ValueOf(inputs))
}

View File

@ -38,7 +38,11 @@ func cd(fm *Frame, args ...string) error {
var dir string
switch len(args) {
case 0:
dir = mustGetHome("")
var err error
dir, err = util.GetHome("")
if err != nil {
return err
}
case 1:
dir = args[0]
default:

View File

@ -484,6 +484,21 @@ func (cp *compiler) redir(n *parse.Redir) OpBody {
return &redirOp{dstOp, cp.compoundOp(n.Right), n.RightIsFd, n.Mode, flag}
}
func makeFlag(m parse.RedirMode) int {
switch m {
case parse.Read:
return os.O_RDONLY
case parse.Write:
return os.O_WRONLY | os.O_CREATE | os.O_TRUNC
case parse.ReadWrite:
return os.O_RDWR | os.O_CREATE
case parse.Append:
return os.O_WRONLY | os.O_CREATE | os.O_APPEND
default:
return -1
}
}
type redirOp struct {
dstOp ValuesOp
srcOp ValuesOp

View File

@ -152,7 +152,10 @@ func doTilde(v interface{}) (interface{}, error) {
uname = s[:i]
rest = s[i+1:]
}
dir := mustGetHome(uname)
dir, err := util.GetHome(uname)
if err != nil {
return nil, err
}
return path.Join(dir, rest), nil
case GlobPattern:
if len(v.Segments) == 0 {
@ -167,11 +170,18 @@ func doTilde(v interface{}) (interface{}, error) {
return nil, ErrCannotDetermineUsername
}
uname := s[:i]
dir := mustGetHome(uname)
dir, err := util.GetHome(uname)
if err != nil {
return nil, err
}
// Replace ~uname in first segment with the found path.
v.Segments[0] = glob.Literal{dir + s[i:]}
case glob.Slash:
v.DirOverride = mustGetHome("")
dir, err := util.GetHome("")
if err != nil {
return nil, err
}
v.DirOverride = dir
default:
return nil, ErrCannotDetermineUsername
}

View File

@ -36,7 +36,7 @@ func (cp *compiler) compiling(n parse.Node) {
}
func (cp *compiler) errorpf(begin, end int, format string, args ...interface{}) {
throw(&CompilationError{fmt.Sprintf(format, args...),
util.Throw(&CompilationError{fmt.Sprintf(format, args...),
*util.NewSourceRange(cp.srcMeta.describePath(), cp.srcMeta.code, begin, end)})
}

View File

@ -1,35 +0,0 @@
package eval
import (
"os"
"github.com/elves/elvish/parse"
"github.com/elves/elvish/util"
)
func throw(e error) {
util.Throw(e)
}
func mustGetHome(uname string) string {
dir, err := util.GetHome(uname)
if err != nil {
throw(err)
}
return dir
}
func makeFlag(m parse.RedirMode) int {
switch m {
case parse.Read:
return os.O_RDONLY
case parse.Write:
return os.O_WRONLY | os.O_CREATE | os.O_TRUNC
case parse.ReadWrite:
return os.O_RDWR | os.O_CREATE
case parse.Append:
return os.O_WRONLY | os.O_CREATE | os.O_APPEND
default:
return -1
}
}

View File

@ -13,6 +13,16 @@ type Iterator interface {
Iterate(func(v interface{}) bool)
}
// CanIterate returns whether the value can be iterated. If CanIterate(v) is
// true, calling Iterate(v, f) will not result in an error.
func CanIterate(v interface{}) bool {
switch v.(type) {
case Iterator, string, listIterable:
return true
}
return false
}
// Iterate iterates the supplied value, and calls the supplied function in each
// of its elements. The function can return false to break the iteration. It is
// implemented for the builtin type string, and types satisfying the