ginger/gg/decoder.go

309 lines
6.7 KiB
Go
Raw Normal View History

package gg
import (
"fmt"
"io"
"log"
"strconv"
"unicode"
2023-10-28 07:53:37 +00:00
. "code.betamike.com/mediocregopher/ginger/gg/grammar"
"code.betamike.com/mediocregopher/ginger/graph"
"golang.org/x/exp/slices"
)
func s(str string) fmt.Stringer {
return Stringer{S: str}
}
var (
notNewline = RuneFunc(
s("not-newline"), func(r rune) bool { return r != '\n' },
)
comment = Prefixed(
Prefixed(Rune('*'), ZeroOrMore(notNewline)), Rune('\n'),
)
whitespace = ZeroOrMore(FirstOf(
Discard(RuneFunc(s("whitespace"), unicode.IsSpace)),
Discard(comment),
))
)
func trimmed[T any](sym Symbol[T]) Symbol[T] {
sym = PrefixDiscarded(whitespace, sym)
sym = Suffixed(sym, whitespace)
return sym
}
func trimmedRune(r rune) Symbol[Located[rune]] {
return trimmed(Rune(r))
}
var (
digit = RuneFunc(
s("digit"), func(r rune) bool { return '0' <= r && r <= '9' },
)
positiveNumber = StringFromRunes(OneOrMore(digit))
negativeNumber = Reduction(
s("negative-number"),
Rune('-'),
positiveNumber,
func(neg Located[rune], posNum Located[string]) Located[string] {
2023-10-27 16:57:44 +00:00
return Locate(neg.Location, string(neg.Value)+posNum.Value)
},
)
number = Mapping(
s("number"),
FirstOf(negativeNumber, positiveNumber),
func(str Located[string]) Located[Value] {
i, err := strconv.ParseInt(str.Value, 10, 64)
if err != nil {
panic(fmt.Errorf("parsing %q as int: %w", str, err))
}
2023-10-27 16:57:44 +00:00
return Locate(str.Location, Number(i))
},
)
)
var (
letter = RuneFunc(
s("letter"),
func(r rune) bool {
return unicode.In(r, unicode.Letter, unicode.Mark)
},
)
nameTail = ZeroOrMore(FirstOf(letter, digit))
name = Reduction(
s("name"),
letter,
nameTail,
func(head Located[rune], tail []Located[rune]) Located[Value] {
name := make([]rune, 0, len(tail)+1)
name = append(name, head.Value)
for _, r := range tail {
name = append(name, r.Value)
}
2023-10-27 16:57:44 +00:00
return Locate(head.Location, Name(string(name)))
},
)
)
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 graphSym, value = func() (
Symbol[Located[Value]], Symbol[Located[Value]],
) {
type tupleState struct {
ins []*OpenEdge
oe *OpenEdge
}
type graphState struct {
g *Graph
oe *OpenEdge
}
var (
rightParen = trimmedRune(')')
tupleEnd = Mapping(
rightParen,
rightParen,
func(Located[rune]) tupleState {
// if ')', then map that to an empty state. This acts as a
// sentinel value to indicate "end of tuple".
return tupleState{}
},
)
rightCurlyBrace = trimmedRune('}')
graphEnd = Mapping(
rightCurlyBrace,
rightCurlyBrace,
func(Located[rune]) graphState {
// if '}', then map that to an empty state. This acts as a
// sentinel value to indicate "end of graph".
return graphState{}
},
)
)
var (
// pre-define these, and then fill in the pointers after, in order to
// deal with recursive dependencies between them.
value = new(SymbolPtr[Located[Value]])
tuple = new(SymbolPtr[*OpenEdge])
tupleTail = new(SymbolPtr[tupleState])
tupleOpenEdge = new(SymbolPtr[tupleState])
tupleOpenEdgeTail = new(SymbolPtr[tupleState])
tupleOpenEdgeValueTail = new(SymbolPtr[tupleState])
graphSym = new(SymbolPtr[Located[Value]])
graphTail = new(SymbolPtr[graphState])
graphOpenEdge = new(SymbolPtr[graphState])
graphOpenEdgeTail = new(SymbolPtr[graphState])
graphOpenEdgeValueTail = new(SymbolPtr[graphState])
)
tuple.Symbol = Reduction[Located[rune], tupleState, *OpenEdge](
s("tuple"),
trimmedRune('('),
tupleTail,
func(_ Located[rune], ts tupleState) *OpenEdge {
slices.Reverse(ts.ins)
return graph.TupleOut(None, ts.ins...)
},
)
tupleTail.Symbol = FirstOf(
tupleEnd,
Mapping[tupleState, tupleState](
tupleOpenEdge,
tupleOpenEdge,
func(ts tupleState) tupleState {
ts.ins = append(ts.ins, ts.oe)
ts.oe = nil
return ts
},
),
)
tupleOpenEdge.Symbol = FirstOf(
Reduction[Located[Value], tupleState, tupleState](
value,
value,
tupleOpenEdgeValueTail,
func(val Located[Value], ts tupleState) tupleState {
ts.oe = openEdgeIntoValue(val.Value, ts.oe)
return ts
},
),
Reduction[*OpenEdge, tupleState, tupleState](
tuple,
tuple,
tupleOpenEdgeTail,
func(oe *OpenEdge, ts tupleState) tupleState {
ts.oe = oe
return ts
},
),
)
tupleOpenEdgeTail.Symbol = FirstOf(
tupleEnd,
Prefixed[Located[rune], tupleState](trimmedRune(','), tupleTail),
)
tupleOpenEdgeValueTail.Symbol = FirstOf[tupleState](
tupleOpenEdgeTail,
Prefixed[Located[rune], tupleState](trimmedRune('<'), tupleOpenEdge),
)
graphSym.Symbol = Reduction[Located[rune], graphState, Located[Value]](
s("graph"),
trimmedRune('{'),
graphTail,
func(r Located[rune], gs graphState) Located[Value] {
if gs.g == nil {
gs.g = new(Graph)
}
2023-10-27 16:57:44 +00:00
return Locate(r.Location, Value{Graph: gs.g})
},
)
graphTail.Symbol = FirstOf(
graphEnd,
Reduction(
name,
name,
Prefixed[Located[rune], graphState](
trimmedRune('='), graphOpenEdge,
),
func(name Located[Value], gs graphState) graphState {
if gs.g == nil {
gs.g = new(Graph)
}
gs.g = gs.g.AddValueIn(name.Value, gs.oe)
gs.oe = nil
return gs
},
),
)
log.Printf("populated graphTail with %v", graphTail)
graphOpenEdge.Symbol = FirstOf(
Reduction[Located[Value], graphState, graphState](
value,
value,
graphOpenEdgeValueTail,
func(val Located[Value], gs graphState) graphState {
gs.oe = openEdgeIntoValue(val.Value, gs.oe)
return gs
},
),
Reduction[*OpenEdge, graphState, graphState](
tuple,
tuple,
graphOpenEdgeTail,
func(oe *OpenEdge, gs graphState) graphState {
gs.oe = oe
return gs
},
),
)
graphOpenEdgeTail.Symbol = FirstOf(
graphEnd,
Prefixed[Located[rune], graphState](trimmedRune(';'), graphTail),
)
log.Printf("populated graphOpenEdgeTail with %v", graphOpenEdgeTail)
graphOpenEdgeValueTail.Symbol = FirstOf[graphState](
graphOpenEdgeTail,
Prefixed[Located[rune], graphState](trimmedRune('<'), graphOpenEdge),
)
value.Symbol = trimmed(FirstOf[Located[Value]](name, number, graphSym))
return graphSym, value
}()
// Decoder reads Values off of an io.Reader, or return io.EOF.
type Decoder interface {
Next() (Located[Value], error)
}
type decoder struct {
r Reader
}
// NewDecoder returns a Decoder which reads off the given io.Reader. The
// io.Reader should not be read from after this call.
func NewDecoder(r io.Reader) Decoder {
return &decoder{r: NewReader(r)}
2021-12-30 22:29:38 +00:00
}
func (d *decoder) Next() (Located[Value], error) {
return value.Decode(d.r)
2021-12-30 22:29:38 +00:00
}