Implement all builtins required to get fib working
Getting `recur` to work required adding an Operation argument to a bunch of places in a really hacky way. I don't like it at all, but I'm also kind of out of mental energy to figure it out properly. The fibonacci demo in the README _works_, at least, though I don't think it's actually tail recursive.
This commit is contained in:
parent
3a2423a937
commit
6257495fe4
16
README.md
16
README.md
@ -4,17 +4,23 @@ Fibonacci function in ginger:
|
|||||||
|
|
||||||
```
|
```
|
||||||
fib = {
|
fib = {
|
||||||
|
|
||||||
decr = { out = add < (in; -1;); };
|
decr = { out = add < (in; -1;); };
|
||||||
|
|
||||||
out = {
|
out = {
|
||||||
n = 0 < in;
|
|
||||||
a = 1 < in;
|
|
||||||
b = 2 < in;
|
|
||||||
|
|
||||||
out < if < (
|
n = tupEl < (in; 0;);
|
||||||
|
a = tupEl < (in; 1;);
|
||||||
|
b = tupEl < (in; 2;);
|
||||||
|
|
||||||
|
out = if < (
|
||||||
zero? < n;
|
zero? < n;
|
||||||
a;
|
a;
|
||||||
recur < (decr < n; b; add < (a;b;); );
|
recur < (
|
||||||
|
decr < n;
|
||||||
|
b;
|
||||||
|
add < (a;b;);
|
||||||
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
} < (in; 0; 1;);
|
} < (in; 0; 1;);
|
||||||
|
20
vm/op.go
20
vm/op.go
@ -46,15 +46,18 @@ func evalThunks(args []Thunk) Thunk {
|
|||||||
|
|
||||||
|
|
||||||
// Operation is an entity which can accept one or more arguments (each not
|
// Operation is an entity which can accept one or more arguments (each not
|
||||||
// having been evaluated yet) and return a Thunk which will perform some internal processing on those
|
// having been evaluated yet) and return a Thunk which will perform some
|
||||||
// arguments and return a resultant Value.
|
// internal processing on those arguments and return a resultant Value.
|
||||||
|
//
|
||||||
|
// The Operation passed into Perform is the Operation which is calling the
|
||||||
|
// Perform. It may be nil.
|
||||||
type Operation interface {
|
type Operation interface {
|
||||||
Perform([]Thunk) (Thunk, error)
|
Perform([]Thunk, Operation) (Thunk, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func preEvalValOp(fn func(Value) (Value, error)) Operation {
|
func preEvalValOp(fn func(Value) (Value, error)) Operation {
|
||||||
|
|
||||||
return OperationFunc(func(args []Thunk) (Thunk, error) {
|
return OperationFunc(func(args []Thunk, _ Operation) (Thunk, error) {
|
||||||
|
|
||||||
return func() (Value, error) {
|
return func() (Value, error) {
|
||||||
|
|
||||||
@ -89,18 +92,19 @@ func OperationFromGraph(g *gg.Graph, scope Scope) Operation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphOp) Perform(args []Thunk) (Thunk, error) {
|
func (g *graphOp) Perform(args []Thunk, _ Operation) (Thunk, error) {
|
||||||
return ScopeFromGraph(
|
return ScopeFromGraph(
|
||||||
g.Graph,
|
g.Graph,
|
||||||
evalThunks(args),
|
evalThunks(args),
|
||||||
g.scope,
|
g.scope,
|
||||||
|
g,
|
||||||
).Evaluate(outVal)
|
).Evaluate(outVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OperationFunc is a function which implements the Operation interface.
|
// OperationFunc is a function which implements the Operation interface.
|
||||||
type OperationFunc func([]Thunk) (Thunk, error)
|
type OperationFunc func([]Thunk, Operation) (Thunk, error)
|
||||||
|
|
||||||
// Perform calls the underlying OperationFunc directly.
|
// Perform calls the underlying OperationFunc directly.
|
||||||
func (f OperationFunc) Perform(args []Thunk) (Thunk, error) {
|
func (f OperationFunc) Perform(args []Thunk, op Operation) (Thunk, error) {
|
||||||
return f(args)
|
return f(args, op)
|
||||||
}
|
}
|
||||||
|
14
vm/scope.go
14
vm/scope.go
@ -24,7 +24,9 @@ type Scope interface {
|
|||||||
// EvaluateEdge will use the given Scope to evaluate the edge's ultimate Value,
|
// EvaluateEdge will use the given Scope to evaluate the edge's ultimate Value,
|
||||||
// after passing all leaf vertices up the tree through all Operations found on
|
// after passing all leaf vertices up the tree through all Operations found on
|
||||||
// edge values.
|
// edge values.
|
||||||
func EvaluateEdge(edge *gg.OpenEdge, scope Scope) (Value, error) {
|
//
|
||||||
|
// The Operation is the Operation which is evaluating the edge, if any.
|
||||||
|
func EvaluateEdge(edge *gg.OpenEdge, scope Scope, op Operation) (Value, error) {
|
||||||
|
|
||||||
thunk, err := graph.MapReduce[gg.Value, gg.Value, Thunk](
|
thunk, err := graph.MapReduce[gg.Value, gg.Value, Thunk](
|
||||||
edge,
|
edge,
|
||||||
@ -73,7 +75,7 @@ func EvaluateEdge(edge *gg.OpenEdge, scope Scope) (Value, error) {
|
|||||||
return nil, fmt.Errorf("edge value must be an operation")
|
return nil, fmt.Errorf("edge value must be an operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
return edgeVal.Operation.Perform(args)
|
return edgeVal.Operation.Perform(args, op)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -115,6 +117,7 @@ type graphScope struct {
|
|||||||
*gg.Graph
|
*gg.Graph
|
||||||
in Thunk
|
in Thunk
|
||||||
parent Scope
|
parent Scope
|
||||||
|
op Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScopeFromGraph returns a Scope which will use the given Graph for evaluation.
|
// ScopeFromGraph returns a Scope which will use the given Graph for evaluation.
|
||||||
@ -133,11 +136,12 @@ type graphScope struct {
|
|||||||
//
|
//
|
||||||
// NewScope will return the parent scope, if one is given, or an empty ScopeMap
|
// NewScope will return the parent scope, if one is given, or an empty ScopeMap
|
||||||
// if not.
|
// if not.
|
||||||
func ScopeFromGraph(g *gg.Graph, in Thunk, parent Scope) Scope {
|
func ScopeFromGraph(g *gg.Graph, in Thunk, parent Scope, op Operation) Scope {
|
||||||
return &graphScope{
|
return &graphScope{
|
||||||
Graph: g,
|
Graph: g,
|
||||||
in: in,
|
in: in,
|
||||||
parent: parent,
|
parent: parent,
|
||||||
|
op: op,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +169,9 @@ func (g *graphScope) Evaluate(nameVal Value) (Thunk, error) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return func() (Value, error) { return EvaluateEdge(edgesIn[0], g) }, nil
|
return func() (Value, error) {
|
||||||
|
return EvaluateEdge(edgesIn[0], g, g.op)
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphScope) NewScope() Scope {
|
func (g *graphScope) NewScope() Scope {
|
||||||
|
@ -12,10 +12,6 @@ var GlobalScope = ScopeMap{
|
|||||||
|
|
||||||
"add": Value{Operation: preEvalValOp(func(val Value) (Value, error) {
|
"add": Value{Operation: preEvalValOp(func(val Value) (Value, error) {
|
||||||
|
|
||||||
if len(val.Tuple) == 0 {
|
|
||||||
return Value{}, fmt.Errorf("add requires a non-zero tuple of numbers as an argument")
|
|
||||||
}
|
|
||||||
|
|
||||||
var sum int64
|
var sum int64
|
||||||
|
|
||||||
for _, tupVal := range val.Tuple {
|
for _, tupVal := range val.Tuple {
|
||||||
@ -30,4 +26,53 @@ var GlobalScope = ScopeMap{
|
|||||||
return Value{Value: gg.Value{Number: &sum}}, nil
|
return Value{Value: gg.Value{Number: &sum}}, nil
|
||||||
|
|
||||||
})},
|
})},
|
||||||
|
|
||||||
|
"tupEl": Value{Operation: preEvalValOp(func(val Value) (Value, error) {
|
||||||
|
|
||||||
|
tup, i := val.Tuple[0], val.Tuple[1]
|
||||||
|
|
||||||
|
return tup.Tuple[int(*i.Number)], nil
|
||||||
|
|
||||||
|
})},
|
||||||
|
|
||||||
|
"isZero": Value{Operation: preEvalValOp(func(val Value) (Value, error) {
|
||||||
|
|
||||||
|
if *val.Number == 0 {
|
||||||
|
one := int64(1)
|
||||||
|
return Value{Value: gg.Value{Number: &one}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
zero := int64(0)
|
||||||
|
return Value{Value: gg.Value{Number: &zero}}, nil
|
||||||
|
|
||||||
|
})},
|
||||||
|
|
||||||
|
"if": Value{Operation: OperationFunc(func(args []Thunk, _ Operation) (Thunk, error) {
|
||||||
|
|
||||||
|
b := args[0]
|
||||||
|
onTrue := args[1]
|
||||||
|
onFalse := args[2]
|
||||||
|
|
||||||
|
return func() (Value, error) {
|
||||||
|
|
||||||
|
bVal, err := b()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ZeroValue, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if *bVal.Number == 0 {
|
||||||
|
return onFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
return onTrue()
|
||||||
|
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
})},
|
||||||
|
|
||||||
|
"recur": Value{Operation: OperationFunc(func(args []Thunk, op Operation) (Thunk, error) {
|
||||||
|
return op.Perform(args, op)
|
||||||
|
})},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
7
vm/vm.go
7
vm/vm.go
@ -115,9 +115,10 @@ func EvaluateSource(opSrc io.Reader, input gg.Value, scope Scope) (Value, error)
|
|||||||
|
|
||||||
op := OperationFromGraph(g, scope.NewScope())
|
op := OperationFromGraph(g, scope.NewScope())
|
||||||
|
|
||||||
thunk, err := op.Perform([]Thunk{
|
thunk, err := op.Perform(
|
||||||
func() (Value, error) { return Value{Value: input}, nil },
|
[]Thunk{valThunk(Value{Value: input})},
|
||||||
})
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ZeroValue, err
|
return ZeroValue, err
|
||||||
|
Loading…
Reference in New Issue
Block a user