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...")
|
logf("interpolating...")
|
||||||
// interpolate strings and other expansionable nodes in AST
|
// interpolate strings and other expansionable nodes in AST
|
||||||
interpolated, err := xast.Interpolate()
|
iast, err := xast.Interpolate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errwrap.Wrapf(err, "could not interpolate AST")
|
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
|
// operation should not depend on any initial scope values, since those
|
||||||
// would all be runtime changes, and we do not support dynamic imports,
|
// 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!
|
// 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")
|
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...")
|
logf("running type unification...")
|
||||||
unifier := &unification.Unifier{
|
unifier := &unification.Unifier{
|
||||||
AST: interpolated,
|
AST: iast,
|
||||||
Solver: unification.SimpleInvariantSolverLogger(unificationLogf),
|
Solver: unification.SimpleInvariantSolverLogger(unificationLogf),
|
||||||
Debug: debug,
|
Debug: debug,
|
||||||
Logf: unificationLogf,
|
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)
|
// get the list of needed files (this is available after SetScope)
|
||||||
fileList, err := ast.CollectFiles(interpolated)
|
fileList, err := ast.CollectFiles(iast)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errwrap.Wrapf(err, "could not collect files")
|
return nil, errwrap.Wrapf(err, "could not collect files")
|
||||||
}
|
}
|
||||||
@@ -743,7 +743,7 @@ func (obj *GAPI) Get(getInfo *gapi.GetInfo) error {
|
|||||||
|
|
||||||
logf("interpolating...")
|
logf("interpolating...")
|
||||||
// interpolate strings and other expansionable nodes in AST
|
// interpolate strings and other expansionable nodes in AST
|
||||||
interpolated, err := ast.Interpolate()
|
iast, err := ast.Interpolate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errwrap.Wrapf(err, "could not interpolate AST")
|
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
|
// 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
|
// operation shouldn't depend on any initial scope values, since those
|
||||||
// would all be runtime changes, and we do not support dynamic imports!
|
// 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")
|
return errwrap.Wrapf(err, "could not set scope")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ import (
|
|||||||
"github.com/purpleidea/mgmt/lang/types"
|
"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
|
// 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
|
// used for static analysis and type checking. If you break this contract, you
|
||||||
// might cause a panic.
|
// might cause a panic.
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import (
|
|||||||
// ExprAny is a placeholder expression that is used for type unification hacks.
|
// ExprAny is a placeholder expression that is used for type unification hacks.
|
||||||
type ExprAny struct {
|
type ExprAny struct {
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
|
|
||||||
|
V types.Value // stored value (set with SetValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a short representation of this expression.
|
// 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) {
|
func (obj *ExprAny) Interpolate() (Expr, error) {
|
||||||
return &ExprAny{
|
return &ExprAny{
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
|
V: obj.V,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,15 +88,30 @@ func (obj *ExprAny) SetType(typ *types.Type) error {
|
|||||||
if obj.typ != nil {
|
if obj.typ != nil {
|
||||||
return obj.typ.Cmp(typ) // if not set, ensure it doesn't change
|
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
|
obj.typ = typ // set
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns the type of this expression.
|
// Type returns the type of this expression.
|
||||||
func (obj *ExprAny) Type() (*types.Type, error) {
|
func (obj *ExprAny) Type() (*types.Type, error) {
|
||||||
if obj.typ == nil {
|
if obj.typ == nil && obj.V == nil {
|
||||||
return nil, ErrTypeCurrentlyUnknown
|
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
|
return obj.typ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +124,8 @@ func (obj *ExprAny) Unify() ([]Invariant, error) {
|
|||||||
Expr: obj,
|
Expr: obj,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
// TODO: should we return an EqualsInvariant with obj.typ ?
|
||||||
|
// TODO: should we return a ValueInvariant with obj.V ?
|
||||||
return invariants, nil
|
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 returns the reactive stream of values that this expression produces.
|
||||||
func (obj *ExprAny) Func() (Func, error) {
|
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
|
// 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
|
// 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
|
// 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!
|
// 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 {
|
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
|
// 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.
|
// 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.
|
// This might get called speculatively (early) during unification to learn more.
|
||||||
func (obj *ExprAny) Value() (types.Value, error) {
|
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...")
|
obj.Logf("interpolating...")
|
||||||
// interpolate strings and other expansionable nodes in AST
|
// interpolate strings and other expansionable nodes in AST
|
||||||
interpolated, err := xast.Interpolate()
|
iast, err := xast.Interpolate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errwrap.Wrapf(err, "could not interpolate AST")
|
return errwrap.Wrapf(err, "could not interpolate AST")
|
||||||
}
|
}
|
||||||
obj.ast = interpolated
|
obj.ast = iast
|
||||||
|
|
||||||
variables := map[string]interfaces.Expr{
|
variables := map[string]interfaces.Expr{
|
||||||
"purpleidea": &ast.ExprStr{V: "hello world!"}, // james says hi
|
"purpleidea": &ast.ExprStr{V: "hello world!"}, // james says hi
|
||||||
@@ -301,7 +301,7 @@ func (obj *Lang) Init() error {
|
|||||||
select {
|
select {
|
||||||
case obj.streamChan <- err: // send
|
case obj.streamChan <- err: // send
|
||||||
if err != nil {
|
if err != nil {
|
||||||
obj.Logf("Stream error: %+v", err)
|
obj.Logf("stream error: %+v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -888,7 +888,10 @@ Loop:
|
|||||||
logf("%s: unsolved equality: %+v", Name, x)
|
logf("%s: unsolved equality: %+v", Name, x)
|
||||||
}
|
}
|
||||||
for x := range unsolved {
|
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
|
return nil, ErrAmbiguous
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user