Beispiel #1
0
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")
	}
}
Beispiel #2
0
func (cp *compiler) controlOp(n *parse.Control) Op {
	return Op{cp.control(n), n.Begin(), n.End()}
}
Beispiel #3
0
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")
	}
}