Compare commits
No commits in common. "303d40a6c3238735eff9446ba598bc487c69ef02" and "e113e96f1fe6ffbe64d5bccce2a42b00b07517fd" have entirely different histories.
303d40a6c3
...
e113e96f1f
29
gg/v2/gg.bnf
29
gg/v2/gg.bnf
@ -5,19 +5,20 @@
|
|||||||
|
|
||||||
<name> ::= (<letter> | <mark>) (<letter> | <mark> | <digit>)*
|
<name> ::= (<letter> | <mark>) (<letter> | <mark> | <digit>)*
|
||||||
|
|
||||||
<tuple> ::= "(" <tuple-tail>
|
<value> ::= <name> | <number> | <tuple> | <graph>
|
||||||
<tuple-tail> ::= ")" | <tuple-open-edge>
|
|
||||||
<tuple-open-edge> ::= <value> <tuple-open-edge-tail>
|
|
||||||
<tuple-open-edge-tail> ::= ")"
|
|
||||||
| "," <tuple-tail>
|
|
||||||
| "<" <tuple-open-edge>
|
|
||||||
|
|
||||||
<graph> ::= "{" <graph-tail>
|
<tuple> ::= "(" <tuple-tail>
|
||||||
<graph-tail> ::= "}" | <name> "=" <graph-open-edge>
|
<tuple-tail> ::= ")" | <value> <tuple-post-value>
|
||||||
<graph-open-edge> ::= <value> <graph-open-edge-value-tail>
|
<tuple-post-value> ::= ")"
|
||||||
| <tuple> <graph-open-edge-tail>
|
| "," <tuple-tail>
|
||||||
<graph-open-edge-tail> ::= "}" | ";" <graph-tail>
|
| "<" <value> <tuple-post-value>
|
||||||
<graph-open-edge-value-tail> ::= <graph-open-edge-tail> | "<" <graph-open-edge>
|
|
||||||
|
|
||||||
<value> ::= <name> | <number> | <graph>
|
<graph> ::= "{" <graph-tail>
|
||||||
<gg> ::= <eof> | <value> <gg>
|
<graph-tail> ::= "}" | <name> "=" <graph-open-edge>
|
||||||
|
<graph-open-edge> ::= <value> <graph-open-edge-tail>
|
||||||
|
<graph-open-edge-tail> ::= "}"
|
||||||
|
| ";" <graph-tail>
|
||||||
|
| "<" <graph-open-edge>
|
||||||
|
|
||||||
|
<top-level-value> ::= <name> | <number> | <graph>
|
||||||
|
<gg> ::= <eof> | <top-level-value> <gg>
|
||||||
|
@ -25,6 +25,10 @@ func (e LocatedError) Error() string {
|
|||||||
return fmt.Sprintf("%d:%d: %v", e.Row, e.Col, e.Err)
|
return fmt.Sprintf("%d:%d: %v", e.Row, e.Col, e.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type locatable interface {
|
||||||
|
locate() Location
|
||||||
|
}
|
||||||
|
|
||||||
type locatableRune struct {
|
type locatableRune struct {
|
||||||
Location
|
Location
|
||||||
r rune
|
r rune
|
||||||
@ -34,3 +38,12 @@ type locatableString struct {
|
|||||||
Location
|
Location
|
||||||
str string
|
str string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type locatableSlice[T locatable] []T
|
||||||
|
|
||||||
|
func (s locatableSlice[T]) locate() Location {
|
||||||
|
if len(s) == 0 {
|
||||||
|
panic("can't locate empty locatableSlice")
|
||||||
|
}
|
||||||
|
return s[0].locate()
|
||||||
|
}
|
||||||
|
213
gg/v2/term.go
213
gg/v2/term.go
@ -9,7 +9,6 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/mediocregopher/ginger/graph"
|
"github.com/mediocregopher/ginger/graph"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -28,7 +27,7 @@ func (str stringerStr) String() string {
|
|||||||
return string(str)
|
return string(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
type term[T any] struct {
|
type term[T locatable] struct {
|
||||||
name fmt.Stringer
|
name fmt.Stringer
|
||||||
decodeFn func(d *Decoder) (T, error)
|
decodeFn func(d *Decoder) (T, error)
|
||||||
}
|
}
|
||||||
@ -37,7 +36,7 @@ func (t term[T]) String() string {
|
|||||||
return t.name.String()
|
return t.name.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstOf[T any](terms ...*term[T]) *term[T] {
|
func firstOf[T locatable](terms ...*term[T]) *term[T] {
|
||||||
if len(terms) < 2 {
|
if len(terms) < 2 {
|
||||||
panic("firstOfTerms requires at least 2 terms")
|
panic("firstOfTerms requires at least 2 terms")
|
||||||
}
|
}
|
||||||
@ -68,11 +67,11 @@ func firstOf[T any](terms ...*term[T]) *term[T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func seq[Ta, Tb, Tc any](
|
func seq[Ta, Tb, Tc locatable](
|
||||||
name fmt.Stringer,
|
name fmt.Stringer,
|
||||||
termA *term[Ta],
|
termA *term[Ta],
|
||||||
termB *term[Tb],
|
termB *term[Tb],
|
||||||
fn func(Ta, Tb) Tc,
|
fn func(Ta, Tb) (Tc, error),
|
||||||
) *term[Tc] {
|
) *term[Tc] {
|
||||||
return &term[Tc]{
|
return &term[Tc]{
|
||||||
name: name,
|
name: name,
|
||||||
@ -91,25 +90,30 @@ func seq[Ta, Tb, Tc any](
|
|||||||
return zero, err
|
return zero, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(va, vb), nil
|
vc, err := fn(va, vb)
|
||||||
|
if err != nil {
|
||||||
|
return zero, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return vc, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchAndSkip[Ta, Tb any](
|
func matchAndSkip[Ta, Tb locatable](
|
||||||
termA *term[Ta], termB *term[Tb],
|
termA *term[Ta], termB *term[Tb],
|
||||||
) *term[Tb] {
|
) *term[Tb] {
|
||||||
return seq(termA, termA, termB, func(_ Ta, b Tb) Tb {
|
return seq(termA, termA, termB, func(_ Ta, b Tb) (Tb, error) {
|
||||||
return b
|
return b, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func oneOrMore[T any](t *term[T]) *term[[]T] {
|
func oneOrMore[T locatable](t *term[T]) *term[locatableSlice[T]] {
|
||||||
return &term[[]T]{
|
return &term[locatableSlice[T]]{
|
||||||
name: stringerFn(func() string {
|
name: stringerFn(func() string {
|
||||||
return fmt.Sprintf("one or more %v", t)
|
return fmt.Sprintf("one or more %v", t)
|
||||||
}),
|
}),
|
||||||
decodeFn: func(d *Decoder) ([]T, error) {
|
decodeFn: func(d *Decoder) (locatableSlice[T], error) {
|
||||||
var vv []T
|
var vv []T
|
||||||
for {
|
for {
|
||||||
v, err := t.decodeFn(d)
|
v, err := t.decodeFn(d)
|
||||||
@ -131,12 +135,12 @@ func oneOrMore[T any](t *term[T]) *term[[]T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func zeroOrMore[T any](t *term[T]) *term[[]T] {
|
func zeroOrMore[T locatable](t *term[T]) *term[locatableSlice[T]] {
|
||||||
return &term[[]T]{
|
return &term[locatableSlice[T]]{
|
||||||
name: stringerFn(func() string {
|
name: stringerFn(func() string {
|
||||||
return fmt.Sprintf("zero or more %v", t)
|
return fmt.Sprintf("zero or more %v", t)
|
||||||
}),
|
}),
|
||||||
decodeFn: func(d *Decoder) ([]T, error) {
|
decodeFn: func(d *Decoder) (locatableSlice[T], error) {
|
||||||
var vv []T
|
var vv []T
|
||||||
for {
|
for {
|
||||||
v, err := t.decodeFn(d)
|
v, err := t.decodeFn(d)
|
||||||
@ -154,7 +158,7 @@ func zeroOrMore[T any](t *term[T]) *term[[]T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapTerm[Ta, Tb any](
|
func mapTerm[Ta locatable, Tb locatable](
|
||||||
name fmt.Stringer, t *term[Ta], fn func(Ta) Tb,
|
name fmt.Stringer, t *term[Ta], fn func(Ta) Tb,
|
||||||
) *term[Tb] {
|
) *term[Tb] {
|
||||||
return &term[Tb]{
|
return &term[Tb]{
|
||||||
@ -200,7 +204,7 @@ func runeTerm(r rune) *term[locatableRune] {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func locatableRunesToString(rr []locatableRune) string {
|
func locatableRunesToString(rr locatableSlice[locatableRune]) string {
|
||||||
str := make([]rune, len(rr))
|
str := make([]rune, len(rr))
|
||||||
for i := range rr {
|
for i := range rr {
|
||||||
str[i] = rr[i].r
|
str[i] = rr[i].r
|
||||||
@ -209,11 +213,11 @@ func locatableRunesToString(rr []locatableRune) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runesToStringTerm(
|
func runesToStringTerm(
|
||||||
t *term[[]locatableRune],
|
t *term[locatableSlice[locatableRune]],
|
||||||
) *term[locatableString] {
|
) *term[locatableString] {
|
||||||
return mapTerm(
|
return mapTerm(
|
||||||
t, t, func(rr []locatableRune) locatableString {
|
t, t, func(rr locatableSlice[locatableRune]) locatableString {
|
||||||
return locatableString{rr[0].locate(), locatableRunesToString(rr)}
|
return locatableString{rr.locate(), locatableRunesToString(rr)}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -230,8 +234,10 @@ var (
|
|||||||
stringerStr("negative-number"),
|
stringerStr("negative-number"),
|
||||||
runeTerm('-'),
|
runeTerm('-'),
|
||||||
positiveNumberTerm,
|
positiveNumberTerm,
|
||||||
func(neg locatableRune, posNum locatableString) locatableString {
|
func(neg locatableRune, posNum locatableString) (locatableString, error) {
|
||||||
return locatableString{neg.locate(), string(neg.r) + posNum.str}
|
return locatableString{
|
||||||
|
neg.locate(), string(neg.r) + posNum.str,
|
||||||
|
}, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -263,125 +269,50 @@ var (
|
|||||||
stringerStr("name"),
|
stringerStr("name"),
|
||||||
letterTerm,
|
letterTerm,
|
||||||
letterTailTerm,
|
letterTailTerm,
|
||||||
func(head locatableRune, tail []locatableRune) Value {
|
func(head locatableRune, tail locatableSlice[locatableRune]) (Value, error) {
|
||||||
name := string(head.r) + locatableRunesToString(tail)
|
name := string(head.r) + locatableRunesToString(tail)
|
||||||
return Value{Name: &name, Location: head.locate()}
|
return Value{Name: &name, Location: head.locate()}, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func openEdgeIntoValue(val Value, oe *OpenEdge) *OpenEdge {
|
|
||||||
switch {
|
|
||||||
case oe == nil:
|
|
||||||
return graph.ValueOut(None, val)
|
|
||||||
case !oe.EdgeValue().Valid:
|
|
||||||
return oe.WithEdgeValue(Some(val))
|
|
||||||
default:
|
|
||||||
return graph.TupleOut(Some(val), oe)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var graphTerm = func() *term[Value] {
|
var graphTerm = func() *term[Value] {
|
||||||
type tupleState struct {
|
|
||||||
ins []*OpenEdge
|
|
||||||
oe *OpenEdge
|
|
||||||
}
|
|
||||||
|
|
||||||
type graphState struct {
|
type graphState struct {
|
||||||
g *Graph
|
Location // location of last place graphState was updated
|
||||||
oe *OpenEdge
|
g *Graph
|
||||||
|
oe *OpenEdge
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
rightParenthesis = runeTerm(')')
|
|
||||||
tupleEndTerm = mapTerm(
|
|
||||||
rightParenthesis,
|
|
||||||
rightParenthesis,
|
|
||||||
func(lr locatableRune) tupleState {
|
|
||||||
// if ')', then map that to an empty state. This acts as a
|
|
||||||
// sentinel value to indicate "end of tuple".
|
|
||||||
return tupleState{}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
rightCurlyBrace = runeTerm('}')
|
|
||||||
graphEndTerm = mapTerm(
|
|
||||||
rightCurlyBrace,
|
|
||||||
rightCurlyBrace,
|
|
||||||
func(lr locatableRune) graphState {
|
|
||||||
// if '}', then map that to an empty state. This acts as a
|
|
||||||
// sentinel value to indicate "end of graph".
|
|
||||||
return graphState{}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// pre-define these, and then fill in the pointers after, in order to
|
// pre-define these, and then fill in the pointers after, in order to
|
||||||
// deal with recursive dependencies between them.
|
// deal with recursive dependencies between them.
|
||||||
valueTerm = new(term[Value])
|
graphTerm = new(term[Value])
|
||||||
|
graphTailTerm = new(term[graphState])
|
||||||
|
graphOpenEdgeTerm = new(term[graphState])
|
||||||
|
graphOpenEdgeTailTerm = new(term[graphState])
|
||||||
|
valueTerm = new(term[Value])
|
||||||
|
|
||||||
tupleTerm = new(term[*OpenEdge])
|
rightCurlyBrace = runeTerm('}')
|
||||||
tupleTailTerm = new(term[tupleState])
|
graphEndTerm = mapTerm(
|
||||||
tupleOpenEdgeTerm = new(term[tupleState])
|
rightCurlyBrace,
|
||||||
tupleOpenEdgeTailTerm = new(term[tupleState])
|
rightCurlyBrace, func(lr locatableRune) graphState {
|
||||||
|
// if '}', then map that to an empty state. This acts as a
|
||||||
graphTerm = new(term[Value])
|
// sentinel value to indicate "end of graph".
|
||||||
graphTailTerm = new(term[graphState])
|
return graphState{Location: lr.locate()}
|
||||||
graphOpenEdgeTerm = new(term[graphState])
|
|
||||||
graphOpenEdgeTailTerm = new(term[graphState])
|
|
||||||
graphOpenEdgeValueTailTerm = new(term[graphState])
|
|
||||||
)
|
|
||||||
|
|
||||||
*tupleTerm = *seq(
|
|
||||||
stringerStr("tuple"),
|
|
||||||
runeTerm('('),
|
|
||||||
tupleTailTerm,
|
|
||||||
func(lr locatableRune, ts tupleState) *OpenEdge {
|
|
||||||
slices.Reverse(ts.ins)
|
|
||||||
return graph.TupleOut(None, ts.ins...)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
*tupleTailTerm = *firstOf(
|
|
||||||
tupleEndTerm,
|
|
||||||
mapTerm(
|
|
||||||
tupleOpenEdgeTerm,
|
|
||||||
tupleOpenEdgeTerm,
|
|
||||||
func(ts tupleState) tupleState {
|
|
||||||
ts.ins = append(ts.ins, ts.oe)
|
|
||||||
ts.oe = nil
|
|
||||||
return ts
|
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
)
|
|
||||||
|
|
||||||
*tupleOpenEdgeTerm = *seq(
|
|
||||||
valueTerm,
|
|
||||||
valueTerm,
|
|
||||||
tupleOpenEdgeTailTerm,
|
|
||||||
func(val Value, ts tupleState) tupleState {
|
|
||||||
ts.oe = openEdgeIntoValue(val, ts.oe)
|
|
||||||
return ts
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
*tupleOpenEdgeTailTerm = *firstOf(
|
|
||||||
tupleEndTerm,
|
|
||||||
matchAndSkip(runeTerm(','), tupleTailTerm),
|
|
||||||
matchAndSkip(runeTerm('<'), tupleOpenEdgeTerm),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
*graphTerm = *seq(
|
*graphTerm = *seq(
|
||||||
stringerStr("graph"),
|
stringerStr("graph"),
|
||||||
runeTerm('{'),
|
runeTerm('{'),
|
||||||
graphTailTerm,
|
graphTailTerm,
|
||||||
func(lr locatableRune, gs graphState) Value {
|
func(lr locatableRune, gs graphState) (Value, error) {
|
||||||
if gs.g == nil {
|
if gs.g == nil {
|
||||||
gs.g = new(Graph)
|
gs.g = new(Graph)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value{Graph: gs.g, Location: lr.locate()}
|
return Value{Graph: gs.g, Location: lr.locate()}, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -390,48 +321,42 @@ var graphTerm = func() *term[Value] {
|
|||||||
seq(
|
seq(
|
||||||
nameTerm,
|
nameTerm,
|
||||||
nameTerm,
|
nameTerm,
|
||||||
matchAndSkip(runeTerm('='), graphOpenEdgeTerm),
|
matchAndSkip(runeTerm('='), graphOpenEdgeTailTerm),
|
||||||
func(name Value, gs graphState) graphState {
|
func(name Value, gs graphState) (graphState, error) {
|
||||||
if gs.g == nil {
|
if gs.g == nil {
|
||||||
gs.g = new(Graph)
|
gs.g = new(Graph)
|
||||||
}
|
}
|
||||||
|
|
||||||
gs.g = gs.g.AddValueIn(name, gs.oe)
|
gs.g = gs.g.AddValueIn(name, gs.oe)
|
||||||
gs.oe = nil
|
gs.oe = nil
|
||||||
return gs
|
gs.Location = name.locate()
|
||||||
|
return gs, nil
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
*graphOpenEdgeTerm = *firstOf(
|
*graphOpenEdgeTerm = *firstOf(
|
||||||
seq(
|
|
||||||
valueTerm,
|
|
||||||
valueTerm,
|
|
||||||
graphOpenEdgeValueTailTerm,
|
|
||||||
func(val Value, gs graphState) graphState {
|
|
||||||
gs.oe = openEdgeIntoValue(val, gs.oe)
|
|
||||||
return gs
|
|
||||||
},
|
|
||||||
),
|
|
||||||
seq(
|
|
||||||
tupleTerm,
|
|
||||||
tupleTerm,
|
|
||||||
graphOpenEdgeTailTerm,
|
|
||||||
func(oe *OpenEdge, gs graphState) graphState {
|
|
||||||
gs.oe = oe
|
|
||||||
return gs
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
*graphOpenEdgeTailTerm = *firstOf(
|
|
||||||
graphEndTerm,
|
graphEndTerm,
|
||||||
matchAndSkip(runeTerm(';'), graphTailTerm),
|
matchAndSkip(runeTerm(';'), graphTailTerm),
|
||||||
|
matchAndSkip(runeTerm('<'), graphOpenEdgeTailTerm),
|
||||||
)
|
)
|
||||||
|
|
||||||
*graphOpenEdgeValueTailTerm = *firstOf(
|
*graphOpenEdgeTailTerm = *seq(
|
||||||
graphOpenEdgeTailTerm,
|
valueTerm,
|
||||||
matchAndSkip(runeTerm('<'), graphOpenEdgeTerm),
|
valueTerm,
|
||||||
|
graphOpenEdgeTerm,
|
||||||
|
func(val Value, gs graphState) (graphState, error) {
|
||||||
|
if gs.oe == nil {
|
||||||
|
gs.oe = graph.ValueOut(None, val)
|
||||||
|
} else if !gs.oe.EdgeValue().Valid {
|
||||||
|
gs.oe = gs.oe.WithEdgeValue(Some(val))
|
||||||
|
} else {
|
||||||
|
gs.oe = graph.TupleOut(Some(val), gs.oe)
|
||||||
|
}
|
||||||
|
|
||||||
|
gs.Location = val.locate()
|
||||||
|
return gs, nil
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
*valueTerm = *firstOf(nameTerm, numberTerm, graphTerm)
|
*valueTerm = *firstOf(nameTerm, numberTerm, graphTerm)
|
||||||
|
@ -84,7 +84,7 @@ func TestTermDecoding(t *testing.T) {
|
|||||||
{in: `{}`, exp: expGraph(1, 1, new(Graph))},
|
{in: `{}`, exp: expGraph(1, 1, new(Graph))},
|
||||||
{in: `{`, expErr: `1:2: expected '}' or name`},
|
{in: `{`, expErr: `1:2: expected '}' or name`},
|
||||||
{in: `{a}`, expErr: `1:3: expected '='`},
|
{in: `{a}`, expErr: `1:3: expected '='`},
|
||||||
{in: `{a=}`, expErr: `1:4: expected name or number or graph or tuple`},
|
{in: `{a=}`, expErr: `1:4: expected name or number or graph`},
|
||||||
{
|
{
|
||||||
in: `{foo=a}`,
|
in: `{foo=a}`,
|
||||||
exp: expGraph(
|
exp: expGraph(
|
||||||
@ -217,89 +217,4 @@ func TestTermDecoding(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
runTests(t, "tuple", graphTerm, []test{
|
|
||||||
{
|
|
||||||
in: `{foo=(a)}`,
|
|
||||||
exp: expGraph(
|
|
||||||
1, 1, new(Graph).
|
|
||||||
AddValueIn(
|
|
||||||
expName(2, 1, "foo"),
|
|
||||||
graph.ValueOut(None, expName(6, 1, "a")),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: `{foo=(a<b)}`,
|
|
||||||
exp: expGraph(
|
|
||||||
1, 1, new(Graph).
|
|
||||||
AddValueIn(
|
|
||||||
expName(2, 1, "foo"),
|
|
||||||
graph.ValueOut(
|
|
||||||
Some(expName(6, 1, "a")),
|
|
||||||
expName(8, 1, "b"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: `{foo=a<(b)}`,
|
|
||||||
exp: expGraph(
|
|
||||||
1, 1, new(Graph).
|
|
||||||
AddValueIn(
|
|
||||||
expName(2, 1, "foo"),
|
|
||||||
graph.ValueOut(
|
|
||||||
Some(expName(6, 1, "a")),
|
|
||||||
expName(8, 1, "b"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: `{foo=a<(b,c)}`,
|
|
||||||
exp: expGraph(
|
|
||||||
1, 1, new(Graph).
|
|
||||||
AddValueIn(
|
|
||||||
expName(2, 1, "foo"),
|
|
||||||
graph.TupleOut(
|
|
||||||
Some(expName(6, 1, "a")),
|
|
||||||
graph.ValueOut(None, expName(8, 1, "b")),
|
|
||||||
graph.ValueOut(None, expName(10, 1, "c")),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: `{foo=a<(b<c)}`,
|
|
||||||
exp: expGraph(
|
|
||||||
1, 1, new(Graph).
|
|
||||||
AddValueIn(
|
|
||||||
expName(2, 1, "foo"),
|
|
||||||
graph.TupleOut(
|
|
||||||
Some(expName(6, 1, "a")),
|
|
||||||
graph.TupleOut(
|
|
||||||
Some(expName(6, 1, "b")),
|
|
||||||
graph.ValueOut(None, expName(8, 1, "c")),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
//{
|
|
||||||
// in: `{foo=a<(b<(c))}`,
|
|
||||||
// exp: expGraph(
|
|
||||||
// 1, 1, new(Graph).
|
|
||||||
// AddValueIn(
|
|
||||||
// expName(2, 1, "foo"),
|
|
||||||
// graph.TupleOut(
|
|
||||||
// Some(expName(6, 1, "a")),
|
|
||||||
// graph.TupleOut(
|
|
||||||
// Some(expName(6, 1, "b")),
|
|
||||||
// graph.ValueOut(None, expName(8, 1, "c")),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
//},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -7,6 +7,5 @@ require github.com/stretchr/testify v1.7.0
|
|||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||||
)
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -5,8 +5,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
@ -126,7 +126,7 @@ func TupleOut[E, V Value](edgeVal E, ins ...*OpenEdge[E, V]) *OpenEdge[E, V] {
|
|||||||
if len(ins) == 1 {
|
if len(ins) == 1 {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
zero E
|
zero V
|
||||||
in = ins[0]
|
in = ins[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -353,6 +353,7 @@ type reducedEdge[Ea, Va Value, Vb any] struct {
|
|||||||
// If a value or edge is connected to multiple times within the root OpenEdge it
|
// If a value or edge is connected to multiple times within the root OpenEdge it
|
||||||
// will only be mapped/reduced a single time, and the result of that single
|
// will only be mapped/reduced a single time, and the result of that single
|
||||||
// map/reduction will be passed to each dependant operation.
|
// map/reduction will be passed to each dependant operation.
|
||||||
|
//
|
||||||
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),
|
||||||
|
Loading…
Reference in New Issue
Block a user