Allow Graph edge and vertex values to be different types

Lots of type aliases in use with `gg` to make this not be a verbose
clusterfuck.
This commit is contained in:
Brian Picciano 2021-12-30 09:56:20 -07:00
parent c4dd673bf4
commit 9c48232ac1
7 changed files with 114 additions and 109 deletions

View File

@ -9,6 +9,12 @@ import (
"github.com/mediocregopher/ginger/graph" "github.com/mediocregopher/ginger/graph"
) )
// Type aliases for convenience
type (
Graph = graph.Graph[Value, Value]
OpenEdge = graph.OpenEdge[Value, Value]
)
// Punctuations which are used in the gg file format. // Punctuations which are used in the gg file format.
const ( const (
punctTerm = ";" punctTerm = ";"
@ -90,7 +96,7 @@ func (d *decoder) parseSingleValue(
func (d *decoder) parseOpenEdge( func (d *decoder) parseOpenEdge(
toks []LexerToken, toks []LexerToken,
) ( ) (
*graph.OpenEdge[Value], []LexerToken, error, *OpenEdge, []LexerToken, error,
) { ) {
if isPunct(toks[0], punctOpenTuple) { if isPunct(toks[0], punctOpenTuple) {
@ -137,7 +143,7 @@ func (d *decoder) parseOpenEdge(
return nil, nil, err return nil, nil, err
} }
oe = graph.TupleOut[Value]([]*graph.OpenEdge[Value]{oe}, val) oe = graph.TupleOut[Value]([]*OpenEdge{oe}, val)
return oe, toks, nil return oe, toks, nil
} }
@ -145,12 +151,12 @@ func (d *decoder) parseOpenEdge(
func (d *decoder) parseTuple( func (d *decoder) parseTuple(
toks []LexerToken, toks []LexerToken,
) ( ) (
*graph.OpenEdge[Value], []LexerToken, error, *OpenEdge, []LexerToken, error,
) { ) {
openTok, toks := toks[0], toks[1:] openTok, toks := toks[0], toks[1:]
var edges []*graph.OpenEdge[Value] var edges []*OpenEdge
for { for {
@ -163,7 +169,7 @@ func (d *decoder) parseTuple(
} }
var ( var (
oe *graph.OpenEdge[Value] oe *OpenEdge
err error err error
) )
@ -203,7 +209,7 @@ func (d *decoder) parseGraphValue(
openTok, toks = toks[0], toks[1:] openTok, toks = toks[0], toks[1:]
} }
g := new(graph.Graph[Value]) g := new(Graph)
for { for {
@ -254,7 +260,7 @@ func (d *decoder) parseGraphValue(
return val, toks, termed, nil return val, toks, termed, nil
} }
func (d *decoder) parseValIn(into *graph.Graph[Value], toks []LexerToken) (*graph.Graph[Value], []LexerToken, error) { func (d *decoder) parseValIn(into *Graph, toks []LexerToken) (*Graph, []LexerToken, error) {
if len(toks) == 0 { if len(toks) == 0 {
return into, nil, nil return into, nil, nil
@ -285,7 +291,7 @@ func (d *decoder) parseValIn(into *graph.Graph[Value], toks []LexerToken) (*grap
return into.AddValueIn(oe, dstVal), toks, nil return into.AddValueIn(oe, dstVal), toks, nil
} }
func (d *decoder) decode(lexer Lexer) (*graph.Graph[Value], error) { func (d *decoder) decode(lexer Lexer) (*Graph, error) {
var toks []LexerToken var toks []LexerToken
@ -316,7 +322,7 @@ func (d *decoder) decode(lexer Lexer) (*graph.Graph[Value], error) {
// construct a Graph according to the rules of the gg file format. DecodeLexer // construct a Graph according to the rules of the gg file format. DecodeLexer
// will only return an error if there is a non-EOF file returned from the Lexer, // will only return an error if there is a non-EOF file returned from the Lexer,
// or the tokens read cannot be used to construct a valid Graph. // or the tokens read cannot be used to construct a valid Graph.
func DecodeLexer(lexer Lexer) (*graph.Graph[Value], error) { func DecodeLexer(lexer Lexer) (*Graph, error) {
decoder := &decoder{} decoder := &decoder{}
return decoder.decode(lexer) return decoder.decode(lexer)
} }

View File

@ -11,7 +11,7 @@ import (
func TestDecoder(t *testing.T) { func TestDecoder(t *testing.T) {
zeroGraph := new(graph.Graph[Value]) zeroGraph := new(Graph)
i := func(i int64) Value { i := func(i int64) Value {
return Value{Number: &i} return Value{Number: &i}
@ -21,19 +21,17 @@ func TestDecoder(t *testing.T) {
return Value{Name: &n} return Value{Name: &n}
} }
vOut := func(val, edgeVal Value) *graph.OpenEdge[Value] { vOut := func(val, edgeVal Value) *OpenEdge {
return graph.ValueOut(val, edgeVal) return graph.ValueOut(val, edgeVal)
} }
tOut := func(ins []*graph.OpenEdge[Value], edgeVal Value) *graph.OpenEdge[Value] { tOut := func(ins []*OpenEdge, edgeVal Value) *OpenEdge {
return graph.TupleOut(ins, edgeVal) return graph.TupleOut(ins, edgeVal)
} }
type openEdge = *graph.OpenEdge[Value]
tests := []struct { tests := []struct {
in string in string
exp *graph.Graph[Value] exp *Graph
}{ }{
{ {
in: "", in: "",
@ -51,7 +49,7 @@ func TestDecoder(t *testing.T) {
in: "out = a < b < 1;", in: "out = a < b < 1;",
exp: zeroGraph.AddValueIn( exp: zeroGraph.AddValueIn(
tOut( tOut(
[]openEdge{vOut(i(1), n("b"))}, []*OpenEdge{vOut(i(1), n("b"))},
n("a"), n("a"),
), ),
n("out"), n("out"),
@ -61,12 +59,12 @@ func TestDecoder(t *testing.T) {
in: "out = a < b < (1; c < 2; d < e < 3;);", in: "out = a < b < (1; c < 2; d < e < 3;);",
exp: zeroGraph.AddValueIn( exp: zeroGraph.AddValueIn(
tOut( tOut(
[]openEdge{tOut( []*OpenEdge{tOut(
[]openEdge{ []*OpenEdge{
vOut(i(1), ZeroValue), vOut(i(1), ZeroValue),
vOut(i(2), n("c")), vOut(i(2), n("c")),
tOut( tOut(
[]openEdge{vOut(i(3), n("e"))}, []*OpenEdge{vOut(i(3), n("e"))},
n("d"), n("d"),
), ),
}, },
@ -81,11 +79,11 @@ func TestDecoder(t *testing.T) {
in: "out = a < b < (1; c < (d < 2; 3;); );", in: "out = a < b < (1; c < (d < 2; 3;); );",
exp: zeroGraph.AddValueIn( exp: zeroGraph.AddValueIn(
tOut( tOut(
[]openEdge{tOut( []*OpenEdge{tOut(
[]openEdge{ []*OpenEdge{
vOut(i(1), ZeroValue), vOut(i(1), ZeroValue),
tOut( tOut(
[]openEdge{ []*OpenEdge{
vOut(i(2), n("d")), vOut(i(2), n("d")),
vOut(i(3), ZeroValue), vOut(i(3), ZeroValue),
}, },
@ -107,7 +105,7 @@ func TestDecoder(t *testing.T) {
AddValueIn(vOut(i(1), ZeroValue), n("a")). AddValueIn(vOut(i(1), ZeroValue), n("a")).
AddValueIn( AddValueIn(
tOut( tOut(
[]openEdge{ []*OpenEdge{
vOut(i(2), n("d")), vOut(i(2), n("d")),
}, },
n("c"), n("c"),
@ -124,7 +122,7 @@ func TestDecoder(t *testing.T) {
in: "out = a < { b = 1; } < 2;", in: "out = a < { b = 1; } < 2;",
exp: zeroGraph.AddValueIn( exp: zeroGraph.AddValueIn(
tOut( tOut(
[]openEdge{ []*OpenEdge{
vOut( vOut(
i(2), i(2),
Value{Graph: zeroGraph. Value{Graph: zeroGraph.

View File

@ -16,7 +16,7 @@ type Value struct {
// Only one of these fields may be set // Only one of these fields may be set
Name *string Name *string
Number *int64 Number *int64
Graph *graph.Graph[Value] Graph *Graph
// TODO coming soon! // TODO coming soon!
// String *string // String *string

View File

@ -15,16 +15,18 @@ type Value interface {
String() string String() string
} }
// OpenEdge is an un-realized Edge which can't be used for anything except // OpenEdge consists of the edge value (E) and source vertex value (V) of an
// constructing graphs. It has no meaning on its own. // edge in a Graph. When passed into the AddValueIn method a full edge is
type OpenEdge[V Value] struct { // created. An OpenEdge can also be sourced from a tuple vertex, whose value is
// an ordered set of OpenEdges of this same type.
type OpenEdge[E, V Value] struct {
val *V val *V
tup []*OpenEdge[V] tup []*OpenEdge[E, V]
edgeVal V edgeVal E
} }
func (oe *OpenEdge[V]) equal(oe2 *OpenEdge[V]) bool { func (oe *OpenEdge[E, V]) equal(oe2 *OpenEdge[E, V]) bool {
if !oe.edgeVal.Equal(oe2.edgeVal) { if !oe.edgeVal.Equal(oe2.edgeVal) {
return false return false
} }
@ -46,7 +48,7 @@ func (oe *OpenEdge[V]) equal(oe2 *OpenEdge[V]) bool {
return true return true
} }
func (oe *OpenEdge[V]) String() string { func (oe *OpenEdge[E, V]) String() string {
vertexType := "tup" vertexType := "tup"
@ -75,20 +77,20 @@ func (oe *OpenEdge[V]) String() string {
// the previous edge value. // the previous edge value.
// //
// NOTE I _think_ this can be factored out once Graph is genericized. // NOTE I _think_ this can be factored out once Graph is genericized.
func (oe *OpenEdge[V]) WithEdgeValue(val V) *OpenEdge[V] { func (oe *OpenEdge[E, V]) WithEdgeValue(val E) *OpenEdge[E, V] {
oeCp := *oe oeCp := *oe
oeCp.edgeVal = val oeCp.edgeVal = val
return &oeCp return &oeCp
} }
// EdgeValue returns the Value which lies on the edge itself. // EdgeValue returns the Value which lies on the edge itself.
func (oe OpenEdge[V]) EdgeValue() V { func (oe OpenEdge[E, V]) EdgeValue() E {
return oe.edgeVal return oe.edgeVal
} }
// FromValue returns the Value from which the OpenEdge was created via ValueOut, // FromValue returns the Value from which the OpenEdge was created via ValueOut,
// or false if it wasn't created via ValueOut. // or false if it wasn't created via ValueOut.
func (oe OpenEdge[V]) FromValue() (V, bool) { func (oe OpenEdge[E, V]) FromValue() (V, bool) {
if oe.val == nil { if oe.val == nil {
var zero V var zero V
return zero, false return zero, false
@ -99,7 +101,7 @@ func (oe OpenEdge[V]) FromValue() (V, bool) {
// FromTuple returns the tuple of OpenEdges from which the OpenEdge was created // FromTuple returns the tuple of OpenEdges from which the OpenEdge was created
// via TupleOut, or false if it wasn't created via TupleOut. // via TupleOut, or false if it wasn't created via TupleOut.
func (oe OpenEdge[V]) FromTuple() ([]*OpenEdge[V], bool) { func (oe OpenEdge[E, V]) FromTuple() ([]*OpenEdge[E, V], bool) {
if oe.val != nil { if oe.val != nil {
return nil, false return nil, false
} }
@ -109,8 +111,8 @@ func (oe OpenEdge[V]) FromTuple() ([]*OpenEdge[V], bool) {
// ValueOut creates a OpenEdge which, when used to construct a Graph, represents // ValueOut creates a OpenEdge which, when used to construct a Graph, represents
// 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[V Value](val, edgeVal V) *OpenEdge[V] { func ValueOut[E, V Value](val V, edgeVal E) *OpenEdge[E, V] {
return &OpenEdge[V]{ return &OpenEdge[E, V]{
val: &val, val: &val,
edgeVal: edgeVal, edgeVal: edgeVal,
} }
@ -119,7 +121,7 @@ func ValueOut[V Value](val, edgeVal V) *OpenEdge[V] {
// TupleOut creates an OpenEdge which, when used to construct a Graph, // TupleOut creates an OpenEdge which, when used to construct a Graph,
// represents an edge (with edgeVal attached to it) coming from the vertex // represents an edge (with edgeVal attached to it) coming from the vertex
// comprised of the given ordered-set of input edges. // comprised of the given ordered-set of input edges.
func TupleOut[V Value](ins []*OpenEdge[V], edgeVal V) *OpenEdge[V] { func TupleOut[E, V Value](ins []*OpenEdge[E, V], edgeVal E) *OpenEdge[E, V] {
if len(ins) == 1 { if len(ins) == 1 {
@ -138,44 +140,44 @@ func TupleOut[V Value](ins []*OpenEdge[V], edgeVal V) *OpenEdge[V] {
} }
return &OpenEdge[V]{ return &OpenEdge[E, V]{
tup: ins, tup: ins,
edgeVal: edgeVal, edgeVal: edgeVal,
} }
} }
type graphValueIn[V Value] struct { type graphValueIn[E, V Value] struct {
val V val V
edge *OpenEdge[V] edge *OpenEdge[E, V]
} }
func (valIn graphValueIn[V]) equal(valIn2 graphValueIn[V]) bool { func (valIn graphValueIn[E, V]) equal(valIn2 graphValueIn[E, V]) bool {
return valIn.val.Equal(valIn2.val) && valIn.edge.equal(valIn2.edge) return valIn.val.Equal(valIn2.val) && valIn.edge.equal(valIn2.edge)
} }
// Graph is an immutable container of a set of vertices. The Graph keeps track // Graph is an immutable container of a set of vertices. The Graph keeps track
// of all Values which terminate an OpenEdge (which may be a tree of Value/Tuple // of all Values which terminate an OpenEdge. E indicates the type of edge
// vertices). // values, while V indicates the type of vertex values.
// //
// NOTE The current implementation of Graph is incredibly inefficient, there's // NOTE The current implementation of Graph is incredibly inefficient, there's
// 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[V Value] struct { type Graph[E, V Value] struct {
edges []*OpenEdge[V] edges []*OpenEdge[E, V]
valIns []graphValueIn[V] valIns []graphValueIn[E, V]
} }
func (g *Graph[V]) cp() *Graph[V] { func (g *Graph[E, V]) cp() *Graph[E, V] {
cp := &Graph[V]{ cp := &Graph[E, V]{
edges: make([]*OpenEdge[V], len(g.edges)), edges: make([]*OpenEdge[E, V], len(g.edges)),
valIns: make([]graphValueIn[V], len(g.valIns)), valIns: make([]graphValueIn[E, V], len(g.valIns)),
} }
copy(cp.edges, g.edges) copy(cp.edges, g.edges)
copy(cp.valIns, g.valIns) copy(cp.valIns, g.valIns)
return cp return cp
} }
func (g *Graph[V]) String() string { func (g *Graph[E, V]) String() string {
var strs []string var strs []string
@ -192,7 +194,7 @@ func (g *Graph[V]) String() string {
// NOTE this method is used more for its functionality than for any performance // NOTE this method is used more for its functionality than for any performance
// reasons... it's incredibly inefficient in how it deduplicates edges, but by // reasons... it's incredibly inefficient in how it deduplicates edges, but by
// doing the deduplication we enable the graph map operation to work correctly. // doing the deduplication we enable the graph map operation to work correctly.
func (g *Graph[V]) dedupeEdge(edge *OpenEdge[V]) *OpenEdge[V] { func (g *Graph[E, V]) dedupeEdge(edge *OpenEdge[E, V]) *OpenEdge[E, V] {
// check if there's an existing edge which is fully equivalent in the graph // check if there's an existing edge which is fully equivalent in the graph
// already, and if so return that. // already, and if so return that.
@ -210,7 +212,7 @@ func (g *Graph[V]) dedupeEdge(edge *OpenEdge[V]) *OpenEdge[V] {
// this edge is a tuple edge, it's possible that one of its sub-edges is // this edge is a tuple edge, it's possible that one of its sub-edges is
// already in the graph. dedupe each sub-edge individually. // already in the graph. dedupe each sub-edge individually.
tupEdges := make([]*OpenEdge[V], len(edge.tup)) tupEdges := make([]*OpenEdge[E, V], len(edge.tup))
for i := range edge.tup { for i := range edge.tup {
tupEdges[i] = g.dedupeEdge(edge.tup[i]) tupEdges[i] = g.dedupeEdge(edge.tup[i])
@ -223,9 +225,9 @@ func (g *Graph[V]) dedupeEdge(edge *OpenEdge[V]) *OpenEdge[V] {
// Graph (ie, all those added via AddValueIn). // Graph (ie, all those added via AddValueIn).
// //
// The returned slice should not be modified. // The returned slice should not be modified.
func (g *Graph[V]) ValueIns(val Value) []*OpenEdge[V] { func (g *Graph[E, V]) ValueIns(val Value) []*OpenEdge[E, V] {
var edges []*OpenEdge[V] var edges []*OpenEdge[E, V]
for _, valIn := range g.valIns { for _, valIn := range g.valIns {
if valIn.val.Equal(val) { if valIn.val.Equal(val) {
@ -238,9 +240,9 @@ func (g *Graph[V]) ValueIns(val Value) []*OpenEdge[V] {
// AddValueIn takes a OpenEdge and connects it to the Value vertex containing // AddValueIn takes a OpenEdge and connects it to the Value vertex containing
// val, returning the new Graph which reflects that connection. // val, returning the new Graph which reflects that connection.
func (g *Graph[V]) AddValueIn(oe *OpenEdge[V], val V) *Graph[V] { func (g *Graph[E, V]) AddValueIn(oe *OpenEdge[E, V], val V) *Graph[E, V] {
valIn := graphValueIn[V]{ valIn := graphValueIn[E, V]{
val: val, val: val,
edge: oe, edge: oe,
} }
@ -260,7 +262,7 @@ func (g *Graph[V]) AddValueIn(oe *OpenEdge[V], val V) *Graph[V] {
} }
// Equal returns whether or not the two Graphs are equivalent in value. // Equal returns whether or not the two Graphs are equivalent in value.
func (g *Graph[V]) Equal(g2 *Graph[V]) bool { func (g *Graph[E, V]) Equal(g2 *Graph[E, V]) bool {
if len(g.valIns) != len(g2.valIns) { if len(g.valIns) != len(g2.valIns) {
return false return false

View File

@ -17,11 +17,11 @@ func TestEqual(t *testing.T) {
var ( var (
zeroValue S zeroValue S
zeroGraph = new(Graph[S]) zeroGraph = new(Graph[S, S])
) )
tests := []struct { tests := []struct {
a, b *Graph[S] a, b *Graph[S, S]
exp bool exp bool
}{ }{
{ {
@ -31,78 +31,78 @@ func TestEqual(t *testing.T) {
}, },
{ {
a: zeroGraph, a: zeroGraph,
b: zeroGraph.AddValueIn(ValueOut[S]("in", "incr"), "out"), b: zeroGraph.AddValueIn(ValueOut[S, S]("in", "incr"), "out"),
exp: false, exp: false,
}, },
{ {
a: zeroGraph.AddValueIn(ValueOut[S]("in", "incr"), "out"), a: zeroGraph.AddValueIn(ValueOut[S, S]("in", "incr"), "out"),
b: zeroGraph.AddValueIn(ValueOut[S]("in", "incr"), "out"), b: zeroGraph.AddValueIn(ValueOut[S, S]("in", "incr"), "out"),
exp: true, exp: true,
}, },
{ {
a: zeroGraph.AddValueIn(ValueOut[S]("in", "incr"), "out"), a: zeroGraph.AddValueIn(ValueOut[S, S]("in", "incr"), "out"),
b: zeroGraph.AddValueIn(TupleOut[S]([]*OpenEdge[S]{ b: zeroGraph.AddValueIn(TupleOut[S, S]([]*OpenEdge[S, S]{
ValueOut[S]("in", "ident"), ValueOut[S, S]("in", "ident"),
ValueOut[S]("1", "ident"), ValueOut[S, S]("1", "ident"),
}, "add"), "out"), }, "add"), "out"),
exp: false, exp: false,
}, },
{ {
// tuples are different order // tuples are different order
a: zeroGraph.AddValueIn(TupleOut[S]([]*OpenEdge[S]{ a: zeroGraph.AddValueIn(TupleOut[S, S]([]*OpenEdge[S, S]{
ValueOut[S]("1", "ident"), ValueOut[S, S]("1", "ident"),
ValueOut[S]("in", "ident"), ValueOut[S, S]("in", "ident"),
}, "add"), "out"), }, "add"), "out"),
b: zeroGraph.AddValueIn(TupleOut[S]([]*OpenEdge[S]{ b: zeroGraph.AddValueIn(TupleOut[S, S]([]*OpenEdge[S, S]{
ValueOut[S]("in", "ident"), ValueOut[S, S]("in", "ident"),
ValueOut[S]("1", "ident"), ValueOut[S, S]("1", "ident"),
}, "add"), "out"), }, "add"), "out"),
exp: false, exp: false,
}, },
{ {
// tuple with no edge value and just a single input edge should be // tuple with no edge value and just a single input edge should be
// equivalent to just that edge. // equivalent to just that edge.
a: zeroGraph.AddValueIn(TupleOut[S]([]*OpenEdge[S]{ a: zeroGraph.AddValueIn(TupleOut[S, S]([]*OpenEdge[S, S]{
ValueOut[S]("1", "ident"), ValueOut[S, S]("1", "ident"),
}, zeroValue), "out"), }, zeroValue), "out"),
b: zeroGraph.AddValueIn(ValueOut[S]("1", "ident"), "out"), b: zeroGraph.AddValueIn(ValueOut[S, S]("1", "ident"), "out"),
exp: true, exp: true,
}, },
{ {
// tuple with an edge value and just a single input edge that has no // tuple with an edge value and just a single input edge that has no
// edgeVal should be equivalent to just that edge with the tuple's // edgeVal should be equivalent to just that edge with the tuple's
// edge value. // edge value.
a: zeroGraph.AddValueIn(TupleOut[S]([]*OpenEdge[S]{ a: zeroGraph.AddValueIn(TupleOut[S, S]([]*OpenEdge[S, S]{
ValueOut[S]("1", zeroValue), ValueOut[S, S]("1", zeroValue),
}, "ident"), "out"), }, "ident"), "out"),
b: zeroGraph.AddValueIn(ValueOut[S]("1", "ident"), "out"), b: zeroGraph.AddValueIn(ValueOut[S, S]("1", "ident"), "out"),
exp: true, exp: true,
}, },
{ {
a: zeroGraph. a: zeroGraph.
AddValueIn(ValueOut[S]("in", "incr"), "out"). AddValueIn(ValueOut[S, S]("in", "incr"), "out").
AddValueIn(ValueOut[S]("in2", "incr2"), "out2"), AddValueIn(ValueOut[S, S]("in2", "incr2"), "out2"),
b: zeroGraph. b: zeroGraph.
AddValueIn(ValueOut[S]("in", "incr"), "out"), AddValueIn(ValueOut[S, S]("in", "incr"), "out"),
exp: false, exp: false,
}, },
{ {
a: zeroGraph. a: zeroGraph.
AddValueIn(ValueOut[S]("in", "incr"), "out"). AddValueIn(ValueOut[S, S]("in", "incr"), "out").
AddValueIn(ValueOut[S]("in2", "incr2"), "out2"), AddValueIn(ValueOut[S, S]("in2", "incr2"), "out2"),
b: zeroGraph. b: zeroGraph.
AddValueIn(ValueOut[S]("in", "incr"), "out"). AddValueIn(ValueOut[S, S]("in", "incr"), "out").
AddValueIn(ValueOut[S]("in2", "incr2"), "out2"), AddValueIn(ValueOut[S, S]("in2", "incr2"), "out2"),
exp: true, exp: true,
}, },
{ {
// order of value ins shouldn't matter // order of value ins shouldn't matter
a: zeroGraph. a: zeroGraph.
AddValueIn(ValueOut[S]("in", "incr"), "out"). AddValueIn(ValueOut[S, S]("in", "incr"), "out").
AddValueIn(ValueOut[S]("in2", "incr2"), "out2"), AddValueIn(ValueOut[S, S]("in2", "incr2"), "out2"),
b: zeroGraph. b: zeroGraph.
AddValueIn(ValueOut[S]("in2", "incr2"), "out2"). AddValueIn(ValueOut[S, S]("in2", "incr2"), "out2").
AddValueIn(ValueOut[S]("in", "incr"), "out"), AddValueIn(ValueOut[S, S]("in", "incr"), "out"),
exp: true, exp: true,
}, },
} }

View File

@ -17,12 +17,12 @@ var (
// The Scope passed into Perform can be used to Evaluate the OpenEdge, as // The Scope passed into Perform can be used to Evaluate the OpenEdge, as
// needed. // needed.
type Operation interface { type Operation interface {
Perform(*graph.OpenEdge[gg.Value], Scope) (Value, error) Perform(*gg.OpenEdge, Scope) (Value, error)
} }
func preEvalValOp(fn func(Value) (Value, error)) Operation { func preEvalValOp(fn func(Value) (Value, error)) Operation {
return OperationFunc(func(edge *graph.OpenEdge[gg.Value], scope Scope) (Value, error) { return OperationFunc(func(edge *gg.OpenEdge, scope Scope) (Value, error) {
edgeVal, err := EvaluateEdge(edge, scope) edgeVal, err := EvaluateEdge(edge, scope)
@ -36,20 +36,20 @@ func preEvalValOp(fn func(Value) (Value, error)) Operation {
// NOTE this is a giant hack to get around the fact that we're not yet // NOTE this is a giant hack to get around the fact that we're not yet
// using a genericized Graph implementation, so when we do AddValueIn // using a genericized Graph implementation, so when we do AddValueIn
// on a graph.Graph[gg.Value] we can't use a Tuple value (because gg has no Tuple // on a gg.Graph we can't use a Tuple value (because gg has no Tuple
// value), we have to use a Tuple vertex instead. // value), we have to use a Tuple vertex instead.
// //
// This also doesn't yet support passing an operation as a value to another // This also doesn't yet support passing an operation as a value to another
// operation. // operation.
func preEvalEdgeOp(fn func(*graph.OpenEdge[gg.Value]) (Value, error)) Operation { func preEvalEdgeOp(fn func(*gg.OpenEdge) (Value, error)) Operation {
return preEvalValOp(func(val Value) (Value, error) { return preEvalValOp(func(val Value) (Value, error) {
var edge *graph.OpenEdge[gg.Value] var edge *gg.OpenEdge
if len(val.Tuple) > 0 { if len(val.Tuple) > 0 {
tupEdges := make([]*graph.OpenEdge[gg.Value], len(val.Tuple)) tupEdges := make([]*gg.OpenEdge, len(val.Tuple))
for i := range val.Tuple { for i := range val.Tuple {
tupEdges[i] = graph.ValueOut[gg.Value](val.Tuple[i].Value, gg.ZeroValue) tupEdges[i] = graph.ValueOut[gg.Value](val.Tuple[i].Value, gg.ZeroValue)
@ -69,7 +69,7 @@ func preEvalEdgeOp(fn func(*graph.OpenEdge[gg.Value]) (Value, error)) Operation
} }
type graphOp struct { type graphOp struct {
*graph.Graph[gg.Value] *gg.Graph
scope Scope scope Scope
} }
@ -80,16 +80,16 @@ type graphOp struct {
// of the given Graph, then that resultant graph and the given parent Scope are // of the given Graph, then that resultant graph and the given parent Scope are
// used to construct a new Scope. The "out" name value is Evaluated on that // used to construct a new Scope. The "out" name value is Evaluated on that
// Scope to obtain a resultant Value. // Scope to obtain a resultant Value.
func OperationFromGraph(g *graph.Graph[gg.Value], scope Scope) Operation { func OperationFromGraph(g *gg.Graph, scope Scope) Operation {
return &graphOp{ return &graphOp{
Graph: g, Graph: g,
scope: scope, scope: scope,
} }
} }
func (g *graphOp) Perform(edge *graph.OpenEdge[gg.Value], scope Scope) (Value, error) { func (g *graphOp) Perform(edge *gg.OpenEdge, scope Scope) (Value, error) {
return preEvalEdgeOp(func(edge *graph.OpenEdge[gg.Value]) (Value, error) { return preEvalEdgeOp(func(edge *gg.OpenEdge) (Value, error) {
scope = ScopeFromGraph( scope = ScopeFromGraph(
g.Graph.AddValueIn(edge, inVal.Value), g.Graph.AddValueIn(edge, inVal.Value),
@ -103,9 +103,9 @@ func (g *graphOp) Perform(edge *graph.OpenEdge[gg.Value], scope Scope) (Value, e
} }
// OperationFunc is a function which implements the Operation interface. // OperationFunc is a function which implements the Operation interface.
type OperationFunc func(*graph.OpenEdge[gg.Value], Scope) (Value, error) type OperationFunc func(*gg.OpenEdge, Scope) (Value, error)
// Perform calls the underlying OperationFunc directly. // Perform calls the underlying OperationFunc directly.
func (f OperationFunc) Perform(edge *graph.OpenEdge[gg.Value], scope Scope) (Value, error) { func (f OperationFunc) Perform(edge *gg.OpenEdge, scope Scope) (Value, error) {
return f(edge, scope) return f(edge, scope)
} }

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/mediocregopher/ginger/gg" "github.com/mediocregopher/ginger/gg"
"github.com/mediocregopher/ginger/graph"
) )
// Scope encapsulates a set of names and the values they indicate, or the means // Scope encapsulates a set of names and the values they indicate, or the means
@ -23,7 +22,7 @@ type Scope interface {
// edgeToValue ignores the edgeValue, it only evaluates the edge's vertex as a // edgeToValue ignores the edgeValue, it only evaluates the edge's vertex as a
// Value. // Value.
func edgeToValue(edge *graph.OpenEdge[gg.Value], scope Scope) (Value, error) { func edgeToValue(edge *gg.OpenEdge, scope Scope) (Value, error) {
if ggVal, ok := edge.FromValue(); ok { if ggVal, ok := edge.FromValue(); ok {
@ -61,7 +60,7 @@ func edgeToValue(edge *graph.OpenEdge[gg.Value], scope Scope) (Value, error) {
// 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 *graph.OpenEdge[gg.Value], scope Scope) (Value, error) { func EvaluateEdge(edge *gg.OpenEdge, scope Scope) (Value, error) {
edgeVal := Value{Value: edge.EdgeValue()} edgeVal := Value{Value: edge.EdgeValue()}
@ -122,7 +121,7 @@ func (m ScopeMap) NewScope() Scope {
} }
type graphScope struct { type graphScope struct {
*graph.Graph[gg.Value] *gg.Graph
parent Scope parent Scope
} }
@ -139,7 +138,7 @@ 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 *graph.Graph[gg.Value], parent Scope) Scope { func ScopeFromGraph(g *gg.Graph, parent Scope) Scope {
return &graphScope{ return &graphScope{
Graph: g, Graph: g,
parent: parent, parent: parent,