elvish/eval/compile_value.go

580 lines
13 KiB
Go
Raw Normal View History

2016-02-20 00:21:51 +08:00
package eval
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"path"
"strings"
"sync"
2016-02-20 00:21:51 +08:00
2018-02-15 17:14:05 +08:00
"github.com/elves/elvish/eval/vals"
2016-02-20 00:21:51 +08:00
"github.com/elves/elvish/glob"
"github.com/elves/elvish/parse"
"github.com/elves/elvish/util"
2016-02-20 00:21:51 +08:00
)
var outputCaptureBufferSize = 16
2018-01-21 06:34:38 +08:00
// ValuesOp is an operation on an Frame that produce Value's.
2016-02-20 07:48:13 +08:00
type ValuesOp struct {
Body ValuesOpBody
2016-02-20 07:48:13 +08:00
Begin, End int
}
// ValuesOpBody is the body of ValuesOp.
type ValuesOpBody interface {
Invoke(*Frame) ([]interface{}, error)
}
2017-06-11 07:04:53 +08:00
// Exec executes a ValuesOp and produces Value's.
func (op ValuesOp) Exec(fm *Frame) ([]interface{}, error) {
fm.begin, fm.end = op.Begin, op.End
return op.Body.Invoke(fm)
2016-02-20 07:48:13 +08:00
}
func (cp *compiler) compound(n *parse.Compound) ValuesOpBody {
2016-02-20 00:21:51 +08:00
if len(n.Indexings) == 0 {
return literalStr("")
}
tilde := false
indexings := n.Indexings
if n.Indexings[0].Head.Type == parse.Tilde {
// A lone ~.
if len(n.Indexings) == 1 {
return funcValuesOp(func(fm *Frame) ([]interface{}, error) {
home, err := util.GetHome("")
if err != nil {
return nil, err
}
return []interface{}{home}, nil
})
2016-02-20 00:21:51 +08:00
}
tilde = true
indexings = indexings[1:]
}
return compoundOp{tilde, cp.indexingOps(indexings)}
}
type compoundOp struct {
tilde bool
subops []ValuesOp
}
func (op compoundOp) Invoke(fm *Frame) ([]interface{}, error) {
// Accumulator.
vs, err := op.subops[0].Exec(fm)
if err != nil {
return nil, err
}
2016-02-20 00:21:51 +08:00
for _, subop := range op.subops[1:] {
us, err := subop.Exec(fm)
if err != nil {
return nil, err
}
vs, err = outerProduct(vs, us, vals.Concat)
if err != nil {
return nil, err
2016-02-20 00:21:51 +08:00
}
}
if op.tilde {
newvs := make([]interface{}, len(vs))
for i, v := range vs {
2018-09-27 22:32:41 +08:00
tilded, err := doTilde(v)
if err != nil {
return nil, err
}
newvs[i] = tilded
2016-02-20 00:21:51 +08:00
}
vs = newvs
}
hasGlob := false
for _, v := range vs {
if _, ok := v.(GlobPattern); ok {
hasGlob = true
break
2016-02-20 00:21:51 +08:00
}
}
if hasGlob {
newvs := make([]interface{}, 0, len(vs))
for _, v := range vs {
if gp, ok := v.(GlobPattern); ok {
2018-09-27 08:48:44 +08:00
results, err := doGlob(gp, fm.Interrupts())
if err != nil {
return nil, err
}
newvs = append(newvs, results...)
} else {
newvs = append(newvs, v)
2016-02-20 00:21:51 +08:00
}
}
vs = newvs
2016-02-20 00:21:51 +08:00
}
return vs, nil
2016-02-20 00:21:51 +08:00
}
func outerProduct(vs []interface{}, us []interface{}, f func(interface{}, interface{}) (interface{}, error)) ([]interface{}, error) {
ws := make([]interface{}, len(vs)*len(us))
2016-02-20 00:21:51 +08:00
nu := len(us)
for i, v := range vs {
for j, u := range us {
var err error
ws[i*nu+j], err = f(v, u)
if err != nil {
return nil, err
}
2016-02-20 00:21:51 +08:00
}
}
return ws, nil
2016-02-20 00:21:51 +08:00
}
2017-06-11 07:04:53 +08:00
// Errors thrown when globbing.
var (
ErrBadGlobPattern = errors.New("bad GlobPattern; elvish bug")
ErrCannotDetermineUsername = errors.New("cannot determine user name from glob pattern")
)
2018-09-27 22:32:41 +08:00
func doTilde(v interface{}) (interface{}, error) {
2016-02-20 00:21:51 +08:00
switch v := v.(type) {
case string:
s := v
2016-02-20 00:21:51 +08:00
i := strings.Index(s, "/")
var uname, rest string
if i == -1 {
uname = s
} else {
uname = s[:i]
rest = s[i+1:]
}
dir := mustGetHome(uname)
2018-09-27 22:32:41 +08:00
return path.Join(dir, rest), nil
2016-02-20 00:21:51 +08:00
case GlobPattern:
if len(v.Segments) == 0 {
2018-09-27 22:32:41 +08:00
return nil, ErrBadGlobPattern
2016-02-20 00:21:51 +08:00
}
2017-02-03 03:15:42 +08:00
switch seg := v.Segments[0].(type) {
case glob.Literal:
2017-02-03 03:15:42 +08:00
s := seg.Data
// Find / in the first segment to determine the username.
i := strings.Index(s, "/")
if i == -1 {
2018-09-27 22:32:41 +08:00
return nil, ErrCannotDetermineUsername
}
uname := s[:i]
dir := mustGetHome(uname)
// Replace ~uname in first segment with the found path.
2017-02-03 03:15:42 +08:00
v.Segments[0] = glob.Literal{dir + s[i:]}
case glob.Slash:
v.DirOverride = mustGetHome("")
default:
2018-09-27 22:32:41 +08:00
return nil, ErrCannotDetermineUsername
2016-02-20 00:21:51 +08:00
}
2018-09-27 22:32:41 +08:00
return v, nil
2016-02-20 00:21:51 +08:00
default:
2018-09-27 22:32:41 +08:00
return nil, fmt.Errorf("tilde doesn't work on value of type %s", vals.Kind(v))
2016-02-20 00:21:51 +08:00
}
}
func (cp *compiler) array(n *parse.Array) ValuesOpBody {
return seqValuesOp{cp.compoundOps(n.Compounds)}
2016-02-20 00:21:51 +08:00
}
func (cp *compiler) indexing(n *parse.Indexing) ValuesOpBody {
2016-02-20 00:21:51 +08:00
if len(n.Indicies) == 0 {
return cp.primary(n.Head)
}
return &indexingOp{cp.primaryOp(n.Head), cp.arrayOps(n.Indicies)}
2016-02-20 00:21:51 +08:00
}
type indexingOp struct {
headOp ValuesOp
indexOps []ValuesOp
2016-02-20 00:21:51 +08:00
}
func (op *indexingOp) Invoke(fm *Frame) ([]interface{}, error) {
vs, err := op.headOp.Exec(fm)
if err != nil {
return nil, err
}
for _, indexOp := range op.indexOps {
indicies, err := indexOp.Exec(fm)
if err != nil {
return nil, err
2016-02-20 00:21:51 +08:00
}
newvs := make([]interface{}, 0, len(vs)*len(indicies))
for _, v := range vs {
for _, index := range indicies {
2018-02-15 17:14:05 +08:00
result, err := vals.Index(v, index)
if err != nil {
return nil, err
}
newvs = append(newvs, result)
2016-02-20 00:21:51 +08:00
}
}
vs = newvs
2016-02-20 00:21:51 +08:00
}
return vs, nil
2016-02-20 00:21:51 +08:00
}
func (cp *compiler) primary(n *parse.Primary) ValuesOpBody {
2016-02-20 00:21:51 +08:00
switch n.Type {
case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
return literalStr(n.Value)
case parse.Variable:
explode, ns, name := ParseVariableRef(n.Value)
if !cp.registerVariableGet(ns, name) {
2016-02-20 04:16:23 +08:00
cp.errorf("variable $%s not found", n.Value)
2016-02-20 00:21:51 +08:00
}
return &variableOp{explode, ns, name}
2016-02-20 00:21:51 +08:00
case parse.Wildcard:
2017-06-27 01:47:10 +08:00
seg, err := wildcardToSegment(n.SourceText())
if err != nil {
cp.errorf("%s", err)
}
vs := []interface{}{
2017-06-27 01:47:10 +08:00
GlobPattern{glob.Pattern{[]glob.Segment{seg}, ""}, 0, nil}}
return literalValues(vs...)
2016-02-20 00:21:51 +08:00
case parse.Tilde:
2016-02-20 04:16:23 +08:00
cp.errorf("compiler bug: Tilde not handled in .compound")
2016-02-20 00:21:51 +08:00
return literalStr("~")
2017-02-18 12:43:27 +08:00
case parse.ExceptionCapture:
return exceptionCaptureOp{cp.chunkOp(n.Chunk)}
2016-02-20 00:21:51 +08:00
case parse.OutputCapture:
return outputCaptureOp{cp.chunkOp(n.Chunk)}
2016-02-20 00:21:51 +08:00
case parse.List:
2017-08-06 03:49:50 +08:00
return cp.list(n)
2016-02-20 00:21:51 +08:00
case parse.Lambda:
return cp.lambda(n)
case parse.Map:
return cp.map_(n)
case parse.Braced:
return cp.braced(n)
default:
2016-02-20 04:16:23 +08:00
cp.errorf("bad PrimaryType; parser bug")
2016-02-20 00:21:51 +08:00
return literalStr(n.SourceText())
}
}
type variableOp struct {
explode bool
ns string
name string
}
func (op variableOp) Invoke(fm *Frame) ([]interface{}, error) {
variable := fm.ResolveVar(op.ns, op.name)
if variable == nil {
return nil, fmt.Errorf("variable $%s:%s not found", op.ns, op.name)
}
value := variable.Get()
if op.explode {
2018-02-15 17:14:05 +08:00
return vals.Collect(value)
2016-03-08 09:01:58 +08:00
}
return []interface{}{value}, nil
2016-03-08 09:01:58 +08:00
}
func (cp *compiler) list(n *parse.Primary) ValuesOpBody {
2018-01-21 21:24:00 +08:00
return listOp{cp.compoundOps(n.Elements)}
}
2018-01-21 21:24:00 +08:00
type listOp struct{ subops []ValuesOp }
func (op listOp) Invoke(fm *Frame) ([]interface{}, error) {
2018-02-15 17:14:05 +08:00
list := vals.EmptyList
2018-01-21 21:24:00 +08:00
for _, subop := range op.subops {
moreValues, err := subop.Exec(fm)
if err != nil {
return nil, err
}
for _, moreValue := range moreValues {
list = list.Cons(moreValue)
2018-01-21 21:24:00 +08:00
}
2016-02-20 00:21:51 +08:00
}
return []interface{}{list}, nil
2016-02-20 00:21:51 +08:00
}
type exceptionCaptureOp struct{ subop Op }
func (op exceptionCaptureOp) Invoke(fm *Frame) ([]interface{}, error) {
2018-03-01 09:56:41 +08:00
err := fm.Eval(op.subop)
if err == nil {
return []interface{}{OK}, nil
2016-02-20 00:21:51 +08:00
}
return []interface{}{err.(*Exception)}, nil
2016-02-20 00:21:51 +08:00
}
type outputCaptureOp struct{ subop Op }
func (op outputCaptureOp) Invoke(fm *Frame) ([]interface{}, error) {
return pcaptureOutput(fm, op.subop)
}
func pcaptureOutput(fm *Frame, op Op) ([]interface{}, error) {
vs := []interface{}{}
var m sync.Mutex
valueCb := func(ch <-chan interface{}) {
2016-02-20 00:21:51 +08:00
for v := range ch {
m.Lock()
2016-02-20 00:21:51 +08:00
vs = append(vs, v)
m.Unlock()
2016-02-20 00:21:51 +08:00
}
}
bytesCb := func(r *os.File) {
buffered := bufio.NewReader(r)
2016-02-20 00:21:51 +08:00
for {
line, err := buffered.ReadString('\n')
if line != "" {
v := strings.TrimSuffix(line, "\n")
m.Lock()
vs = append(vs, v)
m.Unlock()
}
if err != nil {
if err != io.EOF {
logger.Println("error on reading:", err)
}
2016-02-20 00:21:51 +08:00
break
}
}
}
err := pcaptureOutputInner(fm, op, valueCb, bytesCb)
return vs, err
}
func pcaptureOutputInner(fm *Frame, op Op, valuesCb func(<-chan interface{}), bytesCb func(*os.File)) error {
newFm := fm.fork("[output capture]")
ch := make(chan interface{}, outputCaptureBufferSize)
pipeRead, pipeWrite, err := os.Pipe()
if err != nil {
return fmt.Errorf("failed to create pipe: %v", err)
}
newFm.ports[1] = &Port{
Chan: ch, CloseChan: true,
File: pipeWrite, CloseFile: true,
}
bytesCollected := make(chan struct{})
chCollected := make(chan struct{})
go func() {
valuesCb(ch)
close(chCollected)
}()
go func() {
bytesCb(pipeRead)
pipeRead.Close()
close(bytesCollected)
2016-02-20 00:21:51 +08:00
}()
err = newFm.Eval(op)
2016-02-20 00:21:51 +08:00
newFm.Close()
2016-02-20 00:21:51 +08:00
<-bytesCollected
<-chCollected
return err
2016-02-20 00:21:51 +08:00
}
func (cp *compiler) lambda(n *parse.Primary) ValuesOpBody {
// Parse signature.
var (
argNames []string
restArgName string
optNames []string
optDefaultOps []ValuesOp
)
2017-08-06 03:49:50 +08:00
if len(n.Elements) > 0 {
// Argument list.
2017-08-06 03:49:50 +08:00
argNames = make([]string, len(n.Elements))
for i, arg := range n.Elements {
qname := mustString(cp, arg, "argument name must be literal string")
explode, ns, name := ParseVariableRef(qname)
if ns != "" {
cp.errorpf(arg.Begin(), arg.End(), "argument name must be unqualified")
}
if name == "" {
cp.errorpf(arg.Begin(), arg.End(), "argument name must not be empty")
}
if explode {
2017-08-06 03:49:50 +08:00
if i != len(n.Elements)-1 {
cp.errorpf(arg.Begin(), arg.End(), "only the last argument may have @")
}
restArgName = name
argNames = argNames[:i]
} else {
argNames[i] = name
}
2016-02-20 00:21:51 +08:00
}
}
if len(n.MapPairs) > 0 {
optNames = make([]string, len(n.MapPairs))
optDefaultOps = make([]ValuesOp, len(n.MapPairs))
for i, opt := range n.MapPairs {
qname := mustString(cp, opt.Key, "option name must be literal string")
_, ns, name := ParseVariableRef(qname)
if ns != "" {
cp.errorpf(opt.Key.Begin(), opt.Key.End(), "option name must be unqualified")
}
if name == "" {
cp.errorpf(opt.Key.Begin(), opt.Key.End(), "option name must not be empty")
}
optNames[i] = name
if opt.Value == nil {
cp.errorpf(opt.End(), opt.End(), "option must have default value")
} else {
optDefaultOps[i] = cp.compoundOp(opt.Value)
}
}
}
2016-02-20 00:21:51 +08:00
thisScope := cp.pushScope()
for _, argName := range argNames {
thisScope.set(argName)
2016-02-20 00:21:51 +08:00
}
if restArgName != "" {
thisScope.set(restArgName)
}
for _, optName := range optNames {
thisScope.set(optName)
}
subop := cp.chunkOp(n.Chunk)
// XXX The fiddlings with cp.capture is error-prone.
2016-02-20 00:21:51 +08:00
capture := cp.capture
cp.capture = make(staticNs)
2016-02-20 00:21:51 +08:00
cp.popScope()
for name := range capture {
cp.registerVariableGetQname(name)
2017-09-21 07:10:21 +08:00
}
2016-02-20 00:21:51 +08:00
return &lambdaOp{argNames, restArgName, optNames, optDefaultOps, capture, subop, cp.srcMeta, n.Begin(), n.End()}
}
type lambdaOp struct {
argNames []string
restArgName string
optNames []string
optDefaultOps []ValuesOp
capture staticNs
subop Op
srcMeta *Source
defBegin int
defEnd int
}
func (op *lambdaOp) Invoke(fm *Frame) ([]interface{}, error) {
evCapture := make(Ns)
for name := range op.capture {
evCapture[name] = fm.ResolveVar("", name)
}
optDefaults := make([]interface{}, len(op.optDefaultOps))
for i, op := range op.optDefaultOps {
defaultValue := fm.ExecAndUnwrap("option default value", op).One().Any()
optDefaults[i] = defaultValue
2016-02-20 00:21:51 +08:00
}
// XXX(xiaq): Capture uses.
return []interface{}{&Closure{op.argNames, op.restArgName, op.optNames, optDefaults, op.subop, evCapture, op.srcMeta, op.defBegin, op.defEnd}}, nil
2016-02-20 00:21:51 +08:00
}
func (cp *compiler) map_(n *parse.Primary) ValuesOpBody {
return cp.mapPairs(n.MapPairs)
}
func (cp *compiler) mapPairs(pairs []*parse.MapPair) ValuesOpBody {
npairs := len(pairs)
2016-02-20 00:21:51 +08:00
keysOps := make([]ValuesOp, npairs)
valuesOps := make([]ValuesOp, npairs)
2016-02-20 07:48:13 +08:00
begins, ends := make([]int, npairs), make([]int, npairs)
for i, pair := range pairs {
2016-02-20 07:48:13 +08:00
keysOps[i] = cp.compoundOp(pair.Key)
2016-02-20 00:21:51 +08:00
if pair.Value == nil {
2016-02-20 07:48:13 +08:00
p := pair.End()
valuesOps[i] = ValuesOp{literalValues(true), p, p}
2016-02-20 00:21:51 +08:00
} else {
valuesOps[i] = cp.compoundOp(pairs[i].Value)
2016-02-20 00:21:51 +08:00
}
2016-02-20 07:48:13 +08:00
begins[i], ends[i] = pair.Begin(), pair.End()
2016-02-20 00:21:51 +08:00
}
return &mapPairsOp{keysOps, valuesOps, begins, ends}
}
type mapPairsOp struct {
keysOps []ValuesOp
valuesOps []ValuesOp
begins []int
ends []int
}
func (op *mapPairsOp) Invoke(fm *Frame) ([]interface{}, error) {
2018-02-15 17:14:05 +08:00
m := vals.EmptyMap
for i := range op.keysOps {
keys, err := op.keysOps[i].Exec(fm)
if err != nil {
return nil, err
}
values, err := op.valuesOps[i].Exec(fm)
if err != nil {
return nil, err
}
if len(keys) != len(values) {
2018-09-28 01:50:53 +08:00
return nil, fm.errorpf(op.begins[i], op.ends[i],
"%d keys but %d values", len(keys), len(values))
}
for j, key := range keys {
m = m.Assoc(key, values[j])
2016-02-20 00:21:51 +08:00
}
}
return []interface{}{m}, nil
2016-02-20 00:21:51 +08:00
}
func (cp *compiler) braced(n *parse.Primary) ValuesOpBody {
2016-02-20 07:48:13 +08:00
ops := cp.compoundOps(n.Braced)
2016-02-20 00:21:51 +08:00
// TODO: n.IsRange
// isRange := n.IsRange
return seqValuesOp{ops}
}
type literalValuesOp struct{ values []interface{} }
func (op literalValuesOp) Invoke(*Frame) ([]interface{}, error) {
return op.values, nil
}
func literalValues(v ...interface{}) ValuesOpBody {
return literalValuesOp{v}
}
func literalStr(text string) ValuesOpBody {
return literalValues(text)
}
type seqValuesOp struct{ subops []ValuesOp }
func (op seqValuesOp) Invoke(fm *Frame) ([]interface{}, error) {
var values []interface{}
for _, subop := range op.subops {
moreValues, err := subop.Exec(fm)
if err != nil {
return nil, err
}
values = append(values, moreValues...)
}
return values, nil
2016-02-20 00:21:51 +08:00
}
type funcValuesOp func(*Frame) ([]interface{}, error)
func (op funcValuesOp) Invoke(fm *Frame) ([]interface{}, error) { return op(fm) }