Got basic demo working, ran go fmt

This commit is contained in:
Brian Picciano 2021-12-30 15:29:38 -07:00
parent 6257495fe4
commit ebf57591a8
11 changed files with 131 additions and 66 deletions

View File

@ -1,37 +1,7 @@
# Ginger # Ginger
Fibonacci function in ginger: A programming language utilizing a graph datastructure for syntax. Currently in
super-early-alpha-don't-actually-use-this-for-anything development.
```
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;
```
## 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 (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 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! 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
View 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
View 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;);

View File

@ -11,7 +11,7 @@ import (
// Type aliases for convenience // Type aliases for convenience
type ( type (
Graph = graph.Graph[Value, Value] Graph = graph.Graph[Value, Value]
OpenEdge = graph.OpenEdge[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 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 var toks []LexerToken
@ -309,6 +309,17 @@ func (d *decoder) decode(lexer Lexer) (*Graph, error) {
toks = append(toks, tok) 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) val, _, _, err := d.parseGraphValue(toks, false)
if err != nil { if err != nil {
@ -326,3 +337,17 @@ func DecodeLexer(lexer Lexer) (*Graph, error) {
decoder := &decoder{} decoder := &decoder{}
return decoder.decode(lexer) 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
}

View File

@ -52,7 +52,7 @@ func TestDecoder(t *testing.T) {
tOut( tOut(
n("a"), n("a"),
vOut(n("b"), vOut(n("b"),
i(1)), i(1)),
), ),
), ),
}, },

View File

@ -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. // 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] { func ValueOut[E, V Value](edgeVal E, val V) *OpenEdge[E, V] {
return &OpenEdge[E, V]{ return &OpenEdge[E, V]{
val: &val, val: &val,
edgeVal: edgeVal, edgeVal: edgeVal,
} }
} }
@ -127,7 +127,7 @@ func TupleOut[E, V Value](edgeVal E, ins ...*OpenEdge[E, V]) *OpenEdge[E, V] {
var ( var (
zero V zero V
in = ins[0] in = ins[0]
) )
if edgeVal.Equal(zero) { 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]{ return &OpenEdge[E, V]{
tup: ins, tup: ins,
edgeVal: edgeVal, edgeVal: edgeVal,
} }
} }
type graphValueIn[E, V Value] struct { type graphValueIn[E, V Value] struct {
val V val V
edge *OpenEdge[E, 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 // lots of O(N) operations, unnecessary copying on changes, and duplicate data
// in memory. // in memory.
type Graph[E, V Value] struct { type Graph[E, V Value] struct {
edges []*OpenEdge[E, V] edges []*OpenEdge[E, V]
valIns []graphValueIn[E, V] valIns []graphValueIn[E, V]
} }
func (g *Graph[E, V]) cp() *Graph[E, V] { func (g *Graph[E, V]) cp() *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)), valIns: make([]graphValueIn[E, V], len(g.valIns)),
} }
copy(cp.edges, g.edges) 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] { func (g *Graph[E, V]) AddValueIn(val V, oe *OpenEdge[E, V]) *Graph[E, V] {
valIn := graphValueIn[E, V]{ valIn := graphValueIn[E, V]{
val: val, val: val,
edge: oe, edge: oe,
} }
@ -284,14 +284,13 @@ outer:
return true return true
} }
func mapReduce[Ea, Va Value, Vb any]( func mapReduce[Ea, Va Value, Vb any](
root *OpenEdge[Ea, Va], root *OpenEdge[Ea, Va],
mapVal func(Va) (Vb, error), mapVal func(Va) (Vb, error),
reduceEdge func(*OpenEdge[Ea, Va], []Vb) (Vb, error), reduceEdge func(*OpenEdge[Ea, Va], []Vb) (Vb, error),
) ( ) (
Vb, error, Vb, error,
){ ) {
if valA, ok := root.FromValue(); ok { 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 { type reducedEdge[Ea, Va Value, Vb any] struct {
edgeA *OpenEdge[Ea, Va] edgeA *OpenEdge[Ea, Va]
valB Vb // result valB Vb // result
} }
// MapReduce recursively computes a resultant Value of type Vb from an // 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), reduceEdge func(Ea, []Vb) (Vb, error),
) ( ) (
Vb, error, Vb, error,
){ ) {
var ( var (
zeroB Vb zeroB Vb
@ -370,7 +369,7 @@ func MapReduce[Ea, Va Value, Vb any](
// reduction is only performed a single time for each value/edge. // reduction is only performed a single time for each value/edge.
// //
// NOTE this is not implemented very efficiently. // NOTE this is not implemented very efficiently.
mappedVals []mappedVal[Va, Vb] mappedVals []mappedVal[Va, Vb]
reducedEdges []reducedEdge[Ea, 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]{ reducedEdges = append(reducedEdges, reducedEdge[Ea, Va, Vb]{
edgeA: edgeA, edgeA: edgeA,
valB: valB, valB: valB,
}) })
return valB, nil return valB, nil

View File

@ -1,8 +1,8 @@
package graph package graph
import ( import (
"fmt"
"errors" "errors"
"fmt"
"strconv" "strconv"
"testing" "testing"
@ -129,7 +129,7 @@ func TestEqual(t *testing.T) {
type mapReduceTestEdge struct { type mapReduceTestEdge struct {
name string name string
fn func([]int) int fn func([]int) int
done bool done bool
} }
@ -162,9 +162,9 @@ func (e *mapReduceTestEdge) do(ii []int) int {
func TestMapReduce(t *testing.T) { func TestMapReduce(t *testing.T) {
type ( type (
Va = I Va = I
Vb = int Vb = int
Ea = *mapReduceTestEdge Ea = *mapReduceTestEdge
edge = OpenEdge[Ea, Va] edge = OpenEdge[Ea, Va]
) )
@ -180,7 +180,7 @@ func TestMapReduce(t *testing.T) {
return TupleOut[Ea, Va](edge, ins...) return TupleOut[Ea, Va](edge, ins...)
} }
add := func() *mapReduceTestEdge{ add := func() *mapReduceTestEdge {
return &mapReduceTestEdge{ return &mapReduceTestEdge{
name: "add", name: "add",
fn: func(ii []int) int { fn: func(ii []int) int {
@ -193,7 +193,7 @@ func TestMapReduce(t *testing.T) {
} }
} }
mul := func() *mapReduceTestEdge{ mul := func() *mapReduceTestEdge {
return &mapReduceTestEdge{ return &mapReduceTestEdge{
name: "mul", name: "mul",
fn: func(ii []int) int { fn: func(ii []int) int {
@ -225,15 +225,15 @@ func TestMapReduce(t *testing.T) {
} }
tests := []struct { tests := []struct {
in *edge in *edge
exp int exp int
}{ }{
{ {
in: vOut(nil, 1), in: vOut(nil, 1),
exp: 10, exp: 10,
}, },
{ {
in: vOut(add(), 1), in: vOut(add(), 1),
exp: 10, exp: 10,
}, },
{ {

View File

@ -30,7 +30,7 @@ func evalThunks(args []Thunk) Thunk {
return func() (Value, error) { return func() (Value, error) {
var ( var (
err error err error
tupVals = make([]Value, len(args)) 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 // 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 // having been evaluated yet) and return a Thunk which will perform some
// internal processing on those arguments and return a resultant Value. // internal processing on those arguments and return a resultant Value.

View File

@ -115,9 +115,9 @@ func (m ScopeMap) NewScope() Scope {
type graphScope struct { type graphScope struct {
*gg.Graph *gg.Graph
in Thunk in Thunk
parent Scope parent Scope
op Operation 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.
@ -139,9 +139,9 @@ type graphScope struct {
func ScopeFromGraph(g *gg.Graph, in Thunk, parent Scope, op Operation) 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, op: op,
} }
} }

View File

@ -74,5 +74,4 @@ var GlobalScope = ScopeMap{
"recur": Value{Operation: OperationFunc(func(args []Thunk, op Operation) (Thunk, error) { "recur": Value{Operation: OperationFunc(func(args []Thunk, op Operation) (Thunk, error) {
return op.Perform(args, op) return op.Perform(args, op)
})}, })},
} }

View File

@ -2,8 +2,8 @@
package vm package vm
import ( import (
"io"
"fmt" "fmt"
"io"
"strings" "strings"
"github.com/mediocregopher/ginger/gg" "github.com/mediocregopher/ginger/gg"