package eval
import (
)
type valuesOp interface {
diag.Ranger
exec(*Frame) ([]interface{}, Exception)
}
var outputCaptureBufferSize = 16
func ( *compiler) ( *parse.Compound) valuesOp {
if len(.Indexings) == 0 {
return literalValues(, "")
}
:= false
:= .Indexings
if .Indexings[0].Head.Type == parse.Tilde {
if len(.Indexings) == 1 {
return loneTildeOp{.Range()}
}
= true
= [1:]
}
return compoundOp{.Range(), , .indexingOps()}
}
type loneTildeOp struct{ diag.Ranging }
func ( loneTildeOp) ( *Frame) ([]interface{}, Exception) {
, := fsutil.GetHome("")
if != nil {
return nil, .errorp(, )
}
return []interface{}{}, nil
}
func ( *compiler) ( []*parse.Compound) []valuesOp {
:= make([]valuesOp, len())
for , := range {
[] = .compoundOp()
}
return
}
type compoundOp struct {
diag.Ranging
tilde bool
subops []valuesOp
}
func ( compoundOp) ( *Frame) ([]interface{}, Exception) {
, := .subops[0].exec()
if != nil {
return nil,
}
for , := range .subops[1:] {
, := .exec()
if != nil {
return nil,
}
var error
, = outerProduct(, , vals.Concat)
if != nil {
return nil, .errorp(, )
}
}
if .tilde {
:= make([]interface{}, len())
for , := range {
, := doTilde()
if != nil {
return nil, .errorp(, )
}
[] =
}
=
}
:= false
for , := range {
if , := .(globPattern); {
= true
break
}
}
if {
:= make([]interface{}, 0, len())
for , := range {
if , := .(globPattern); {
, := doGlob(, .Interrupts())
if != nil {
return nil, .errorp(, )
}
= append(, ...)
} else {
= append(, )
}
}
=
}
return , nil
}
func ( []interface{}, []interface{}, func(interface{}, interface{}) (interface{}, error)) ([]interface{}, error) {
:= make([]interface{}, len()*len())
:= len()
for , := range {
for , := range {
var error
[*+], = (, )
if != nil {
return nil,
}
}
}
return , nil
}
var (
ErrBadglobPattern = errors.New("bad globPattern; elvish bug")
ErrCannotDetermineUsername = errors.New("cannot determine user name from glob pattern")
)
func ( interface{}) (interface{}, error) {
switch v := .(type) {
case string:
:=
:= strings.Index(, "/")
var , string
if == -1 {
=
} else {
= [:]
= [:]
}
, := fsutil.GetHome()
if != nil {
return nil,
}
return + , nil
case globPattern:
if len(.Segments) == 0 {
return nil, ErrBadglobPattern
}
switch seg := .Segments[0].(type) {
case glob.Literal:
if len(.Segments) == 1 {
return nil, ErrBadglobPattern
}
, := .Segments[1].(glob.Slash)
if {
, := fsutil.GetHome(.Data)
if != nil {
return nil,
}
.Segments[0] = glob.Literal{Data: }
return , nil
}
case glob.Slash:
, := fsutil.GetHome("")
if != nil {
return nil,
}
.DirOverride =
return , nil
}
return nil, ErrCannotDetermineUsername
default:
return nil, fmt.Errorf("tilde doesn't work on value of type %s", vals.Kind())
}
}
func ( *compiler) ( *parse.Array) valuesOp {
return seqValuesOp{.Range(), .compoundOps(.Compounds)}
}
func ( *compiler) ( []*parse.Array) []valuesOp {
:= make([]valuesOp, len())
for , := range {
[] = .arrayOp()
}
return
}
func ( *compiler) ( *parse.Indexing) valuesOp {
if len(.Indicies) == 0 {
return .primaryOp(.Head)
}
return &indexingOp{.Range(), .primaryOp(.Head), .arrayOps(.Indicies)}
}
func ( *compiler) ( []*parse.Indexing) []valuesOp {
:= make([]valuesOp, len())
for , := range {
[] = .indexingOp()
}
return
}
type indexingOp struct {
diag.Ranging
headOp valuesOp
indexOps []valuesOp
}
func ( *indexingOp) ( *Frame) ([]interface{}, Exception) {
, := .headOp.exec()
if != nil {
return nil,
}
for , := range .indexOps {
, := .exec()
if != nil {
return nil,
}
:= make([]interface{}, 0, len()*len())
for , := range {
for , := range {
, := vals.Index(, )
if != nil {
return nil, .errorp(, )
}
= append(, )
}
}
=
}
return , nil
}
func ( *compiler) ( *parse.Primary) valuesOp {
switch .Type {
case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
return literalValues(, .Value)
case parse.Variable:
, := SplitSigil(.Value)
:= resolveVarRef(, , )
if == nil {
.errorpf(, "variable $%s not found", )
}
return &variableOp{.Range(), != "", , }
case parse.Wildcard:
, := wildcardToSegment(parse.SourceText())
if != nil {
.errorpf(, "%s", )
}
:= []interface{}{
globPattern{Pattern: glob.Pattern{Segments: []glob.Segment{}, DirOverride: ""},
Flags: 0, Buts: nil, TypeCb: nil}}
return literalValues(, ...)
case parse.Tilde:
.errorpf(, "compiler bug: Tilde not handled in .compound")
return literalValues(, "~")
case parse.ExceptionCapture:
return exceptionCaptureOp{.Range(), .chunkOp(.Chunk)}
case parse.OutputCapture:
return outputCaptureOp{.Range(), .chunkOp(.Chunk)}
case parse.List:
return listOp{.Range(), .compoundOps(.Elements)}
case parse.Lambda:
return .lambda()
case parse.Map:
return mapOp{.Range(), .mapPairs(.MapPairs)}
case parse.Braced:
return seqValuesOp{.Range(), .compoundOps(.Braced)}
default:
.errorpf(, "bad PrimaryType; parser bug")
return literalValues(, parse.SourceText())
}
}
func ( *compiler) ( []*parse.Primary) []valuesOp {
:= make([]valuesOp, len())
for , := range {
[] = .primaryOp()
}
return
}
type variableOp struct {
diag.Ranging
explode bool
qname string
ref *varRef
}
func ( variableOp) ( *Frame) ([]interface{}, Exception) {
:= deref(, .ref)
if == nil {
return nil, .errorpf(, "variable $%s not found", .qname)
}
:= .Get()
if .explode {
, := vals.Collect()
return , .errorp(, )
}
return []interface{}{}, nil
}
type listOp struct {
diag.Ranging
subops []valuesOp
}
func ( listOp) ( *Frame) ([]interface{}, Exception) {
:= vals.EmptyList
for , := range .subops {
, := .exec()
if != nil {
return nil,
}
for , := range {
= .Cons()
}
}
return []interface{}{}, nil
}
type exceptionCaptureOp struct {
diag.Ranging
subop effectOp
}
func ( exceptionCaptureOp) ( *Frame) ([]interface{}, Exception) {
:= .subop.exec()
if == nil {
return []interface{}{OK}, nil
}
return []interface{}{}, nil
}
type outputCaptureOp struct {
diag.Ranging
subop effectOp
}
func ( outputCaptureOp) ( *Frame) ([]interface{}, Exception) {
, , := CapturePort()
if != nil {
return nil, .errorp(, )
}
:= .subop.exec(.forkWithOutput("[output capture]", ))
return (),
}
func ( *compiler) ( *parse.Primary) valuesOp {
var (
[]string
int = -1
[]string
[]valuesOp
)
if len(.Elements) > 0 {
= make([]string, len(.Elements))
for , := range .Elements {
:= stringLiteralOrError(, , "argument name")
, := SplitSigil()
, := SplitQName()
if != "" {
.errorpf(, "argument name must be unqualified")
}
if == "" {
.errorpf(, "argument name must not be empty")
}
if == "@" {
if != -1 {
.errorpf(, "only one argument may have @")
}
=
}
[] =
}
}
if len(.MapPairs) > 0 {
= make([]string, len(.MapPairs))
= make([]valuesOp, len(.MapPairs))
for , := range .MapPairs {
:= stringLiteralOrError(, .Key, "option name")
, := SplitQName()
if != "" {
.errorpf(.Key, "option name must be unqualified")
}
if == "" {
.errorpf(.Key, "option name must not be empty")
}
[] =
if .Value == nil {
.errorpf(.Key, "option must have default value")
} else {
[] = .compoundOp(.Value)
}
}
}
, := .pushScope()
for , := range {
.add()
}
for , := range {
.add()
}
:= len(.names)
:= .chunkOp(.Chunk)
:= .names[:]
.popScope()
return &lambdaOp{.Range(), , , , , , , , .srcMeta}
}
type lambdaOp struct {
diag.Ranging
argNames []string
restArg int
optNames []string
optDefaultOps []valuesOp
newLocal []string
capture *staticUpNs
subop effectOp
srcMeta parse.Source
}
func ( *lambdaOp) ( *Frame) ([]interface{}, Exception) {
:= &Ns{
make([]vars.Var, len(.capture.names)),
.capture.names,
make([]bool, len(.capture.names))}
for := range .capture.names {
if .capture.local[] {
.slots[] = .local.slots[.capture.index[]]
} else {
.slots[] = .up.slots[.capture.index[]]
}
}
:= make([]interface{}, len(.optDefaultOps))
for , := range .optDefaultOps {
, := evalForValue(, , "option default value")
if != nil {
return nil,
}
[] =
}
return []interface{}{&closure{.argNames, .restArg, .optNames, , .subop, .newLocal, , .srcMeta, .Range()}}, nil
}
type mapOp struct {
diag.Ranging
pairsOp *mapPairsOp
}
func ( mapOp) ( *Frame) ([]interface{}, Exception) {
:= vals.EmptyMap
:= .pairsOp.exec(, func(, interface{}) Exception {
= .Assoc(, )
return nil
})
if != nil {
return nil,
}
return []interface{}{}, nil
}
func ( *compiler) ( []*parse.MapPair) *mapPairsOp {
:= len()
:= make([]valuesOp, )
:= make([]valuesOp, )
, := make([]int, ), make([]int, )
for , := range {
[] = .compoundOp(.Key)
if .Value == nil {
:= .Range().To
[] = literalValues(diag.PointRanging(), true)
} else {
[] = .compoundOp([].Value)
}
[], [] = .Range().From, .Range().To
}
return &mapPairsOp{, , , }
}
type mapPairsOp struct {
keysOps []valuesOp
valuesOps []valuesOp
begins []int
ends []int
}
func ( *mapPairsOp) ( *Frame, func(, interface{}) Exception) Exception {
for := range .keysOps {
, := .keysOps[].exec()
if != nil {
return
}
, := .valuesOps[].exec()
if != nil {
return
}
if len() != len() {
return .errorpf(diag.Ranging{From: .begins[], To: .ends[]},
"%d keys but %d values", len(), len())
}
for , := range {
:= (, [])
if != nil {
return
}
}
}
return nil
}
type literalValuesOp struct {
diag.Ranging
values []interface{}
}
func ( literalValuesOp) (*Frame) ([]interface{}, Exception) {
return .values, nil
}
func ( diag.Ranger, ...interface{}) valuesOp {
return literalValuesOp{.Range(), }
}
type seqValuesOp struct {
diag.Ranging
subops []valuesOp
}
func ( seqValuesOp) ( *Frame) ([]interface{}, Exception) {
var []interface{}
for , := range .subops {
, := .exec()
if != nil {
return nil,
}
= append(, ...)
}
return , nil
}
type nopValuesOp struct{ diag.Ranging }
func (nopValuesOp) ( *Frame) ([]interface{}, Exception) { return nil, nil }
func ( *Frame, valuesOp, string) (interface{}, Exception) {
, := .exec()
if != nil {
return nil,
}
if len() != 1 {
return nil, .errorp(, errs.ArityMismatch{
What: , ValidLow: 1, ValidHigh: 1, Actual: len()})
}
return [0], nil
}