func (cp *compiler) control(n *parse.Control) Op { switch n.Kind { case parse.IfControl: condOps := cp.errorCaptures(n.Conditions) bodyOps := cp.chunks(n.Bodies) var elseOp Op if n.ElseBody != nil { elseOp = cp.chunk(n.ElseBody) } return func(ec *EvalCtx) { for i, condOp := range condOps { if condOp(ec)[0].(Error).inner == nil { bodyOps[i](ec) return } } if elseOp != nil { elseOp(ec) } } case parse.WhileControl: condOp := cp.errorCapture(n.Condition) bodyOp := cp.chunk(n.Body) return func(ec *EvalCtx) { for condOp(ec)[0].(Error).inner == nil { ex := ec.PEval(bodyOp) if ex == Continue { // do nothing } else if ex == Break { break } else if ex != nil { throw(ex) } } } case parse.ForControl: 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}) ex := ec.PEval(bodyOp) if ex == Continue { // do nothing } else if ex == Break { break } else if ex != nil { throw(ex) } } } case parse.BeginControl: return cp.chunk(n.Body) default: cp.errorf(n.Begin(), "unknown ControlKind %s, compiler bug", n.Kind) panic("unreachable") } }
func (cp *compiler) controlOp(n *parse.Control) Op { return Op{cp.control(n), n.Begin(), n.End()} }
func (cp *compiler) control(n *parse.Control) OpFunc { switch n.Kind { case parse.IfControl: condOps := cp.chunkOps(n.Conditions) bodyOps := cp.chunkOps(n.Bodies) var elseOp Op if n.ElseBody != nil { elseOp = cp.chunkOp(n.ElseBody) } return func(ec *EvalCtx) { for i, condOp := range condOps { condOp.Exec(ec) if ec.verdict { bodyOps[i].Exec(ec) return } } if elseOp.Func != nil { elseOp.Exec(ec) } else { ec.verdict = true } } case parse.TryControl: Logger.Println("compiling a try control") bodyOp := cp.errorCaptureOp(n.Body) var exceptOp, elseOp ValuesOp var finallyOp Op var exceptVarOp LValuesOp if n.ExceptBody != nil { if n.ExceptVar != nil { var restOp LValuesOp exceptVarOp, restOp = cp.lvaluesOp(n.ExceptVar) if restOp.Func != nil { cp.errorpf(restOp.Begin, restOp.End, "may not use @rest in except variable") } } exceptOp = cp.errorCaptureOp(n.ExceptBody) } if n.ElseBody != nil { elseOp = cp.errorCaptureOp(n.ElseBody) } if n.FinallyBody != nil { finallyOp = cp.chunkOp(n.FinallyBody) } return func(ec *EvalCtx) { e := bodyOp.Exec(ec)[0].(Error).Inner Logger.Println("e is now", e) if e != nil { if exceptOp.Func != nil { if exceptVarOp.Func != nil { exceptVars := exceptVarOp.Exec(ec) if len(exceptVars) != 1 { throw(ErrArityMismatch) } exceptVars[0].Set(Error{e}) } e = exceptOp.Exec(ec)[0].(Error).Inner Logger.Println("e is now", e) } } else { if elseOp.Func != nil { e = elseOp.Exec(ec)[0].(Error).Inner Logger.Println("e is now", e) } } if finallyOp.Func != nil { finallyOp.Exec(ec) } if e != nil { throw(e) } } case parse.WhileControl: condOp := cp.chunkOp(n.Condition) bodyOp := cp.chunkOp(n.Body) return func(ec *EvalCtx) { for { condOp.Exec(ec) if !ec.verdict { break } //for condOp.Exec(ec)[0].(Error).Inner == nil { ex := ec.PEval(bodyOp) if ex == Continue { // do nothing } else if ex == Break { break } else if ex != nil { throw(ex) } } ec.verdict = true } case parse.ForControl: iteratorOp, restOp := cp.lvaluesOp(n.Iterator) if restOp.Func != nil { cp.errorpf(restOp.Begin, restOp.End, "may not use @rest in iterator") } valuesOp := cp.arrayOp(n.Array) bodyOp := cp.chunkOp(n.Body) return func(ec *EvalCtx) { iterators := iteratorOp.Exec(ec) if len(iterators) != 1 { throw(ErrArityMismatch) } iterator := iterators[0] values := valuesOp.Exec(ec) for _, v := range values { iterator.Set(v) ex := ec.PEval(bodyOp) if ex == Continue { // do nothing } else if ex == Break { break } else if ex != nil { throw(ex) } } } case parse.BeginControl: return cp.chunk(n.Body) default: cp.errorpf(n.Begin(), n.End(), "unknown ControlKind %s, compiler bug", n.Kind) panic("unreachable") } }