Documentation
¶
Index ¶
Constants ¶
const ( // Debug enables debugging for some commonly used debug information. Debug = false )
const ( // ErrTypeCurrentlyUnknown is returned from the Type() call on Expr if // unification didn't run successfully and the type isn't obvious yet. ErrTypeCurrentlyUnknown = Error("type is currently unknown") )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Edge ¶
type Edge struct { Kind1 string // kind of resource Name1 string // name of resource Send string // name of field used for send/recv (optional) Kind2 string // kind of resource Name2 string // name of resource Recv string // name of field used for send/recv (optional) Notify bool // is there a notification being sent? }
Edge is the data structure representing a compiled edge that is used in the lang to express a dependency between two resources and optionally send/recv.
type Expr ¶
type Expr interface { pgraph.Vertex // must implement this since we store these in our graphs Interpolate() (Expr, error) // return expanded form of AST as a new AST SetScope(*Scope) error // set the scope here and propagate it downwards SetType(*types.Type) error // sets the type definitively, errors if incompatible Type() (*types.Type, error) Unify() ([]Invariant, error) // TODO: is this named correctly? Graph() (*pgraph.Graph, error) Func() (Func, error) // a function that represents this reactively SetValue(types.Value) error Value() (types.Value, error) }
Expr represents an expression in the language. Expr implementations must have their method receivers implemented as pointer receivers so that they can be easily copied and moved around. Expr also implements pgraph.Vertex so that these can be stored as pointers in our graph data structure.
type Func ¶
type Func interface { Validate() error // FIXME: this is only needed for PolyFunc. Get it moved and used! Info() *Info Init(*Init) error Stream() error Close() error }
Func is the interface that any valid func must fulfill. It is very simple, but still event driven. Funcs should attempt to only send values when they have changed. TODO: should we support a static version of this interface for funcs that never change to avoid the overhead of the goroutine and channel listener?
type Info ¶
type Info struct { Pure bool // is the function pure? (can it be memoized?) Memo bool // should the function be memoized? (false if too much output) Sig *types.Type // the signature of the function, must be KindFunc Err error // is this a valid function, or was it created improperly? }
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.
type Init ¶
type Init struct { Hostname string // uuid for the host //Noop bool Input chan types.Value // Engine will close `input` chan Output chan types.Value // Stream must close `output` chan World engine.World Debug bool Logf func(format string, v ...interface{}) }
Init is the structure of values and references which is passed into all functions on initialization.
type Invariant ¶
Invariant represents a constraint that is described by the Expr's and Stmt's, and which is passed into the unification solver to describe what is known by the AST.
type PolyFunc ¶
type PolyFunc interface { Func // implement everything in Func but add the additional requirements // Polymorphisms returns a list of possible function type signatures. It // takes as input a list of partial "hints" as to limit the number of // possible results it returns. These partial hints take the form of a // function type signature (with as many types in it specified and the // rest set to nil) and any known static values for the input args. If // the partial type is not nil, then the Ord parameter must be of the // correct arg length. If any types are specified, then the array must // be of that length as well, with the known ones filled in. Some // static polymorphic functions require a minimal amount of hinting or // they will be unable to return any possible result that is not // infinite in length. If you expect to need to return an infinite (or // very large) amount of results, then you should return an error // instead. The arg names in your returned func type signatures should // be in the standardized "a..b..c" format. Use util.NumToAlpha if you // want to convert easily. Polymorphisms(*types.Type, []types.Value) ([]*types.Type, error) // Build takes the known type signature for this function and finalizes // this structure so that it is now determined, and ready to function as // a normal function would. (The normal methods in the Func interface // are all that should be needed or used after this point.) Build(*types.Type) error // then, you can get argNames from Info() }
PolyFunc is an interface for functions which are statically polymorphic. In other words, they are functions which before compile time are polymorphic, but after a successful compilation have a fixed static signature. This makes implementing what would appear to be generic or polymorphic instead something that is actually static and that still has the language safety properties.
type Scope ¶
type Scope struct { Variables map[string]Expr //Functions map[string]??? // TODO: do we want a separate namespace for user defined functions? Classes map[string]Stmt Chain []Stmt // chain of previously seen stmt's }
Scope represents a mapping between a variables identifier and the corresponding expression it is bound to. Local scopes in this language exist and are formed by nesting within if statements. Child scopes can shadow variables in parent scopes, which is another way of saying they can redefine previously used variables as long as the new binding happens within a child scope. This is useful so that someone in the top scope can't prevent a child module from ever using that variable name again. It might be worth revisiting this point in the future if we find it adds even greater code safety. Please report any bugs you have written that would have been prevented by this.
func (*Scope) Copy ¶
Copy makes a copy of the Scope struct. This ensures that if the internal map is changed, it doesn't affect other copies of the Scope. It does *not* copy or change the Expr pointers contained within, since these are references, and we need those to be consistently pointing to the same things after copying.
type Stmt ¶
type Stmt interface { Interpolate() (Stmt, error) // return expanded form of AST as a new AST SetScope(*Scope) error // set the scope here and propagate it downwards Unify() ([]Invariant, error) // TODO: is this named correctly? Graph() (*pgraph.Graph, error) Output() (*Output, error) }
Stmt represents a statement node in the language. A stmt could be a resource, a `bind` statement, or even an `if` statement. (Different from an `if` expression.)