lang: Misc changes from an old feature branch

This commit is contained in:
James Shubin
2022-08-04 14:49:24 -04:00
parent 12ae44d563
commit ac39606386
5 changed files with 60 additions and 14 deletions

View File

@@ -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")
}

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}