mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-12 17:27:50 +08:00
Export eval.Closure and (*eval.Frame).Fork.
This commit is contained in:
parent
4906c4aa28
commit
d9e14da0db
|
@ -84,7 +84,7 @@ func runParallel(fm *Frame, functions ...Callable) error {
|
|||
*pexc = err.(Exception)
|
||||
}
|
||||
wg.Done()
|
||||
}(fm.fork("[run-parallel function]"), function, &exceptions[i])
|
||||
}(fm.Fork("[run-parallel function]"), function, &exceptions[i])
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
@ -130,7 +130,7 @@ func each(fm *Frame, f Callable, inputs Inputs) error {
|
|||
if broken {
|
||||
return
|
||||
}
|
||||
newFm := fm.fork("closure of each")
|
||||
newFm := fm.Fork("closure of each")
|
||||
ex := f.Call(newFm, []interface{}{v}, NoOpts)
|
||||
newFm.Close()
|
||||
|
||||
|
@ -201,7 +201,7 @@ func peach(fm *Frame, f Callable, inputs Inputs) error {
|
|||
}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
newFm := fm.fork("closure of peach")
|
||||
newFm := fm.Fork("closure of peach")
|
||||
newFm.ports[0] = DummyInputPort
|
||||
ex := f.Call(newFm, []interface{}{v}, NoOpts)
|
||||
newFm.Close()
|
||||
|
|
|
@ -185,7 +185,7 @@ func call(fm *Frame, fn Callable, argsVal vals.List, optsVal vals.Map) error {
|
|||
}
|
||||
opts[ks] = v
|
||||
}
|
||||
return fn.Call(fm.fork("-call"), args, opts)
|
||||
return fn.Call(fm.Fork("-call"), args, opts)
|
||||
}
|
||||
|
||||
//elvdoc:fn resolve
|
||||
|
@ -294,7 +294,7 @@ func eval(fm *Frame, opts evalOpts, code string) error {
|
|||
// nil as the second argument.
|
||||
newNs, exc := fm.Eval(src, nil, ns)
|
||||
if opts.OnEnd != nil {
|
||||
newFm := fm.fork("on-end callback of eval")
|
||||
newFm := fm.Fork("on-end callback of eval")
|
||||
errCb := opts.OnEnd.Call(newFm, []interface{}{newNs}, NoOpts)
|
||||
if exc == nil {
|
||||
return errCb
|
||||
|
@ -518,7 +518,7 @@ func timeCmd(fm *Frame, opts timeOpt, f Callable) error {
|
|||
|
||||
dt := t1.Sub(t0)
|
||||
if opts.OnEnd != nil {
|
||||
newFm := fm.fork("on-end callback of time")
|
||||
newFm := fm.Fork("on-end callback of time")
|
||||
errCb := opts.OnEnd.Call(newFm, []interface{}{dt.Seconds()}, NoOpts)
|
||||
if err == nil {
|
||||
err = errCb
|
||||
|
|
|
@ -209,7 +209,7 @@ func eawk(fm *Frame, f Callable, inputs Inputs) error {
|
|||
args = append(args, field)
|
||||
}
|
||||
|
||||
newFm := fm.fork("fn of eawk")
|
||||
newFm := fm.Fork("fn of eawk")
|
||||
// TODO: Close port 0 of newFm.
|
||||
ex := f.Call(newFm, args, NoOpts)
|
||||
newFm.Close()
|
||||
|
|
|
@ -252,8 +252,8 @@ func (op fnOp) exec(fm *Frame) Exception {
|
|||
if exc != nil {
|
||||
return exc
|
||||
}
|
||||
c := values[0].(*closure)
|
||||
c.Op = fnWrap{c.Op}
|
||||
c := values[0].(*Closure)
|
||||
c.op = fnWrap{c.op}
|
||||
return fm.errorp(op.keywordRange, fm.local.slots[op.varIndex].Set(c))
|
||||
}
|
||||
|
||||
|
@ -520,16 +520,16 @@ func (op *ifOp) exec(fm *Frame) Exception {
|
|||
}
|
||||
elseFn := execLambdaOp(fm, op.elseOp)
|
||||
for i, condOp := range op.condOps {
|
||||
condValues, exc := condOp.exec(fm.fork("if cond"))
|
||||
condValues, exc := condOp.exec(fm.Fork("if cond"))
|
||||
if exc != nil {
|
||||
return exc
|
||||
}
|
||||
if allTrue(condValues) {
|
||||
return fm.errorp(op, bodies[i].Call(fm.fork("if body"), NoArgs, NoOpts))
|
||||
return fm.errorp(op, bodies[i].Call(fm.Fork("if body"), NoArgs, NoOpts))
|
||||
}
|
||||
}
|
||||
if op.elseOp != nil {
|
||||
return fm.errorp(op, elseFn.Call(fm.fork("if else"), NoArgs, NoOpts))
|
||||
return fm.errorp(op, elseFn.Call(fm.Fork("if else"), NoArgs, NoOpts))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -562,7 +562,7 @@ func (op *whileOp) exec(fm *Frame) Exception {
|
|||
|
||||
iterated := false
|
||||
for {
|
||||
condValues, exc := op.condOp.exec(fm.fork("while cond"))
|
||||
condValues, exc := op.condOp.exec(fm.Fork("while cond"))
|
||||
if exc != nil {
|
||||
return exc
|
||||
}
|
||||
|
@ -570,7 +570,7 @@ func (op *whileOp) exec(fm *Frame) Exception {
|
|||
break
|
||||
}
|
||||
iterated = true
|
||||
err := body.Call(fm.fork("while"), NoArgs, NoOpts)
|
||||
err := body.Call(fm.Fork("while"), NoArgs, NoOpts)
|
||||
if err != nil {
|
||||
exc := err.(Exception)
|
||||
if exc.Reason() == Continue {
|
||||
|
@ -584,7 +584,7 @@ func (op *whileOp) exec(fm *Frame) Exception {
|
|||
}
|
||||
|
||||
if op.elseOp != nil && !iterated {
|
||||
return fm.errorp(op, elseBody.Call(fm.fork("while else"), NoArgs, NoOpts))
|
||||
return fm.errorp(op, elseBody.Call(fm.Fork("while else"), NoArgs, NoOpts))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ func (op *forOp) exec(fm *Frame) Exception {
|
|||
errElement = err
|
||||
return false
|
||||
}
|
||||
err = body.Call(fm.fork("for"), NoArgs, NoOpts)
|
||||
err = body.Call(fm.Fork("for"), NoArgs, NoOpts)
|
||||
if err != nil {
|
||||
exc := err.(Exception)
|
||||
if exc.Reason() == Continue {
|
||||
|
@ -661,7 +661,7 @@ func (op *forOp) exec(fm *Frame) Exception {
|
|||
}
|
||||
|
||||
if !iterated && elseBody != nil {
|
||||
return fm.errorp(op, elseBody.Call(fm.fork("for else"), NoArgs, NoOpts))
|
||||
return fm.errorp(op, elseBody.Call(fm.Fork("for else"), NoArgs, NoOpts))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -729,7 +729,7 @@ func (op *tryOp) exec(fm *Frame) Exception {
|
|||
elseFn := execLambdaOp(fm, op.elseOp)
|
||||
finally := execLambdaOp(fm, op.finallyOp)
|
||||
|
||||
err := body.Call(fm.fork("try body"), NoArgs, NoOpts)
|
||||
err := body.Call(fm.Fork("try body"), NoArgs, NoOpts)
|
||||
if err != nil {
|
||||
if except != nil {
|
||||
if exceptVar != nil {
|
||||
|
@ -738,15 +738,15 @@ func (op *tryOp) exec(fm *Frame) Exception {
|
|||
return fm.errorp(op.exceptVar, err)
|
||||
}
|
||||
}
|
||||
err = except.Call(fm.fork("try except"), NoArgs, NoOpts)
|
||||
err = except.Call(fm.Fork("try except"), NoArgs, NoOpts)
|
||||
}
|
||||
} else {
|
||||
if elseFn != nil {
|
||||
err = elseFn.Call(fm.fork("try else"), NoArgs, NoOpts)
|
||||
err = elseFn.Call(fm.Fork("try else"), NoArgs, NoOpts)
|
||||
}
|
||||
}
|
||||
if finally != nil {
|
||||
errFinally := finally.Call(fm.fork("try finally"), NoArgs, NoOpts)
|
||||
errFinally := finally.Call(fm.Fork("try finally"), NoArgs, NoOpts)
|
||||
if errFinally != nil {
|
||||
// TODO: If err is not nil, this discards err. Use something similar
|
||||
// to pipeline exception to expose both.
|
||||
|
|
|
@ -15,44 +15,45 @@ import (
|
|||
"src.elv.sh/pkg/persistent/hash"
|
||||
)
|
||||
|
||||
// A user-defined function in Elvish code. Each closure has its unique identity.
|
||||
type closure struct {
|
||||
// Closure is a function defined with Elvish code. Each Closure has its unique
|
||||
// identity.
|
||||
type Closure struct {
|
||||
ArgNames []string
|
||||
// The index of the rest argument. -1 if there is no rest argument.
|
||||
RestArg int
|
||||
OptNames []string
|
||||
OptDefaults []interface{}
|
||||
Op effectOp
|
||||
NewLocal []staticVarInfo
|
||||
Captured *Ns
|
||||
SrcMeta parse.Source
|
||||
DefRange diag.Ranging
|
||||
op effectOp
|
||||
newLocal []staticVarInfo
|
||||
captured *Ns
|
||||
}
|
||||
|
||||
var _ Callable = &closure{}
|
||||
var _ Callable = &Closure{}
|
||||
|
||||
// Kind returns "fn".
|
||||
func (*closure) Kind() string {
|
||||
func (*Closure) Kind() string {
|
||||
return "fn"
|
||||
}
|
||||
|
||||
// Equal compares by address.
|
||||
func (c *closure) Equal(rhs interface{}) bool {
|
||||
func (c *Closure) Equal(rhs interface{}) bool {
|
||||
return c == rhs
|
||||
}
|
||||
|
||||
// Hash returns the hash of the address of the closure.
|
||||
func (c *closure) Hash() uint32 {
|
||||
func (c *Closure) Hash() uint32 {
|
||||
return hash.Pointer(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
// Repr returns an opaque representation "<closure 0x23333333>".
|
||||
func (c *closure) Repr(int) string {
|
||||
func (c *Closure) Repr(int) string {
|
||||
return fmt.Sprintf("<closure %p>", c)
|
||||
}
|
||||
|
||||
// Call calls a closure.
|
||||
func (c *closure) Call(fm *Frame, args []interface{}, opts map[string]interface{}) error {
|
||||
func (c *Closure) Call(fm *Frame, args []interface{}, opts map[string]interface{}) error {
|
||||
// Check number of arguments.
|
||||
if c.RestArg != -1 {
|
||||
if len(args) < len(c.ArgNames)-1 {
|
||||
|
@ -93,10 +94,10 @@ func (c *closure) Call(fm *Frame, args []interface{}, opts map[string]interface{
|
|||
// and ports can be problematic.
|
||||
|
||||
// Make upvalue namespace and capture variables.
|
||||
fm.up = c.Captured
|
||||
fm.up = c.captured
|
||||
|
||||
// Populate local scope with arguments, options, and newly created locals.
|
||||
localSize := len(c.ArgNames) + len(c.OptNames) + len(c.NewLocal)
|
||||
localSize := len(c.ArgNames) + len(c.OptNames) + len(c.newLocal)
|
||||
local := &Ns{make([]vars.Var, localSize), make([]staticVarInfo, localSize)}
|
||||
|
||||
for i, name := range c.ArgNames {
|
||||
|
@ -129,7 +130,7 @@ func (c *closure) Call(fm *Frame, args []interface{}, opts map[string]interface{
|
|||
}
|
||||
|
||||
offset += len(c.OptNames)
|
||||
for i, info := range c.NewLocal {
|
||||
for i, info := range c.newLocal {
|
||||
local.infos[offset+i] = info
|
||||
// TODO: Take info.readOnly into account too when creating variable
|
||||
local.slots[offset+i] = MakeVarFromName(info.name)
|
||||
|
@ -138,7 +139,7 @@ func (c *closure) Call(fm *Frame, args []interface{}, opts map[string]interface{
|
|||
fm.local = local
|
||||
fm.srcMeta = c.SrcMeta
|
||||
fm.defers = new([]func(*Frame) Exception)
|
||||
exc := c.Op.exec(fm)
|
||||
exc := c.op.exec(fm)
|
||||
excDefer := fm.runDefers()
|
||||
// TODO: Combine exc and excDefer if both are not nil
|
||||
if excDefer != nil && exc == nil {
|
||||
|
@ -180,9 +181,9 @@ func (er UnsupportedOptionsError) Error() string {
|
|||
return fmt.Sprintf("unsupported options: %s", strings.Join(er.Options, ", "))
|
||||
}
|
||||
|
||||
func (c *closure) Fields() vals.StructMap { return closureFields{c} }
|
||||
func (c *Closure) Fields() vals.StructMap { return closureFields{c} }
|
||||
|
||||
type closureFields struct{ c *closure }
|
||||
type closureFields struct{ c *Closure }
|
||||
|
||||
func (closureFields) IsStructMap() {}
|
||||
|
||||
|
@ -196,7 +197,7 @@ func (cf closureFields) OptDefaults() vals.List {
|
|||
}
|
||||
|
||||
func (cf closureFields) Body() string {
|
||||
r := cf.c.Op.(diag.Ranger).Range()
|
||||
r := cf.c.op.(diag.Ranger).Range()
|
||||
return cf.c.SrcMeta.Code[r.From:r.To]
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ func (op *pipelineOp) exec(fm *Frame) Exception {
|
|||
}
|
||||
|
||||
if op.bg {
|
||||
fm = fm.fork("background job" + op.source)
|
||||
fm = fm.Fork("background job" + op.source)
|
||||
fm.intCh = nil
|
||||
fm.background = true
|
||||
fm.Evaler.addNumBgJobs(1)
|
||||
|
@ -88,7 +88,7 @@ func (op *pipelineOp) exec(fm *Frame) Exception {
|
|||
|
||||
// For each form, create a dedicated evalCtx and run asynchronously
|
||||
for i, formOp := range op.subops {
|
||||
newFm := fm.fork("[form op]")
|
||||
newFm := fm.Fork("[form op]")
|
||||
inputIsPipe := i > 0
|
||||
outputIsPipe := i < nforms-1
|
||||
if inputIsPipe {
|
||||
|
|
|
@ -468,7 +468,7 @@ func (op *lambdaOp) exec(fm *Frame) ([]interface{}, Exception) {
|
|||
}
|
||||
optDefaults[i] = defaultValue
|
||||
}
|
||||
return []interface{}{&closure{op.argNames, op.restArg, op.optNames, optDefaults, op.subop, op.newLocal, capture, op.srcMeta, op.Range()}}, nil
|
||||
return []interface{}{&Closure{op.argNames, op.restArg, op.optNames, optDefaults, op.srcMeta, op.Range(), op.subop, op.newLocal, capture}}, nil
|
||||
}
|
||||
|
||||
type mapOp struct {
|
||||
|
|
|
@ -154,9 +154,9 @@ func linesToChan(r io.Reader, ch chan<- interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// fork returns a modified copy of ec. The ports are forked, and the name is
|
||||
// Fork returns a modified copy of fm. The ports are forked, and the name is
|
||||
// changed to the given value. Other fields are copied shallowly.
|
||||
func (fm *Frame) fork(name string) *Frame {
|
||||
func (fm *Frame) Fork(name string) *Frame {
|
||||
newPorts := make([]*Port, len(fm.ports))
|
||||
for i, p := range fm.ports {
|
||||
if p != nil {
|
||||
|
@ -173,7 +173,7 @@ func (fm *Frame) fork(name string) *Frame {
|
|||
|
||||
// A shorthand for forking a frame and setting the output port.
|
||||
func (fm *Frame) forkWithOutput(name string, p *Port) *Frame {
|
||||
newFm := fm.fork(name)
|
||||
newFm := fm.Fork(name)
|
||||
newFm.ports[1] = p
|
||||
return newFm
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user