docs: document remaining packages and simplify AST types #45
@@ -7,18 +7,24 @@ import (
|
||||
"git.maximhutz.com/max/lambda/pkg/codec"
|
||||
)
|
||||
|
||||
// A Codec is a type-erased codec that serializes and deserializes expressions
|
||||
// as Expr values, regardless of the underlying representation type.
|
||||
type Codec interface {
|
||||
codec.Codec[Expr]
|
||||
|
||||
// InType returns the name of the representation this codec handles.
|
||||
InType() string
|
||||
}
|
||||
|
||||
type convertedCodec[T any] struct {
|
||||
// A registeredCodec adapts a typed codec.Codec[T] into the type-erased Codec
|
||||
// interface. It wraps decoded values into Expr on decode, and extracts the
|
||||
// underlying T from an Expr on encode.
|
||||
type registeredCodec[T any] struct {
|
||||
codec codec.Codec[T]
|
||||
inType string
|
||||
}
|
||||
|
||||
func (c convertedCodec[T]) Decode(s string) (Expr, error) {
|
||||
func (c registeredCodec[T]) Decode(s string) (Expr, error) {
|
||||
t, err := c.codec.Decode(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -27,7 +33,7 @@ func (c convertedCodec[T]) Decode(s string) (Expr, error) {
|
||||
return NewExpr(c.inType, t), nil
|
||||
}
|
||||
|
||||
func (c convertedCodec[T]) Encode(r Expr) (string, error) {
|
||||
func (c registeredCodec[T]) Encode(r Expr) (string, error) {
|
||||
t, ok := r.Data().(T)
|
||||
if !ok {
|
||||
dataType := reflect.TypeOf(r.Data())
|
||||
@@ -38,13 +44,15 @@ func (c convertedCodec[T]) Encode(r Expr) (string, error) {
|
||||
return c.codec.Encode(t)
|
||||
}
|
||||
|
||||
func (c convertedCodec[T]) InType() string { return c.inType }
|
||||
func (c registeredCodec[T]) InType() string { return c.inType }
|
||||
|
||||
// RegisterCodec registers a typed codec under the given representation name.
|
||||
// Returns an error if a codec for that representation is already registered.
|
||||
func RegisterCodec[T any](registry *Registry, m codec.Codec[T], inType string) error {
|
||||
if _, ok := registry.codecs[inType]; ok {
|
||||
return fmt.Errorf("Codec for '%s' already registered", inType)
|
||||
}
|
||||
|
||||
registry.codecs[inType] = convertedCodec[T]{m, inType}
|
||||
registry.codecs[inType] = registeredCodec[T]{m, inType}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,19 +6,29 @@ import (
|
||||
"git.maximhutz.com/max/lambda/pkg/codec"
|
||||
)
|
||||
|
||||
// A Conversion is a type-erased transformation from one representation to
|
||||
// another. It operates on Expr values, hiding the underlying representation
|
||||
// types.
|
||||
type Conversion interface {
|
||||
// InType returns the name of the source representation.
|
||||
InType() string
|
||||
// OutType returns the name of the target representation.
|
||||
OutType() string
|
||||
|
||||
// Run applies the conversion to the given expression. Returns an error if
|
||||
// the expression's data does not match the expected source type.
|
||||
Run(Expr) (Expr, error)
|
||||
}
|
||||
|
||||
type convertedConversion[T, U any] struct {
|
||||
// A registeredConversion adapts a typed codec.Conversion[T, U] into the
|
||||
// type-erased Conversion interface. It extracts the underlying T from an Expr,
|
||||
// applies the conversion, and wraps the result as a new Expr.
|
||||
type registeredConversion[T, U any] struct {
|
||||
conversion codec.Conversion[T, U]
|
||||
inType, outType string
|
||||
}
|
||||
|
||||
func (c convertedConversion[T, U]) Run(expr Expr) (Expr, error) {
|
||||
func (c registeredConversion[T, U]) Run(expr Expr) (Expr, error) {
|
||||
t, ok := expr.Data().(T)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not parse '%v' as '%s'", t, c.inType)
|
||||
@@ -32,12 +42,18 @@ func (c convertedConversion[T, U]) Run(expr Expr) (Expr, error) {
|
||||
return NewExpr(c.outType, u), nil
|
||||
}
|
||||
|
||||
func (c convertedConversion[T, U]) InType() string { return c.inType }
|
||||
func (c registeredConversion[T, U]) InType() string { return c.inType }
|
||||
|
||||
func (c convertedConversion[T, U]) OutType() string { return c.outType }
|
||||
func (c registeredConversion[T, U]) OutType() string { return c.outType }
|
||||
|
||||
func RegisterConversion[T, U any](registry *Registry, conversion func(T) (U, error), inType, outType string) error {
|
||||
registry.converter.Add(convertedConversion[T, U]{conversion, inType, outType})
|
||||
// RegisterConversion registers a typed conversion function between two
|
||||
// representations.
|
||||
func RegisterConversion[T, U any](
|
||||
registry *Registry,
|
||||
conversion codec.Conversion[T, U],
|
||||
inType, outType string,
|
||||
) error {
|
||||
registry.converter.Add(registeredConversion[T, U]{conversion, inType, outType})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package registry
|
||||
|
||||
// A Converter is a directed graph of conversions between representations. Each
|
||||
// node is a representation name, and each edge is a Conversion.
|
||||
type Converter struct {
|
||||
data map[string][]Conversion
|
||||
}
|
||||
|
||||
// NewConverter creates an empty Converter with no registered conversions.
|
||||
func NewConverter() *Converter {
|
||||
return &Converter{data: map[string][]Conversion{}}
|
||||
}
|
||||
|
||||
// Add registers a conversion, adding an edge from its source representation
|
||||
// to its target representation.
|
||||
func (g *Converter) Add(c Conversion) {
|
||||
conversionsFromIn, ok := g.data[c.InType()]
|
||||
if !ok {
|
||||
@@ -18,6 +23,8 @@ func (g *Converter) Add(c Conversion) {
|
||||
g.data[c.InType()] = conversionsFromIn
|
||||
}
|
||||
|
||||
// ConversionsFrom returns all conversions that have the given representation
|
||||
// as their source type.
|
||||
func (g *Converter) ConversionsFrom(t string) []Conversion {
|
||||
return g.data[t]
|
||||
}
|
||||
|
||||
@@ -6,26 +6,36 @@ import (
|
||||
"git.maximhutz.com/max/lambda/pkg/engine"
|
||||
)
|
||||
|
||||
// An Engine is a type-erased evaluation engine that can load an expression
|
||||
// into a runnable Process.
|
||||
type Engine interface {
|
||||
// Load prepares an expression for evaluation, returning a Process. Returns
|
||||
// an error if the expression's data does not match the engine's expected
|
||||
// representation type.
|
||||
Load(Expr) (Process, error)
|
||||
// Name returns the name of this engine.
|
||||
Name() string
|
||||
// InType returns the name of the representation this engine operates on.
|
||||
InType() string
|
||||
}
|
||||
|
||||
type convertedEngine[T any] struct {
|
||||
// A registeredEngine adapts a typed engine.Engine[T] into the type-erased
|
||||
// Engine interface. It extracts the underlying T from an Expr before passing it
|
||||
// to the engine.
|
||||
type registeredEngine[T any] struct {
|
||||
engine engine.Engine[T]
|
||||
name string
|
||||
inType string
|
||||
}
|
||||
|
||||
func (e convertedEngine[T]) InType() string { return e.inType }
|
||||
func (e registeredEngine[T]) InType() string { return e.inType }
|
||||
|
||||
func (e convertedEngine[T]) Name() string { return e.name }
|
||||
func (e registeredEngine[T]) Name() string { return e.name }
|
||||
|
||||
func (e convertedEngine[T]) Load(expr Expr) (Process, error) {
|
||||
func (e registeredEngine[T]) Load(expr Expr) (Process, error) {
|
||||
t, ok := expr.Data().(T)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("'ncorrent format '%s' for engine '%s'", expr.Repr(), e.inType)
|
||||
return nil, fmt.Errorf("incorrect format '%s' for engine '%s'", expr.Repr(), e.inType)
|
||||
}
|
||||
|
||||
process, err := e.engine(t)
|
||||
@@ -33,14 +43,16 @@ func (e convertedEngine[T]) Load(expr Expr) (Process, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return convertedProcess[T]{process, e.inType}, nil
|
||||
return registeredProcess[T]{process, e.inType}, nil
|
||||
}
|
||||
|
||||
// RegisterEngine registers a typed engine under the given name. Returns an
|
||||
// error if an engine with that name is already registered.
|
||||
func RegisterEngine[T any](registry *Registry, e engine.Engine[T], name, inType string) error {
|
||||
if _, ok := registry.engines[name]; ok {
|
||||
return fmt.Errorf("engine '%s' already registered", name)
|
||||
}
|
||||
|
||||
registry.engines[name] = &convertedEngine[T]{e, name, inType}
|
||||
registry.engines[name] = ®isteredEngine[T]{e, name, inType}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package registry
|
||||
|
||||
// A Expr is a lambda calculus expression. It can have any type of
|
||||
// Expresentation, so long as that class is known to the registry it is handled
|
||||
// An Expr is a type-erased lambda calculus expression. It can have any type of
|
||||
// representation, so long as that type is known to the registry it is handled
|
||||
// by.
|
||||
type Expr interface {
|
||||
// Repr returns the name of the underlying Expresentation. It is assumed if
|
||||
// two expressions have the same Repr(), they have the same Expresentation.
|
||||
// Repr returns the name of the underlying representation. Two expressions
|
||||
// with the same Repr() are assumed to have the same representation type.
|
||||
Repr() string
|
||||
|
||||
// The base expression data.
|
||||
// Data returns the underlying expression data.
|
||||
Data() any
|
||||
}
|
||||
|
||||
// A baseExpr is the default implementation of Expr.
|
||||
type baseExpr struct {
|
||||
id string
|
||||
data any
|
||||
@@ -21,4 +22,5 @@ func (r baseExpr) Repr() string { return r.id }
|
||||
|
||||
func (r baseExpr) Data() any { return r.data }
|
||||
|
||||
// NewExpr creates an Expr with the given representation name and data.
|
||||
func NewExpr(id string, data any) Expr { return baseExpr{id, data} }
|
||||
|
||||
@@ -10,14 +10,14 @@ type Process interface {
|
||||
InType() string
|
||||
}
|
||||
|
||||
type convertedProcess[T any] struct {
|
||||
type registeredProcess[T any] struct {
|
||||
process engine.Process[T]
|
||||
inType string
|
||||
}
|
||||
|
||||
func (e convertedProcess[T]) InType() string { return e.inType }
|
||||
func (e registeredProcess[T]) InType() string { return e.inType }
|
||||
|
||||
func (b convertedProcess[T]) Get() (Expr, error) {
|
||||
func (b registeredProcess[T]) Get() (Expr, error) {
|
||||
s, err := b.process.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -26,6 +26,6 @@ func (b convertedProcess[T]) Get() (Expr, error) {
|
||||
return NewExpr(b.inType, s), nil
|
||||
}
|
||||
|
||||
func (b convertedProcess[T]) Step(i int) bool {
|
||||
func (b registeredProcess[T]) Step(i int) bool {
|
||||
return b.process.Step(i)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user