예제 #1
0
// lvaluesOp compiles lvalues, returning the fixed part and, optionally a rest
// part.
//
// In the AST an lvalue is either an Indexing node where the head is a string
// literal, or a braced list of such Indexing nodes. The last Indexing node may
// be prefixed by @, in which case they become the rest part. For instance, in
// {a[x],b,@c[z]}, "a[x],b" is the fixed part and "c[z]" is the rest part.
func (cp *compiler) lvaluesOp(n *parse.Indexing) (LValuesOp, LValuesOp) {
	if n.Head.Type == parse.Braced {
		// Braced list of variable specs, possibly with indicies. The braced list
		if len(n.Indicies) > 0 {
			cp.errorf("may not have indicies")
		}

		opFuncs := make([]LValuesOpFunc, len(n.Head.Braced))
		var restNode *parse.Indexing
		var restOpFunc LValuesOpFunc

		// Compile each spec inside the brace.
		lvalueNodes := n.Head.Braced
		fixedEnd := 0
		for i, cn := range lvalueNodes {
			if len(cn.Indexings) != 1 {
				cp.errorpf(cn.Begin(), cn.End(), "must be an lvalue")
			}
			var rest bool
			rest, opFuncs[i] = cp.lvaluesOne(cn.Indexings[0], "must be an lvalue ")
			// Only the last one may a rest part.
			if rest {
				if i == len(n.Head.Braced)-1 {
					restNode = cn.Indexings[0]
					restOpFunc = opFuncs[i]
				} else {
					cp.errorpf(cn.Begin(), cn.End(), "only the last lvalue may have @")
				}
			} else {
				fixedEnd = cn.End()
			}
		}

		var restOp LValuesOp
		// If there is a rest part, make LValuesOp for it and remove it from opFuncs.
		if restOpFunc != nil {
			restOp = LValuesOp{restOpFunc, restNode.Begin(), restNode.End()}
			opFuncs = opFuncs[:len(opFuncs)-1]
		}

		var op LValuesOp
		// If there is still anything left in opFuncs, make LValuesOp for the fixed part.
		if len(opFuncs) > 0 {
			op = LValuesOp{func(ec *EvalCtx) []Variable {
				var variables []Variable
				for _, opFunc := range opFuncs {
					variables = append(variables, opFunc(ec)...)
				}
				return variables
			}, lvalueNodes[0].Begin(), fixedEnd}
		}

		return op, restOp
	}
	rest, opFunc := cp.lvaluesOne(n, "must be an lvalue or a braced list of those")
	op := LValuesOp{opFunc, n.Begin(), n.End()}
	if rest {
		return LValuesOp{}, op
	} else {
		return op, LValuesOp{}
	}
}
예제 #2
0
파일: boilerplate.go 프로젝트: zhsj/elvish
func (cp *compiler) indexingOp(n *parse.Indexing) ValuesOp {
	return ValuesOp{cp.indexing(n), n.Begin(), n.End()}
}