unification

package
v0.0.0-...-c12452b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2024 License: GPL-3.0 Imports: 6 Imported by: 5

Documentation

Overview

Package unification contains the code related to type unification for the mcl language.

Index

Constants

View Source
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"

	// StrategyOptimizationsKey is the string key used to tell the solver
	// about the specific optimizations you'd like to request. The format
	// can be specific to each solver.
	StrategyOptimizationsKey = "optimizations"
)

Variables

This section is empty.

Functions

func DebugSolverState

func DebugSolverState(solved map[interfaces.Expr]*types.Type, equalities []interfaces.Invariant) string

DebugSolverState helps us in understanding the state of the type unification solver in a more mainstream format. Example:

solver state:

* str("foo") :: str * call:f(str("foo")) [0xc000ac9f10] :: ?1 * var(x) [0xc00088d840] :: ?2 * param(x) [0xc00000f950] :: ?3 * func(x) { var(x) } [0xc0000e9680] :: ?4 * ?2 = ?3 * ?4 = func(arg0 str) ?1 * ?4 = func(x str) ?2 * ?1 = ?2

func ExclusivesProduct

func ExclusivesProduct(exclusives []*interfaces.ExclusiveInvariant) [][]interfaces.Invariant

ExclusivesProduct returns a list of different products produced from the combinatorial product of the list of exclusives. Each ExclusiveInvariant must contain between one and more Invariants. This takes every combination of Invariants (choosing one from each ExclusiveInvariant) and returns that list. In other words, if you have three exclusives, with invariants named (A1, B1), (A2), and (A3, B3, C3) you'll get: (A1, A2, A3), (A1, A2, B3), (A1, A2, C3), (B1, A2, A3), (B1, A2, B3), (B1, A2, C3) as results for this function call.

func ExprContains

func ExprContains(needle interfaces.Expr, haystack []interfaces.Expr) bool

ExprContains is an "in array" function to test for an expr in a slice of expressions.

func ExprListToExprMap

func ExprListToExprMap(exprList []interfaces.Expr) map[interfaces.Expr]struct{}

ExprListToExprMap converts a list of expressions to a map that has the unique expr pointers as the keys. This is just an alternate representation of the same data structure. If you have any duplicate values in your list, they'll get removed when stored as a map.

func ExprMapToExprList

func ExprMapToExprList(exprMap map[interfaces.Expr]struct{}) []interfaces.Expr

ExprMapToExprList converts a map of expressions to a list that has the unique expr pointers as the values. This is just an alternate representation of the same data structure.

func Register

func Register(name string, solver func() Solver)

Register takes a solver and its name and makes it available for use. It is commonly called in the init() method of the solver at program startup. There is no matching Unregister function.

func UniqueExprList

func UniqueExprList(exprList []interfaces.Expr) []interfaces.Expr

UniqueExprList returns a unique list of expressions with no duplicates. It does this my converting it to a map and then back. This isn't necessarily the most efficient way, and doesn't preserve list ordering.

Types

type Init

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{})
}

Init contains some handles that are used to initialize every solver. Each individual solver can choose to omit using some of the fields.

type InvariantSolution

type InvariantSolution struct {
	Solutions []*interfaces.EqualsInvariant // list of trivial solutions for each node
}

InvariantSolution lists a trivial set of EqualsInvariant mappings so that you can populate your AST with SetType calls in a simple loop.

func (*InvariantSolution) ExprList

func (obj *InvariantSolution) ExprList() []interfaces.Expr

ExprList returns the list of valid expressions. This struct is not part of the invariant interface, but it implements this anyways.

type Pairs

Pairs is a simple list of pairs of expressions which can be used as a simple undirected graph structure, or as a simple list of equalities.

func (Pairs) DFS

func (obj Pairs) DFS(start interfaces.Expr) []interfaces.Expr

DFS returns a depth first search for the graph, starting at the input vertex.

func (Pairs) Vertices

func (obj Pairs) Vertices(expr interfaces.Expr) []interfaces.Expr

Vertices returns the list of vertices that the input expr is directly connected to.

type Solver

type Solver interface {
	// Init initializes the solver struct before first use.
	Init(*Init) error

	// Solve performs the actual solving. It must return as soon as possible
	// if the context is closed.
	Solve(ctx context.Context, invariants []interfaces.Invariant, expected []interfaces.Expr) (*InvariantSolution, error)
}

Solver is the general interface that any solver needs to implement.

func Lookup

func Lookup(name string) (Solver, error)

Lookup returns a pointer to the solver's struct.

func LookupDefault

func LookupDefault() (Solver, error)

LookupDefault attempts to return a "default" solver.

type Unifier

type Unifier struct {
	// AST is the input abstract syntax tree to unify.
	AST interfaces.Stmt

	// 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{})
}

Unifier holds all the data that the Unify function will need for it to run.

func (*Unifier) Unify

func (obj *Unifier) Unify(ctx context.Context) error

Unify takes an AST expression tree and attempts to assign types to every node using the specified solver. The expression tree returns a list of invariants (or constraints) which must be met in order to find a unique value for the type of each expression. This list of invariants is passed into the solver, which hopefully finds a solution. If it cannot find a unique solution, then it will return an error. The invariants are available in different flavours which describe different constraint scenarios. The simplest expresses that a a particular node id (it's pointer) must be a certain type. More complicated invariants might express that two different node id's must have the same type. This function and logic was invented after the author could not find any proper literature or examples describing a well-known implementation of this process. Improvements and polite recommendations are welcome.

Directories

Path Synopsis
Package solvers is used to have a central place to import all solvers from.
Package solvers is used to have a central place to import all solvers from.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL