Skip to content

Commit

Permalink
lang: Plumb data and unification strategy through the lang struct
Browse files Browse the repository at this point in the history
This adds some plumbing to pass values into the lang struct.
  • Loading branch information
purpleidea committed Mar 30, 2024
1 parent cede7e5 commit ddf1be6
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 16 deletions.
5 changes: 3 additions & 2 deletions cli/util/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ type LangArgs struct {
OnlyDownload bool `arg:"--only-download" help:"stop after downloading any missing imports"`
Update bool `arg:"--update" help:"update all dependencies to the latest versions"`

OnlyUnify bool `arg:"--only-unify" help:"stop after type unification"`
SkipUnify bool `arg:"--skip-unify" help:"skip type unification"`
OnlyUnify bool `arg:"--only-unify" help:"stop after type unification"`
SkipUnify bool `arg:"--skip-unify" help:"skip type unification"`
UnifySolver *string `arg:"--unify-name" help:"pick a specific unification solver"`

Depth int `arg:"--depth" default:"-1" help:"max recursion depth limit (-1 is unlimited)"`

Expand Down
23 changes: 18 additions & 5 deletions lang/gapi/gapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func init() {
type GAPI struct {
InputURI string // input URI of code file system to run

// Data is some additional data for the lang struct.
Data *lang.Data

lang *lang.Lang // lang struct
wgRun *sync.WaitGroup
ctx context.Context
Expand Down Expand Up @@ -261,6 +264,11 @@ func (obj *GAPI) Cli(info *gapi.Info) (*gapi.Deploy, error) {
return nil, nil // success!
}

unificationStrategy := make(map[string]string)
if name := args.UnifySolver; name != nil && *name != "" {
unificationStrategy[unification.StrategyNameKey] = *name
}

if !args.SkipUnify {
// apply type unification
unificationLogf := func(format string, v ...interface{}) {
Expand All @@ -275,10 +283,11 @@ func (obj *GAPI) Cli(info *gapi.Info) (*gapi.Deploy, error) {
return nil, errwrap.Wrapf(err, "could not get default solver")
}
unifier := &unification.Unifier{
AST: iast,
Solver: solver,
Debug: debug,
Logf: unificationLogf,
AST: iast,
Solver: solver,
Strategy: unificationStrategy,
Debug: debug,
Logf: unificationLogf,
}
startTime := time.Now()
unifyErr := unifier.Unify(context.TODO())
Expand Down Expand Up @@ -411,7 +420,10 @@ func (obj *GAPI) Cli(info *gapi.Info) (*gapi.Deploy, error) {
Sema: info.Flags.Sema,
GAPI: &GAPI{
InputURI: fs.URI(),
// TODO: add properties here...
Data: &lang.Data{
UnificationStrategy: unificationStrategy,
// TODO: add properties here...
},
},
}, nil
}
Expand Down Expand Up @@ -451,6 +463,7 @@ func (obj *GAPI) LangInit(ctx context.Context) error {
Fs: fs,
FsURI: obj.InputURI,
Input: input,
Data: obj.Data,

Hostname: obj.data.Hostname,
Local: obj.data.Local,
Expand Down
38 changes: 32 additions & 6 deletions lang/lang.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ const (
EngineStartupStatsTimeout = 10
)

// Data is some data that is passed into the Lang struct. It is presented here
// as a single struct with room for multiple fields so that it can be changed or
// extended in the future without having to re-plumb through all the fields it
// contains
type Data struct {
// UnificationStrategy is a hack to tune unification performance until
// we have an overall cleaner unification algorithm in place.
UnificationStrategy map[string]string

// TODO: Add other fields here if necessary.
}

// Lang is the main language lexer/parser object.
type Lang struct {
Fs engine.Fs // connected fs where input dir or metadata exists
Expand All @@ -79,6 +91,9 @@ type Lang struct {
// run the raw string as mcl code.
Input string

// Data is some additional data for the lang struct.
Data *Data

Hostname string
Local *local.API
World engine.World
Expand All @@ -101,6 +116,12 @@ type Lang struct {
// watching them, *before* we pull their values, that way we'll know if they
// changed from the values we wanted.
func (obj *Lang) Init(ctx context.Context) error {
if obj.Data == nil {
return fmt.Errorf("lang struct was not built properly")
}
if obj.Data.UnificationStrategy == nil {
return fmt.Errorf("lang struct was not built properly")
}
if obj.Debug {
obj.Logf("input: %s", obj.Input)
tree, err := util.FsTree(obj.Fs, "/") // should look like gapi
Expand Down Expand Up @@ -227,15 +248,20 @@ func (obj *Lang) Init(ctx context.Context) error {
}
obj.Logf("running type unification...")

solver, err := unification.LookupDefault()
if err != nil {
var solver unification.Solver
if name, exists := obj.Data.UnificationStrategy["solver"]; exists && name != "" {
if solver, err = unification.Lookup(name); err != nil {
return errwrap.Wrapf(err, "could not get solver: %s", name)
}
} else if solver, err = unification.LookupDefault(); err != nil {
return errwrap.Wrapf(err, "could not get default solver")
}
unifier := &unification.Unifier{
AST: obj.ast,
Solver: solver,
Debug: obj.Debug,
Logf: logf,
AST: obj.ast,
Solver: solver,
Strategy: obj.Data.UnificationStrategy,
Debug: obj.Debug,
Logf: logf,
}
timing = time.Now()
// NOTE: This is the "real" Unify that runs. (This is not for deploy.)
Expand Down
5 changes: 4 additions & 1 deletion lang/lang_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ func runInterpret(t *testing.T, code string) (_ *pgraph.Graph, reterr error) {
lang := &Lang{
Fs: fs,
Input: "/" + interfaces.MetadataFilename, // start path in fs
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
Data: &Data{
UnificationStrategy: make(map[string]string), // empty
},
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
Logf: logf,
}
if err := lang.Init(ctx); err != nil {
Expand Down
7 changes: 7 additions & 0 deletions lang/unification/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,18 @@ const (
// ErrAmbiguous means we couldn't find a solution, but we weren't
// inconsistent.
ErrAmbiguous = interfaces.Error("can't unify, no equalities were consumed, we're ambiguous")

// StrategyNameKey is the string key used when choosing a solver name.
StrategyNameKey = "name"
)

// Init contains some handles that are used to initialize every solver. Each
// individual solver can choose to omit using some of the fields.
type Init struct {
// Strategy is a hack to tune unification performance until we have an
// overall cleaner unification algorithm in place.
Strategy map[string]string

Debug bool
Logf func(format string, v ...interface{})
}
Expand Down
2 changes: 2 additions & 0 deletions lang/unification/simplesolver/simplesolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type SimpleInvariantSolver struct {

// Init contains some handles that are used to initialize the solver.
func (obj *SimpleInvariantSolver) Init(init *unification.Init) error {
obj.Strategy = init.Strategy

obj.Debug = init.Debug
obj.Logf = init.Logf

Expand Down
9 changes: 7 additions & 2 deletions lang/unification/unification.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type Unifier struct {
// Solver is the solver algorithm implementation to use.
Solver Solver

// Strategy is a hack to tune unification performance until we have an
// overall cleaner unification algorithm in place.
Strategy map[string]string

Debug bool
Logf func(format string, v ...interface{})
}
Expand Down Expand Up @@ -76,8 +80,9 @@ func (obj *Unifier) Unify(ctx context.Context) error {
}

init := &Init{
Logf: obj.Logf,
Debug: obj.Debug,
Strategy: obj.Strategy,
Logf: obj.Logf,
Debug: obj.Debug,
}
if err := obj.Solver.Init(init); err != nil {
return err
Expand Down

0 comments on commit ddf1be6

Please sign in to comment.