Got basic demo working, ran go fmt
This commit is contained in:
parent
6257495fe4
commit
ebf57591a8
47
README.md
47
README.md
@ -1,37 +1,7 @@
|
||||
# Ginger
|
||||
|
||||
Fibonacci function in ginger:
|
||||
|
||||
```
|
||||
fib = {
|
||||
|
||||
decr = { out = add < (in; -1;); };
|
||||
|
||||
out = {
|
||||
|
||||
n = tupEl < (in; 0;);
|
||||
a = tupEl < (in; 1;);
|
||||
b = tupEl < (in; 2;);
|
||||
|
||||
out = if < (
|
||||
zero? < n;
|
||||
a;
|
||||
recur < (
|
||||
decr < n;
|
||||
b;
|
||||
add < (a;b;);
|
||||
);
|
||||
);
|
||||
|
||||
} < (in; 0; 1;);
|
||||
};
|
||||
```
|
||||
|
||||
Usage of the function to generate the 6th fibonnaci number:
|
||||
|
||||
```
|
||||
fib < 5;
|
||||
```
|
||||
A programming language utilizing a graph datastructure for syntax. Currently in
|
||||
super-early-alpha-don't-actually-use-this-for-anything development.
|
||||
|
||||
## Development
|
||||
|
||||
@ -48,3 +18,16 @@ from the repo root and you will be dropped into a shell with all dependencies
|
||||
(including the correct go version) in your PATH, ready to use. This could
|
||||
probably be expanded to other OSs/architectures easily, if you care to do so
|
||||
please check out the `default.nix` file and submit a PR!
|
||||
|
||||
## Demo
|
||||
|
||||
An example program which computes the Nth fibonacci number can be found at
|
||||
`examples/fib.gg`. You can try it out by doing:
|
||||
|
||||
```
|
||||
go run ./cmd/eval/main.go "$(cat examples/fib.gg)" 5
|
||||
```
|
||||
|
||||
Where you can replace `5` with any number. The vm has only been given enough
|
||||
capability to run this program as a demo, and is extremely poorly optimized (as
|
||||
will be evident if you input any large number). Further work is obviously TODO.
|
||||
|
41
cmd/eval/main.go
Normal file
41
cmd/eval/main.go
Normal file
@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/mediocregopher/ginger/gg"
|
||||
"github.com/mediocregopher/ginger/vm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if len(os.Args) < 3 {
|
||||
fmt.Printf(`Usage: %s <operation source> "in = <value>"\n`, os.Args[0])
|
||||
return
|
||||
}
|
||||
|
||||
opSrc := os.Args[1]
|
||||
inSrc := os.Args[2]
|
||||
|
||||
inVal, err := gg.DecodeSingleValueFromLexer(
|
||||
gg.NewLexer(bytes.NewBufferString(inSrc + ";")),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("decoding input: %v", err))
|
||||
}
|
||||
|
||||
res, err := vm.EvaluateSource(
|
||||
bytes.NewBufferString(opSrc),
|
||||
inVal,
|
||||
vm.GlobalScope,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("evaluating: %v", err))
|
||||
}
|
||||
|
||||
fmt.Println(res)
|
||||
}
|
19
examples/fib.gg
Normal file
19
examples/fib.gg
Normal file
@ -0,0 +1,19 @@
|
||||
out = {
|
||||
|
||||
decr = { out = add < (in; -1;); };
|
||||
|
||||
n = tupEl < (in; 0;);
|
||||
a = tupEl < (in; 1;);
|
||||
b = tupEl < (in; 2;);
|
||||
|
||||
out = if < (
|
||||
isZero < n;
|
||||
a;
|
||||
recur < (
|
||||
decr < n;
|
||||
b;
|
||||
add < (a;b;);
|
||||
);
|
||||
);
|
||||
|
||||
} < (in; 0; 1;);
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
// Type aliases for convenience
|
||||
type (
|
||||
Graph = graph.Graph[Value, Value]
|
||||
Graph = graph.Graph[Value, Value]
|
||||
OpenEdge = graph.OpenEdge[Value, Value]
|
||||
)
|
||||
|
||||
@ -291,7 +291,7 @@ func (d *decoder) parseValIn(into *Graph, toks []LexerToken) (*Graph, []LexerTok
|
||||
return into.AddValueIn(dstVal, oe), toks, nil
|
||||
}
|
||||
|
||||
func (d *decoder) decode(lexer Lexer) (*Graph, error) {
|
||||
func (d *decoder) readAllTokens(lexer Lexer) ([]LexerToken, error) {
|
||||
|
||||
var toks []LexerToken
|
||||
|
||||
@ -309,6 +309,17 @@ func (d *decoder) decode(lexer Lexer) (*Graph, error) {
|
||||
toks = append(toks, tok)
|
||||
}
|
||||
|
||||
return toks, nil
|
||||
}
|
||||
|
||||
func (d *decoder) decode(lexer Lexer) (*Graph, error) {
|
||||
|
||||
toks, err := d.readAllTokens(lexer)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
val, _, _, err := d.parseGraphValue(toks, false)
|
||||
|
||||
if err != nil {
|
||||
@ -326,3 +337,17 @@ func DecodeLexer(lexer Lexer) (*Graph, error) {
|
||||
decoder := &decoder{}
|
||||
return decoder.decode(lexer)
|
||||
}
|
||||
|
||||
func DecodeSingleValueFromLexer(lexer Lexer) (Value, error) {
|
||||
decoder := &decoder{}
|
||||
|
||||
toks, err := decoder.readAllTokens(lexer)
|
||||
|
||||
if err != nil {
|
||||
return ZeroValue, err
|
||||
}
|
||||
|
||||
val, _, _, err := decoder.parseSingleValue(toks)
|
||||
|
||||
return val, err
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func TestDecoder(t *testing.T) {
|
||||
tOut(
|
||||
n("a"),
|
||||
vOut(n("b"),
|
||||
i(1)),
|
||||
i(1)),
|
||||
),
|
||||
),
|
||||
},
|
||||
|
@ -113,7 +113,7 @@ func (oe OpenEdge[E, V]) FromTuple() ([]*OpenEdge[E, V], bool) {
|
||||
// an edge (with edgeVal attached to it) coming from the vertex containing val.
|
||||
func ValueOut[E, V Value](edgeVal E, val V) *OpenEdge[E, V] {
|
||||
return &OpenEdge[E, V]{
|
||||
val: &val,
|
||||
val: &val,
|
||||
edgeVal: edgeVal,
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ func TupleOut[E, V Value](edgeVal E, ins ...*OpenEdge[E, V]) *OpenEdge[E, V] {
|
||||
|
||||
var (
|
||||
zero V
|
||||
in = ins[0]
|
||||
in = ins[0]
|
||||
)
|
||||
|
||||
if edgeVal.Equal(zero) {
|
||||
@ -141,13 +141,13 @@ func TupleOut[E, V Value](edgeVal E, ins ...*OpenEdge[E, V]) *OpenEdge[E, V] {
|
||||
}
|
||||
|
||||
return &OpenEdge[E, V]{
|
||||
tup: ins,
|
||||
tup: ins,
|
||||
edgeVal: edgeVal,
|
||||
}
|
||||
}
|
||||
|
||||
type graphValueIn[E, V Value] struct {
|
||||
val V
|
||||
val V
|
||||
edge *OpenEdge[E, V]
|
||||
}
|
||||
|
||||
@ -163,13 +163,13 @@ func (valIn graphValueIn[E, V]) equal(valIn2 graphValueIn[E, V]) bool {
|
||||
// lots of O(N) operations, unnecessary copying on changes, and duplicate data
|
||||
// in memory.
|
||||
type Graph[E, V Value] struct {
|
||||
edges []*OpenEdge[E, V]
|
||||
edges []*OpenEdge[E, V]
|
||||
valIns []graphValueIn[E, V]
|
||||
}
|
||||
|
||||
func (g *Graph[E, V]) cp() *Graph[E, V] {
|
||||
cp := &Graph[E, V]{
|
||||
edges: make([]*OpenEdge[E, V], len(g.edges)),
|
||||
edges: make([]*OpenEdge[E, V], len(g.edges)),
|
||||
valIns: make([]graphValueIn[E, V], len(g.valIns)),
|
||||
}
|
||||
copy(cp.edges, g.edges)
|
||||
@ -243,7 +243,7 @@ func (g *Graph[E, V]) ValueIns(val Value) []*OpenEdge[E, V] {
|
||||
func (g *Graph[E, V]) AddValueIn(val V, oe *OpenEdge[E, V]) *Graph[E, V] {
|
||||
|
||||
valIn := graphValueIn[E, V]{
|
||||
val: val,
|
||||
val: val,
|
||||
edge: oe,
|
||||
}
|
||||
|
||||
@ -284,14 +284,13 @@ outer:
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
func mapReduce[Ea, Va Value, Vb any](
|
||||
root *OpenEdge[Ea, Va],
|
||||
mapVal func(Va) (Vb, error),
|
||||
reduceEdge func(*OpenEdge[Ea, Va], []Vb) (Vb, error),
|
||||
) (
|
||||
Vb, error,
|
||||
){
|
||||
) {
|
||||
|
||||
if valA, ok := root.FromValue(); ok {
|
||||
|
||||
@ -333,7 +332,7 @@ type mappedVal[Va Value, Vb any] struct {
|
||||
|
||||
type reducedEdge[Ea, Va Value, Vb any] struct {
|
||||
edgeA *OpenEdge[Ea, Va]
|
||||
valB Vb // result
|
||||
valB Vb // result
|
||||
}
|
||||
|
||||
// MapReduce recursively computes a resultant Value of type Vb from an
|
||||
@ -361,7 +360,7 @@ func MapReduce[Ea, Va Value, Vb any](
|
||||
reduceEdge func(Ea, []Vb) (Vb, error),
|
||||
) (
|
||||
Vb, error,
|
||||
){
|
||||
) {
|
||||
|
||||
var (
|
||||
zeroB Vb
|
||||
@ -370,7 +369,7 @@ func MapReduce[Ea, Va Value, Vb any](
|
||||
// reduction is only performed a single time for each value/edge.
|
||||
//
|
||||
// NOTE this is not implemented very efficiently.
|
||||
mappedVals []mappedVal[Va, Vb]
|
||||
mappedVals []mappedVal[Va, Vb]
|
||||
reducedEdges []reducedEdge[Ea, Va, Vb]
|
||||
)
|
||||
|
||||
@ -413,7 +412,7 @@ func MapReduce[Ea, Va Value, Vb any](
|
||||
|
||||
reducedEdges = append(reducedEdges, reducedEdge[Ea, Va, Vb]{
|
||||
edgeA: edgeA,
|
||||
valB: valB,
|
||||
valB: valB,
|
||||
})
|
||||
|
||||
return valB, nil
|
||||
|
@ -1,8 +1,8 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
@ -129,7 +129,7 @@ func TestEqual(t *testing.T) {
|
||||
|
||||
type mapReduceTestEdge struct {
|
||||
name string
|
||||
fn func([]int) int
|
||||
fn func([]int) int
|
||||
done bool
|
||||
}
|
||||
|
||||
@ -162,9 +162,9 @@ func (e *mapReduceTestEdge) do(ii []int) int {
|
||||
func TestMapReduce(t *testing.T) {
|
||||
|
||||
type (
|
||||
Va = I
|
||||
Vb = int
|
||||
Ea = *mapReduceTestEdge
|
||||
Va = I
|
||||
Vb = int
|
||||
Ea = *mapReduceTestEdge
|
||||
edge = OpenEdge[Ea, Va]
|
||||
)
|
||||
|
||||
@ -180,7 +180,7 @@ func TestMapReduce(t *testing.T) {
|
||||
return TupleOut[Ea, Va](edge, ins...)
|
||||
}
|
||||
|
||||
add := func() *mapReduceTestEdge{
|
||||
add := func() *mapReduceTestEdge {
|
||||
return &mapReduceTestEdge{
|
||||
name: "add",
|
||||
fn: func(ii []int) int {
|
||||
@ -193,7 +193,7 @@ func TestMapReduce(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
mul := func() *mapReduceTestEdge{
|
||||
mul := func() *mapReduceTestEdge {
|
||||
return &mapReduceTestEdge{
|
||||
name: "mul",
|
||||
fn: func(ii []int) int {
|
||||
@ -225,15 +225,15 @@ func TestMapReduce(t *testing.T) {
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
in *edge
|
||||
in *edge
|
||||
exp int
|
||||
}{
|
||||
{
|
||||
in: vOut(nil, 1),
|
||||
in: vOut(nil, 1),
|
||||
exp: 10,
|
||||
},
|
||||
{
|
||||
in: vOut(add(), 1),
|
||||
in: vOut(add(), 1),
|
||||
exp: 10,
|
||||
},
|
||||
{
|
||||
|
3
vm/op.go
3
vm/op.go
@ -30,7 +30,7 @@ func evalThunks(args []Thunk) Thunk {
|
||||
return func() (Value, error) {
|
||||
|
||||
var (
|
||||
err error
|
||||
err error
|
||||
tupVals = make([]Value, len(args))
|
||||
)
|
||||
|
||||
@ -44,7 +44,6 @@ func evalThunks(args []Thunk) Thunk {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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 arguments and return a resultant Value.
|
||||
|
@ -115,9 +115,9 @@ func (m ScopeMap) NewScope() Scope {
|
||||
|
||||
type graphScope struct {
|
||||
*gg.Graph
|
||||
in Thunk
|
||||
in Thunk
|
||||
parent Scope
|
||||
op Operation
|
||||
op Operation
|
||||
}
|
||||
|
||||
// ScopeFromGraph returns a Scope which will use the given Graph for evaluation.
|
||||
@ -139,9 +139,9 @@ type graphScope struct {
|
||||
func ScopeFromGraph(g *gg.Graph, in Thunk, parent Scope, op Operation) Scope {
|
||||
return &graphScope{
|
||||
Graph: g,
|
||||
in: in,
|
||||
in: in,
|
||||
parent: parent,
|
||||
op: op,
|
||||
op: op,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,5 +74,4 @@ var GlobalScope = ScopeMap{
|
||||
"recur": Value{Operation: OperationFunc(func(args []Thunk, op Operation) (Thunk, error) {
|
||||
return op.Perform(args, op)
|
||||
})},
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user