lang: Misc changes from an old feature branch
This commit is contained in:
@@ -270,7 +270,7 @@ func (obj *GAPI) Cli(cliInfo *gapi.CliInfo) (*gapi.Deploy, error) {
|
||||
|
||||
logf("interpolating...")
|
||||
// interpolate strings and other expansionable nodes in AST
|
||||
interpolated, err := xast.Interpolate()
|
||||
iast, err := xast.Interpolate()
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf(err, "could not interpolate AST")
|
||||
}
|
||||
@@ -301,7 +301,7 @@ func (obj *GAPI) Cli(cliInfo *gapi.CliInfo) (*gapi.Deploy, error) {
|
||||
// operation should not depend on any initial scope values, since those
|
||||
// would all be runtime changes, and we do not support dynamic imports,
|
||||
// however, we need to since we're doing type unification to err early!
|
||||
if err := interpolated.SetScope(scope); err != nil { // empty initial scope!
|
||||
if err := iast.SetScope(scope); err != nil { // empty initial scope!
|
||||
return nil, errwrap.Wrapf(err, "could not set scope")
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ func (obj *GAPI) Cli(cliInfo *gapi.CliInfo) (*gapi.Deploy, error) {
|
||||
}
|
||||
logf("running type unification...")
|
||||
unifier := &unification.Unifier{
|
||||
AST: interpolated,
|
||||
AST: iast,
|
||||
Solver: unification.SimpleInvariantSolverLogger(unificationLogf),
|
||||
Debug: debug,
|
||||
Logf: unificationLogf,
|
||||
@@ -323,7 +323,7 @@ func (obj *GAPI) Cli(cliInfo *gapi.CliInfo) (*gapi.Deploy, error) {
|
||||
}
|
||||
|
||||
// get the list of needed files (this is available after SetScope)
|
||||
fileList, err := ast.CollectFiles(interpolated)
|
||||
fileList, err := ast.CollectFiles(iast)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf(err, "could not collect files")
|
||||
}
|
||||
@@ -743,7 +743,7 @@ func (obj *GAPI) Get(getInfo *gapi.GetInfo) error {
|
||||
|
||||
logf("interpolating...")
|
||||
// interpolate strings and other expansionable nodes in AST
|
||||
interpolated, err := ast.Interpolate()
|
||||
iast, err := ast.Interpolate()
|
||||
if err != nil {
|
||||
return errwrap.Wrapf(err, "could not interpolate AST")
|
||||
}
|
||||
@@ -754,7 +754,8 @@ func (obj *GAPI) Get(getInfo *gapi.GetInfo) error {
|
||||
// don't think we need to pass in an initial scope because the download
|
||||
// operation shouldn't depend on any initial scope values, since those
|
||||
// would all be runtime changes, and we do not support dynamic imports!
|
||||
if err := interpolated.SetScope(nil); err != nil { // empty initial scope!
|
||||
// XXX Add non-empty scope?
|
||||
if err := iast.SetScope(nil); err != nil { // empty initial scope!
|
||||
return errwrap.Wrapf(err, "could not set scope")
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ import (
|
||||
"github.com/purpleidea/mgmt/lang/types"
|
||||
)
|
||||
|
||||
// FuncSig is the simple signature that is used throughout our implementations.
|
||||
type FuncSig = func([]types.Value) (types.Value, error)
|
||||
|
||||
// Info is a static representation of some information about the function. It is
|
||||
// used for static analysis and type checking. If you break this contract, you
|
||||
// might cause a panic.
|
||||
|
||||
@@ -28,6 +28,8 @@ import (
|
||||
// ExprAny is a placeholder expression that is used for type unification hacks.
|
||||
type ExprAny struct {
|
||||
typ *types.Type
|
||||
|
||||
V types.Value // stored value (set with SetValue)
|
||||
}
|
||||
|
||||
// String returns a short representation of this expression.
|
||||
@@ -51,6 +53,7 @@ func (obj *ExprAny) Init(*Data) error { return nil }
|
||||
func (obj *ExprAny) Interpolate() (Expr, error) {
|
||||
return &ExprAny{
|
||||
typ: obj.typ,
|
||||
V: obj.V,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -85,15 +88,30 @@ func (obj *ExprAny) SetType(typ *types.Type) error {
|
||||
if obj.typ != nil {
|
||||
return obj.typ.Cmp(typ) // if not set, ensure it doesn't change
|
||||
}
|
||||
if obj.V != nil {
|
||||
// if there's a value already, ensure the types are the same...
|
||||
if err := obj.V.Type().Cmp(typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
obj.typ = typ // set
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns the type of this expression.
|
||||
func (obj *ExprAny) Type() (*types.Type, error) {
|
||||
if obj.typ == nil {
|
||||
if obj.typ == nil && obj.V == nil {
|
||||
return nil, ErrTypeCurrentlyUnknown
|
||||
}
|
||||
if obj.typ != nil && obj.V != nil {
|
||||
if err := obj.V.Type().Cmp(obj.typ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.typ, nil
|
||||
}
|
||||
if obj.V != nil {
|
||||
return obj.V.Type(), nil
|
||||
}
|
||||
return obj.typ, nil
|
||||
}
|
||||
|
||||
@@ -106,6 +124,8 @@ func (obj *ExprAny) Unify() ([]Invariant, error) {
|
||||
Expr: obj,
|
||||
},
|
||||
}
|
||||
// TODO: should we return an EqualsInvariant with obj.typ ?
|
||||
// TODO: should we return a ValueInvariant with obj.V ?
|
||||
return invariants, nil
|
||||
}
|
||||
|
||||
@@ -127,20 +147,39 @@ func (obj *ExprAny) Graph() (*pgraph.Graph, error) {
|
||||
|
||||
// Func returns the reactive stream of values that this expression produces.
|
||||
func (obj *ExprAny) Func() (Func, error) {
|
||||
return nil, fmt.Errorf("programming error") // this should not be called
|
||||
// // XXX: this could be a list too, so improve this code or improve the subgraph code...
|
||||
// return &structs.ConstFunc{
|
||||
// Value: obj.V,
|
||||
// }
|
||||
|
||||
return nil, fmt.Errorf("programming error using ExprAny") // this should not be called
|
||||
}
|
||||
|
||||
// SetValue here is a no-op, because algorithmically when this is called from
|
||||
// the func engine, the child elements (the list elements) will have had this
|
||||
// done to them first, and as such when we try and retrieve the set value from
|
||||
// this expression by calling `Value`, it will build it from scratch!
|
||||
|
||||
// SetValue here is used to store a value for this expression node. This value
|
||||
// is cached and can be retrieved by calling Value.
|
||||
func (obj *ExprAny) SetValue(value types.Value) error {
|
||||
return fmt.Errorf("programming error") // this should not be called
|
||||
typ := value.Type()
|
||||
if obj.typ != nil {
|
||||
if err := obj.typ.Cmp(typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
obj.typ = typ
|
||||
obj.V = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns the value of this expression in our type system. This will
|
||||
// usually only be valid once the engine has run and values have been produced.
|
||||
// This might get called speculatively (early) during unification to learn more.
|
||||
func (obj *ExprAny) Value() (types.Value, error) {
|
||||
return nil, fmt.Errorf("programming error") // this should not be called
|
||||
if obj.V == nil {
|
||||
return nil, fmt.Errorf("value is not set")
|
||||
}
|
||||
return obj.V, nil
|
||||
}
|
||||
|
||||
@@ -164,11 +164,11 @@ func (obj *Lang) Init() error {
|
||||
|
||||
obj.Logf("interpolating...")
|
||||
// interpolate strings and other expansionable nodes in AST
|
||||
interpolated, err := xast.Interpolate()
|
||||
iast, err := xast.Interpolate()
|
||||
if err != nil {
|
||||
return errwrap.Wrapf(err, "could not interpolate AST")
|
||||
}
|
||||
obj.ast = interpolated
|
||||
obj.ast = iast
|
||||
|
||||
variables := map[string]interfaces.Expr{
|
||||
"purpleidea": &ast.ExprStr{V: "hello world!"}, // james says hi
|
||||
@@ -301,7 +301,7 @@ func (obj *Lang) Init() error {
|
||||
select {
|
||||
case obj.streamChan <- err: // send
|
||||
if err != nil {
|
||||
obj.Logf("Stream error: %+v", err)
|
||||
obj.Logf("stream error: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -888,7 +888,10 @@ Loop:
|
||||
logf("%s: unsolved equality: %+v", Name, x)
|
||||
}
|
||||
for x := range unsolved {
|
||||
logf("%s: unsolved expected: %+v", Name, x)
|
||||
logf("%s: unsolved expected: (%p) %+v", Name, x, x)
|
||||
}
|
||||
for expr, typ := range solved {
|
||||
logf("%s: solved: (%p) => %+v", Name, expr, typ)
|
||||
}
|
||||
return nil, ErrAmbiguous
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user