2021-12-28 20:18:01 +00:00
|
|
|
package vm
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/mediocregopher/ginger/gg"
|
|
|
|
)
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
// Scope encapsulates a set of name->Value mappings.
|
2021-12-28 20:18:01 +00:00
|
|
|
type Scope interface {
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
// Resolve accepts a name and returns an Value.
|
|
|
|
Resolve(string) (Value, error)
|
2021-12-28 20:18:01 +00:00
|
|
|
|
|
|
|
// NewScope returns a new Scope which sub-operations within this Scope
|
|
|
|
// should use for themselves.
|
|
|
|
NewScope() Scope
|
|
|
|
}
|
|
|
|
|
|
|
|
// ScopeMap implements the Scope interface.
|
|
|
|
type ScopeMap map[string]Value
|
|
|
|
|
|
|
|
var _ Scope = ScopeMap{}
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
// Resolve uses the given name as a key into the ScopeMap map, and
|
|
|
|
// returns the Operation held there for the key, if any.
|
|
|
|
func (m ScopeMap) Resolve(name string) (Value, error) {
|
2021-12-28 20:18:01 +00:00
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
v, ok := m[name]
|
2021-12-28 20:18:01 +00:00
|
|
|
|
|
|
|
if !ok {
|
2022-03-31 15:18:02 +00:00
|
|
|
return Value{}, fmt.Errorf("%q not defined", name)
|
2021-12-28 20:18:01 +00:00
|
|
|
}
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
return v, nil
|
2021-12-28 20:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewScope returns the ScopeMap as-is.
|
|
|
|
func (m ScopeMap) NewScope() Scope {
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
type scopeWith struct {
|
|
|
|
Scope // parent
|
|
|
|
name string
|
|
|
|
val Value
|
|
|
|
}
|
|
|
|
|
|
|
|
// ScopeWith returns a copy of the given Scope, except that evaluating the given
|
|
|
|
// name will always return the given Value.
|
|
|
|
func ScopeWith(scope Scope, name string, val Value) Scope {
|
|
|
|
return &scopeWith{
|
|
|
|
Scope: scope,
|
|
|
|
name: name,
|
|
|
|
val: val,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *scopeWith) Resolve(name string) (Value, error) {
|
|
|
|
if name == s.name {
|
|
|
|
return s.val, nil
|
|
|
|
}
|
|
|
|
return s.Scope.Resolve(name)
|
|
|
|
}
|
|
|
|
|
2021-12-28 20:18:01 +00:00
|
|
|
type graphScope struct {
|
2021-12-30 16:56:20 +00:00
|
|
|
*gg.Graph
|
2021-12-28 20:18:01 +00:00
|
|
|
parent Scope
|
|
|
|
}
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
/*
|
|
|
|
|
|
|
|
TODO I don't think this is actually necessary
|
|
|
|
|
|
|
|
// ScopeFromGraph returns a Scope which will use the given Graph for name
|
|
|
|
// resolution.
|
2021-12-28 20:18:01 +00:00
|
|
|
//
|
2022-03-31 15:18:02 +00:00
|
|
|
// When a name is resolved, that name will be looked up in the Graph. The name's
|
|
|
|
// vertex must have only a single OpenEdge leading to it. That edge will be
|
|
|
|
// compiled into an Operation and returned.
|
2021-12-30 21:00:04 +00:00
|
|
|
//
|
2021-12-28 20:18:01 +00:00
|
|
|
// If a name does not appear in the Graph, then the given parent Scope will be
|
2022-03-31 15:18:02 +00:00
|
|
|
// used to resolve that name. If the parent Scope is nil then an error is
|
2021-12-28 20:18:01 +00:00
|
|
|
// returned.
|
|
|
|
//
|
|
|
|
// NewScope will return the parent scope, if one is given, or an empty ScopeMap
|
|
|
|
// if not.
|
2022-03-31 15:18:02 +00:00
|
|
|
func ScopeFromGraph(g *gg.Graph, parent Scope) Scope {
|
2021-12-28 20:18:01 +00:00
|
|
|
return &graphScope{
|
|
|
|
Graph: g,
|
|
|
|
parent: parent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
func (g *graphScope) Resolve(name string) (Value, error) {
|
2021-12-28 20:18:01 +00:00
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
var ggNameVal gg.Value
|
|
|
|
ggNameVal.Name = &name
|
2021-12-28 20:18:01 +00:00
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
log.Printf("resolving %q", name)
|
|
|
|
edgesIn := g.ValueIns(ggNameVal)
|
2021-12-28 20:18:01 +00:00
|
|
|
|
|
|
|
if l := len(edgesIn); l == 0 && g.parent != nil {
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
return g.parent.Resolve(name)
|
2021-12-28 20:18:01 +00:00
|
|
|
|
|
|
|
} else if l != 1 {
|
|
|
|
|
2021-12-30 21:00:04 +00:00
|
|
|
return nil, fmt.Errorf(
|
2021-12-28 20:18:01 +00:00
|
|
|
"%q must have exactly one input edge, found %d input edges",
|
2022-03-31 15:18:02 +00:00
|
|
|
name, l,
|
2021-12-28 20:18:01 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-03-31 15:18:02 +00:00
|
|
|
return CompileEdge(edgesIn[0], g)
|
2021-12-28 20:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *graphScope) NewScope() Scope {
|
|
|
|
|
|
|
|
if g.parent == nil {
|
|
|
|
return ScopeMap{}
|
|
|
|
}
|
|
|
|
|
|
|
|
return g.parent
|
|
|
|
}
|
2022-03-31 15:18:02 +00:00
|
|
|
|
|
|
|
*/
|