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:
parent
c4dd673bf4
commit
9c48232ac1
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
2
gg/gg.go
2
gg/gg.go
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
24
vm/op.go
24
vm/op.go
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user