Implement for.

This commit is contained in:
Qi Xiao 2016-02-14 19:42:08 +01:00
parent 26006a03f4
commit ec9a628ba0
4 changed files with 45 additions and 31 deletions

View File

@ -77,14 +77,14 @@ func assignmentBegins(ns []*parse.Assignment) []int {
return begins
}
func (cp *compiler) indexingVars(ns []*parse.Indexing, msg string) []VariableOp {
func (cp *compiler) singleVariables(ns []*parse.Indexing, msg string) []VariableOp {
ops := make([]VariableOp, len(ns))
for i, n := range ns {
ops[i] = cp.indexingVar(n, msg)
ops[i] = cp.singleVariable(n, msg)
}
return ops
}
func indexingVarBegins(ns []*parse.Indexing) []int {
func singleVariableBegins(ns []*parse.Indexing) []int {
begins := make([]int, len(ns))
for i, n := range ns {
begins[i] = n.Begin()

View File

@ -277,8 +277,17 @@ func (cp *compiler) control(n *parse.Control) Op {
}
}
case parse.ForControl:
cp.errorf(n.Begin(), "not yet implemented")
panic("unreachable")
iteratorOp := cp.singleVariable(n.Iterator, "must be a single variable")
valuesOp := cp.array(n.Array)
bodyOp := cp.chunk(n.Body)
return func(ec *EvalCtx) {
iterator := iteratorOp(ec)
values := valuesOp(ec)
for _, v := range values {
doSet(ec, []Variable{iterator}, []Value{v})
bodyOp(ec)
}
}
case parse.BeginControl:
return cp.chunk(n.Body)
default:
@ -298,21 +307,7 @@ func (cp *compiler) literal(n *parse.Primary, msg string) string {
}
func (cp *compiler) assignment(n *parse.Assignment) Op {
var variableOps []VariableOp
if n.Dst.Head.Type == parse.Braced {
compounds := n.Dst.Head.Braced
indexings := make([]*parse.Indexing, len(compounds))
for i, cn := range compounds {
if len(cn.Indexings) != 1 {
cp.errorf(cn.Begin(), "must be a variable spec")
}
indexings[i] = cn.Indexings[0]
}
variableOps = cp.indexingVars(indexings, "must be a variable spc")
} else {
variableOps = []VariableOp{cp.indexingVar(n.Dst, "must be a variable spec or a braced list of those")}
}
variableOps := cp.multiVariable(n.Dst)
valuesOp := cp.compound(n.Src)
return func(ec *EvalCtx) {
@ -324,8 +319,27 @@ func (cp *compiler) assignment(n *parse.Assignment) Op {
}
}
func (cp *compiler) indexingVar(n *parse.Indexing, msg string) VariableOp {
// XXX will we be using indexingVar for purposes other than setting?
func (cp *compiler) multiVariable(n *parse.Indexing) []VariableOp {
var variableOps []VariableOp
if n.Head.Type == parse.Braced {
// XXX ignore n.Indicies.
compounds := n.Head.Braced
indexings := make([]*parse.Indexing, len(compounds))
for i, cn := range compounds {
if len(cn.Indexings) != 1 {
cp.errorf(cn.Begin(), "must be a variable spec")
}
indexings[i] = cn.Indexings[0]
}
variableOps = cp.singleVariables(indexings, "must be a variable spc")
} else {
variableOps = []VariableOp{cp.singleVariable(n, "must be a variable spec or a braced list of those")}
}
return variableOps
}
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()

View File

@ -92,7 +92,7 @@ func (n *Control) setCondition(ch *Chunk) {
addChild(n, ch)
}
func (n *Control) setIterator(ch *Primary) {
func (n *Control) setIterator(ch *Indexing) {
n.Iterator = ch
addChild(n, ch)
}

View File

@ -286,13 +286,13 @@ func (an *Assignment) parse(ps *parser) {
type Control struct {
node
Kind ControlKind
Condition *Chunk // Valid for WhileControl.
Iterator *Primary // Valid for ForControl.
Array *Array // Valid for ForControl.
Body *Chunk // Valid for all except IfControl.
Conditions []*Chunk // Valid for IfControl.
Bodies []*Chunk // Valid for IfControl.
ElseBody *Chunk // Valid for IfControl, WhileControl and ForControl.
Condition *Chunk // Valid for WhileControl.
Iterator *Indexing // Valid for ForControl.
Array *Array // Valid for ForControl.
Body *Chunk // Valid for all except IfControl.
Conditions []*Chunk // Valid for IfControl.
Bodies []*Chunk // Valid for IfControl.
ElseBody *Chunk // Valid for IfControl, WhileControl and ForControl.
}
// ControlKind identifies which control structure a Control represents.
@ -374,7 +374,7 @@ func (ctrl *Control) parse(ps *parser, leader string) {
case "for":
ctrl.Kind = ForControl
parseSpaces(ctrl, ps)
ctrl.setIterator(parsePrimary(ps))
ctrl.setIterator(parseIndexing(ps))
parseSpaces(ctrl, ps)
if ps.findPossibleLeader() == "in" {
ps.advance(len("in"))