package eval

import (
	

	
	
	
	
	
)

// Parsed group of lvalues.
type lvaluesGroup struct {
	lvalues []lvalue
	// Index of the rest variable within lvalues. If there is no rest variable,
	// the index is -1.
	rest int
}

// Parsed lvalue.
type lvalue struct {
	diag.Ranging
	ref      *varRef
	indexOps []valuesOp
	ends     []int
}

func ( *compiler) ( []*parse.Compound) lvaluesGroup {
	 := lvaluesGroup{nil, -1}
	for ,  := range  {
		if len(.Indexings) != 1 {
			.errorpf(, "lvalue may not be composite expressions")
		}
		 := .parseIndexingLValue(.Indexings[0])
		if .rest == -1 {
			.lvalues = append(.lvalues, .lvalues...)
		} else if .rest != -1 {
			.errorpf(, "at most one rest variable is allowed")
		} else {
			.rest = len(.lvalues) + .rest
			.lvalues = append(.lvalues, .lvalues...)
		}
	}
	return 
}

func ( *compiler) ( *parse.Indexing) lvaluesGroup {
	if .Head.Type == parse.Braced {
		// Braced list of lvalues may not have indices.
		if len(.Indicies) > 0 {
			.errorpf(, "braced list may not have indices when used as lvalue")
		}
		return .parseCompoundLValues(.Head.Braced)
	}
	// A basic lvalue.
	if !parse.ValidLHSVariable(.Head, true) {
		.errorpf(.Head, "lvalue must be valid literal variable names")
	}
	 := .Head.Value
	,  := SplitSigil()
	var  *varRef
	if len(.Indicies) == 0 {
		 = resolveVarRef(, , nil)
		if  == nil {
			 := SplitQNameSegs()
			if len() == 1 {
				// Unqualified name - implicit local
				 = &varRef{localScope, .thisScope().addInner([0]), nil}
			} else if len() == 2 && ([0] == "local:" || [0] == ":") {
				// Qualified local name
				 = &varRef{localScope, .thisScope().addInner([1]), nil}
			} else {
				.errorpf(, "cannot create variable $%s; new variables can only be created in the local scope", )
			}
		}
	} else {
		 = resolveVarRef(, , )
		if  == nil {
			.errorpf(, "cannot find variable $%s", )
		}
	}
	 := make([]int, len(.Indicies)+1)
	[0] = .Head.Range().To
	for ,  := range .Indicies {
		[+1] = .Range().To
	}
	 := lvalue{.Range(), , .arrayOps(.Indicies), }
	 := -1
	if  == "@" {
		 = 0
	}
	// TODO: Deal with other sigils when they exist.
	return lvaluesGroup{[]lvalue{}, }
}

type assignOp struct {
	diag.Ranging
	lhs lvaluesGroup
	rhs valuesOp
}

func ( *assignOp) ( *Frame) Exception {
	 := make([]vars.Var, len(.lhs.lvalues))
	for ,  := range .lhs.lvalues {
		,  := derefLValue(, )
		if  != nil {
			return .errorp(, )
		}
		[] = 
	}

	,  := .rhs.exec()
	if  != nil {
		return 
	}

	if .lhs.rest == -1 {
		if len() != len() {
			return .errorp(, errs.ArityMismatch{
				What:     "assignment right-hand-side",
				ValidLow: len(), ValidHigh: len(), Actual: len()})
		}
		for ,  := range  {
			 := .Set([])
			if  != nil {
				return .errorp(.lhs.lvalues[], )
			}
		}
	} else {
		if len() < len()-1 {
			return .errorp(, errs.ArityMismatch{
				What:     "assignment right-hand-side",
				ValidLow: len() - 1, ValidHigh: -1, Actual: len()})
		}
		 := .lhs.rest
		for  := 0;  < ; ++ {
			 := [].Set([])
			if  != nil {
				return .errorp(.lhs.lvalues[], )
			}
		}
		 := len() - len()
		 := [].Set(vals.MakeList([ : ++1]...))
		if  != nil {
			return .errorp(.lhs.lvalues[], )
		}
		for  :=  + 1;  < len(); ++ {
			 := [].Set([+])
			if  != nil {
				return .errorp(.lhs.lvalues[], )
			}
		}
	}
	return nil
}

// NoSuchVariable returns an error representing that a variable can't be found.
func ( string) error {
	return noSuchVariableError{}
}

type noSuchVariableError struct{ name string }

func ( noSuchVariableError) () string { return "no variable $" + .name }

func ( *Frame,  lvalue) (vars.Var, error) {
	 := deref(, .ref)
	if  == nil {
		return nil, NoSuchVariable(.srcMeta.Code[.From:.To])
	}
	if len(.indexOps) == 0 {
		return , nil
	}
	 := make([]interface{}, len(.indexOps))
	for ,  := range .indexOps {
		,  := .exec()
		if  != nil {
			return nil, 
		}
		// TODO: Implement multi-indexing.
		if len() != 1 {
			return nil, errors.New("multi indexing not implemented")
		}
		[] = [0]
	}
	,  := vars.MakeElement(, )
	if  != nil {
		 := vars.ElementErrorLevel()
		if  < 0 {
			return nil, .errorp(, )
		}
		return nil, .errorp(diag.Ranging{From: .From, To: .ends[]}, )
	}
	return , nil
}