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 } } }
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} } }
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]}} } }
// 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{} } }
func (cp *compiler) indexingOp(n *parse.Indexing) ValuesOp { return ValuesOp{cp.indexing(n), n.Begin(), n.End()} }
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]} } }