package eval

import (
	
	
	

	
	
	
	
	
	
	
)

// An operation that produces values.
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 {
		// A lone ~.
		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) {
	// Accumulator.
	,  := .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
}

// Errors thrown when globbing.
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:
		 := 
		// TODO: Make this correct on Windows.
		 := 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  {
				// ~username or ~username/xxx. Replace the first segment with
				// the home directory of the specified user.
				,  := 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 {
	// Parse signature.
	var (
		      []string
		       int = -1
		      []string
		 []valuesOp
	)
	if len(.Elements) > 0 {
		// Argument list.
		 = 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
}