2016-02-20 00:21:51 +08:00
|
|
|
package eval
|
|
|
|
|
|
|
|
import (
|
2016-02-20 00:33:55 +08:00
|
|
|
"fmt"
|
2020-04-26 20:14:51 +08:00
|
|
|
"io"
|
2016-02-20 00:33:55 +08:00
|
|
|
|
2019-12-24 04:00:59 +08:00
|
|
|
"github.com/elves/elvish/pkg/diag"
|
|
|
|
"github.com/elves/elvish/pkg/parse"
|
2016-02-20 00:21:51 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// compiler maintains the set of states needed when compiling a single source
|
|
|
|
// file.
|
|
|
|
type compiler struct {
|
2017-12-24 07:51:32 +08:00
|
|
|
// Builtin namespace.
|
2020-12-25 01:39:51 +08:00
|
|
|
builtin *staticNs
|
2017-12-24 07:51:32 +08:00
|
|
|
// Lexical namespaces.
|
2020-12-25 01:39:51 +08:00
|
|
|
scopes []*staticNs
|
|
|
|
// Sources of captured variables.
|
|
|
|
captures []*staticUpNs
|
2020-04-26 20:14:51 +08:00
|
|
|
// Destination of warning messages. This is currently only used for
|
|
|
|
// deprecation messages.
|
|
|
|
warn io.Writer
|
|
|
|
// Deprecation registry.
|
|
|
|
deprecations deprecationRegistry
|
2016-10-11 21:37:27 +08:00
|
|
|
// Information about the source.
|
2020-04-26 02:22:38 +08:00
|
|
|
srcMeta parse.Source
|
2016-02-20 00:21:51 +08:00
|
|
|
}
|
|
|
|
|
2020-12-25 01:39:51 +08:00
|
|
|
type capture struct {
|
|
|
|
name string
|
|
|
|
// If true, the captured variable is from the immediate outer level scope,
|
|
|
|
// i.e. the local scope the lambda is evaluated in. Otherwise the captured
|
|
|
|
// variable is from a more outer level, i.e. the upvalue scope the lambda is
|
|
|
|
// evaluated in.
|
|
|
|
local bool
|
|
|
|
// Index to the captured variable.
|
|
|
|
index int
|
|
|
|
}
|
|
|
|
|
2020-08-22 05:28:54 +08:00
|
|
|
// Op represents an operation on a Frame. It is the result of compiling a piece
|
|
|
|
// of source.
|
|
|
|
type Op struct {
|
|
|
|
Inner effectOp
|
|
|
|
Src parse.Source
|
|
|
|
}
|
|
|
|
|
2020-12-25 01:39:51 +08:00
|
|
|
func compile(b, g *staticNs, tree parse.Tree, w io.Writer) (op Op, err error) {
|
|
|
|
g = g.clone()
|
|
|
|
gLenInit := len(g.names)
|
2020-04-26 20:14:51 +08:00
|
|
|
cp := &compiler{
|
2020-12-25 01:39:51 +08:00
|
|
|
b, []*staticNs{g}, []*staticUpNs{new(staticUpNs)},
|
2020-04-26 20:14:51 +08:00
|
|
|
w, newDeprecationRegistry(), tree.Source}
|
2020-01-13 06:55:17 +08:00
|
|
|
defer func() {
|
|
|
|
r := recover()
|
|
|
|
if r == nil {
|
|
|
|
return
|
2021-01-02 07:26:24 +08:00
|
|
|
} else if e := GetCompilationError(r); e != nil {
|
2020-01-13 06:55:17 +08:00
|
|
|
// Save the compilation error and stop the panic.
|
|
|
|
err = e
|
|
|
|
} else {
|
|
|
|
// Resume the panic; it is not supposed to be handled here.
|
|
|
|
panic(r)
|
|
|
|
}
|
|
|
|
}()
|
2020-04-27 02:04:49 +08:00
|
|
|
chunkOp := cp.chunkOp(tree.Root)
|
2020-12-25 01:39:51 +08:00
|
|
|
scopeOp := wrapScopeOp(chunkOp, g.names[gLenInit:])
|
2020-04-27 02:04:49 +08:00
|
|
|
|
|
|
|
return Op{scopeOp, tree.Source}, nil
|
|
|
|
}
|
|
|
|
|
2020-03-29 04:34:52 +08:00
|
|
|
func (cp *compiler) errorpf(r diag.Ranger, format string, args ...interface{}) {
|
2020-01-13 06:55:17 +08:00
|
|
|
// The panic is caught by the recover in compile above.
|
|
|
|
panic(NewCompilationError(fmt.Sprintf(format, args...),
|
2020-03-29 06:11:23 +08:00
|
|
|
*diag.NewContext(cp.srcMeta.Name, cp.srcMeta.Code, r)))
|
2016-02-20 04:16:23 +08:00
|
|
|
}
|
|
|
|
|
2020-12-25 01:39:51 +08:00
|
|
|
func (cp *compiler) thisScope() *staticNs {
|
2016-02-20 00:21:51 +08:00
|
|
|
return cp.scopes[len(cp.scopes)-1]
|
|
|
|
}
|
|
|
|
|
2020-12-25 01:39:51 +08:00
|
|
|
func (cp *compiler) pushScope() (*staticNs, *staticUpNs) {
|
|
|
|
sc := new(staticNs)
|
|
|
|
up := new(staticUpNs)
|
2016-02-20 00:21:51 +08:00
|
|
|
cp.scopes = append(cp.scopes, sc)
|
2020-12-25 01:39:51 +08:00
|
|
|
cp.captures = append(cp.captures, up)
|
|
|
|
return sc, up
|
2016-02-20 00:21:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cp *compiler) popScope() {
|
2020-12-25 01:39:51 +08:00
|
|
|
cp.scopes[len(cp.scopes)-1] = nil
|
2016-02-20 00:21:51 +08:00
|
|
|
cp.scopes = cp.scopes[:len(cp.scopes)-1]
|
2020-12-25 01:39:51 +08:00
|
|
|
cp.captures[len(cp.captures)-1] = nil
|
|
|
|
cp.captures = cp.captures[:len(cp.captures)-1]
|
2020-04-26 20:14:51 +08:00
|
|
|
}
|