mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
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:
parent
2320106a56
commit
a0395f31bc
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)})
|
||||
}
|
||||
|
||||
|
|
35
eval/util.go
35
eval/util.go
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user