Example #1
0
func (cp *compiler) indexingVar(n *parse.Indexing, msg string) variableOp {
	// XXX will we be using indexingVar for purposes other than setting?
	varname := cp.literal(n.Head, msg)
	p := n.Begin()

	if len(n.Indicies) == 0 {
		cp.registerVariableSet(varname)

		return func(ec *evalCtx) Variable {
			ns, barename := splitQualifiedName(varname)
			variable := ec.ResolveVar(ns, barename)
			if variable == nil {
				// New variable.
				// XXX We depend on the fact that this variable will
				// immeidately be set.
				variable = newPtrVariable(nil)
				ec.local[barename] = variable
			}
			return variable
		}
	} else {
		cp.registerVariableGet(varname)
		indexOps := cp.arrays(n.Indicies)
		indexBegins := make([]int, len(n.Indicies))
		indexEnds := make([]int, len(n.Indicies))
		for i, in := range n.Indicies {
			indexBegins[i] = in.Begin()
			indexEnds[i] = in.End()
		}

		return func(ec *evalCtx) Variable {
			variable := ec.ResolveVar(splitQualifiedName(varname))
			if variable == nil {
				ec.errorf(p, "variable $%s does not exisit, compiler bug", varname)
			}
			for i, op := range indexOps {
				indexer, ok := variable.Get().(IndexVarer)
				if !ok {
					ec.errorf( /* from p to */ indexBegins[i], "cannot be indexing for setting (type %T)", variable.Get())
				}
				values := op(ec)
				if len(values) != 1 {
					ec.errorf(indexBegins[i], "index must eval to a single Value (got %v)", values)
				}

				variable = indexer.IndexVar(values[0])
			}
			return variable
		}
	}
}
Example #2
0
func (cp *compiler) indexing(n *parse.Indexing) valuesOp {
	if len(n.Indicies) == 0 {
		return cp.primary(n.Head)
	}

	headOp := cp.primary(n.Head)
	indexOps := cp.arrays(n.Indicies)
	p := n.Begin()
	indexPoses := make([]int, len(n.Indicies))
	for i, index := range n.Indicies {
		indexPoses[i] = index.Begin()
	}

	return func(ec *evalCtx) []Value {
		v := ec.must(headOp(ec), "the indexing value", p).mustOne()
		for i, indexOp := range indexOps {
			index := ec.must(indexOp(ec), "the index", p).mustOne()
			v = evalIndex(ec, v, index, p, indexPoses[i])
		}
		return []Value{v}
	}
}
Example #3
0
func (cp *compiler) lvaluesOne(n *parse.Indexing, msg string) (bool, LValuesOpFunc) {
	varname := cp.literal(n.Head, msg)
	cp.registerVariableSet(varname)
	explode, ns, barename := ParseAndFixVariable(varname)

	if len(n.Indicies) == 0 {
		return explode, func(ec *EvalCtx) []Variable {
			variable := ec.ResolveVar(ns, barename)
			if variable == nil {
				if ns == "" || ns == "local" {
					// New variable.
					// XXX We depend on the fact that this variable will
					// immeidately be set.
					variable = NewPtrVariable(nil)
					ec.local[barename] = variable
				} else if mod, ok := ec.Modules[ns]; ok {
					variable = NewPtrVariable(nil)
					mod[barename] = variable
				} else {
					throwf("cannot set $%s", varname)
				}
			}
			return []Variable{variable}
		}
	}

	p := n.Begin()
	indexOps := cp.arrayOps(n.Indicies)

	return explode, func(ec *EvalCtx) []Variable {
		variable := ec.ResolveVar(ns, barename)
		if variable == nil {
			throwf("variable $%s does not exisit, compiler bug", varname)
		}

		// Indexing. Do Index up to the last but one index.
		value := variable.Get()
		n := len(indexOps)
		// TODO set location information according.
		for _, op := range indexOps[:n-1] {
			indexer := mustIndexer(value, ec)

			indicies := op.Exec(ec)
			values := indexer.Index(indicies)
			if len(values) != 1 {
				throw(errors.New("multi indexing not implemented"))
			}
			value = values[0]
		}
		// Now this must be an IndexSetter.
		indexSetter, ok := value.(IndexSetter)
		if !ok {
			// XXX the indicated end location will fall on or after the opening
			// bracket of the last index, instead of exactly on the penultimate
			// index.
			ec.errorpf(p, indexOps[n-1].Begin, "cannot be indexed for setting (value is %s, type %s)", value.Repr(NoPretty), value.Kind())
		}
		// XXX Duplicate code.
		indicies := indexOps[n-1].Exec(ec)
		if len(indicies) != 1 {
			ec.errorpf(indexOps[n-1].Begin, indexOps[n-1].End, "index must eval to a single Value (got %v)", indicies)
		}
		return []Variable{elemVariable{indexSetter, indicies[0]}}
	}
}
Example #4
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{}
	}
}
Example #5
0
func (cp *compiler) indexingOp(n *parse.Indexing) ValuesOp {
	return ValuesOp{cp.indexing(n), n.Begin(), n.End()}
}
Example #6
0
func (cp *compiler) singleVariable(n *parse.Indexing, msg string) VariableOp {
	// XXX will we be using this for purposes other than setting?
	varname := cp.literal(n.Head, msg)
	p := n.Begin()

	if len(n.Indicies) == 0 {
		cp.registerVariableSet(varname)

		return func(ec *EvalCtx) Variable {
			splice, ns, barename := parseVariable(varname)
			if splice {
				// XXX
				ec.errorf(p, "not yet supported")
			}
			variable := ec.ResolveVar(ns, barename)
			if variable == nil {
				// New variable.
				// XXX We depend on the fact that this variable will
				// immeidately be set.
				variable = NewPtrVariable(nil)
				ec.local[barename] = variable
			}
			return variable
		}
	}
	cp.registerVariableGet(varname)
	indexOps := cp.arrays(n.Indicies)
	indexBegins := make([]int, len(n.Indicies))
	indexEnds := make([]int, len(n.Indicies))
	for i, in := range n.Indicies {
		indexBegins[i] = in.Begin()
		indexEnds[i] = in.End()
	}

	return func(ec *EvalCtx) Variable {
		splice, ns, name := parseVariable(varname)
		if splice {
			// XXX
			ec.errorf(p, "not yet supported")
		}
		variable := ec.ResolveVar(ns, name)
		if variable == nil {
			ec.errorf(p, "variable $%s does not exisit, compiler bug", varname)
		}
		if len(indexOps) == 0 {
			// Just a variable, return directly.
			return variable
		}

		// Indexing. Do Index up to the last but one index.
		value := variable.Get()
		n := len(indexOps)
		for i, op := range indexOps[:n-1] {
			indexer, ok := value.(Indexer)
			if !ok {
				ec.errorf( /* from p to */ indexBegins[i], "cannot be indexed (value is %s, type %s)", value.Repr(), value.Kind())
			}

			indicies := op(ec)
			if len(indicies) != 1 {
				ec.errorf(indexBegins[i], "index must eval to a single Value (got %v)", indicies)
			}

			value = indexer.Index(indicies[0])
		}
		// Now this must be an IndexSetter.
		indexSetter, ok := value.(IndexSetter)
		if !ok {
			ec.errorf( /* from p to */ indexBegins[n-1], "cannot be indexed for setting (value is %s, type %s)", value.Repr(), value.Kind())
		}
		// XXX Duplicate code.
		indicies := indexOps[n-1](ec)
		if len(indicies) != 1 {
			ec.errorf(indexBegins[n-1], "index must eval to a single Value (got %v)", indicies)
		}
		return elemVariable{indexSetter, indicies[0]}
	}
}