Implementation should be good like this. TODO: Tests
This commit is contained in:
parent
be2f5d3d1d
commit
dc24f39ca3
4 changed files with 102 additions and 5 deletions
9
go.mod
9
go.mod
|
@ -2,4 +2,11 @@ module git.mstar.dev/mstar/treeificator
|
||||||
|
|
||||||
go 1.24.2
|
go 1.24.2
|
||||||
|
|
||||||
require git.mstar.dev/mstar/goutils v1.12.3 // indirect
|
require git.mstar.dev/mstar/goutils v1.12.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
|
github.com/rs/zerolog v1.33.0 // indirect
|
||||||
|
golang.org/x/sys v0.12.0 // indirect
|
||||||
|
)
|
||||||
|
|
15
go.sum
15
go.sum
|
@ -1,2 +1,17 @@
|
||||||
git.mstar.dev/mstar/goutils v1.12.3 h1:Wx7i8/a99Cp+Y/XcXgqQr0r9cSsJu7QkWBlKyprTH44=
|
git.mstar.dev/mstar/goutils v1.12.3 h1:Wx7i8/a99Cp+Y/XcXgqQr0r9cSsJu7QkWBlKyprTH44=
|
||||||
git.mstar.dev/mstar/goutils v1.12.3/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
|
git.mstar.dev/mstar/goutils v1.12.3/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
|
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||||
|
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
|
@ -8,6 +8,8 @@ type Informer interface {
|
||||||
GetSuffix() string
|
GetSuffix() string
|
||||||
// Get the name of the node type.
|
// Get the name of the node type.
|
||||||
// Each name (in lowercase) may only exist once. The parser will enforce this.
|
// Each name (in lowercase) may only exist once. The parser will enforce this.
|
||||||
|
// No guaranteed order for which informer will be used if multiple with the same name are in use.
|
||||||
|
// The name "default" is occupied by the built-in default informer for just strings
|
||||||
GetName() string
|
GetName() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
81
parser.go
81
parser.go
|
@ -1,13 +1,86 @@
|
||||||
package treeificator
|
package treeificator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.mstar.dev/mstar/goutils/other"
|
||||||
|
)
|
||||||
|
|
||||||
func Marshal(raw string, informers ...Informer) Node {
|
func Marshal(raw string, informers ...Informer) Node {
|
||||||
prefixToInformer := map[string]Informer{}
|
prefixToInformer := map[string]Informer{}
|
||||||
|
maxPrefixLen := 0
|
||||||
|
for _, informer := range informers {
|
||||||
|
prefixToInformer[informer.GetPrefix()] = informer
|
||||||
|
if l := len(informer.GetPrefix()); l > maxPrefixLen {
|
||||||
|
maxPrefixLen = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defaultInformer := &DefaultInformer{}
|
||||||
|
delete(prefixToInformer, defaultInformer.GetPrefix())
|
||||||
|
elems, consumed := marshal(raw, prefixToInformer, nil)
|
||||||
|
_ = consumed
|
||||||
return Node{
|
return Node{
|
||||||
NodeType: &DefaultInformer{},
|
NodeType: defaultInformer,
|
||||||
Elements: marshal(raw, prefixToInformer),
|
Elements: elems,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshal(raw string, informers map[string]Informer) []NodeElement {
|
// Return the elements in the given string, using the given informers, in order of appearance.
|
||||||
return []NodeElement{NodeElement{Text: &raw}}
|
func marshal(
|
||||||
|
raw string,
|
||||||
|
informers map[string]Informer,
|
||||||
|
activeInformer Informer,
|
||||||
|
) ([]NodeElement, uint64) {
|
||||||
|
elements := []NodeElement{}
|
||||||
|
buffer := make([]rune, len(raw))
|
||||||
|
var consumed uint64 = 0
|
||||||
|
var insideDiff uint64 = 0 // Nr of runes consumed by recursive calls
|
||||||
|
for i, char := range []rune(raw) {
|
||||||
|
// Skip runes that have been consumed by recursive calls
|
||||||
|
if uint64(i)+insideDiff < consumed {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buffer = append(buffer, char)
|
||||||
|
consumed = uint64(i) + insideDiff
|
||||||
|
for k, v := range informers {
|
||||||
|
if !strings.HasSuffix(string(buffer), k) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(buffer) > 0 {
|
||||||
|
// Cut informer prefix from buffer, append buffer as text element
|
||||||
|
elements = append(
|
||||||
|
elements,
|
||||||
|
NodeElement{Text: other.IntoPointer(strings.TrimSuffix(string(buffer), k))},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
buffer = make([]rune, uint64(len(raw))-consumed)
|
||||||
|
subElems, subConsumed := marshal(string([]rune(raw)[consumed:]), informers, v)
|
||||||
|
elements = append(elements, NodeElement{
|
||||||
|
Node: &Node{
|
||||||
|
NodeType: v,
|
||||||
|
Elements: subElems,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
insideDiff += subConsumed
|
||||||
|
consumed += subConsumed
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if activeInformer != nil && strings.HasSuffix(string(buffer), activeInformer.GetSuffix()) {
|
||||||
|
if len(buffer) > 0 {
|
||||||
|
elements = append(
|
||||||
|
elements,
|
||||||
|
NodeElement{
|
||||||
|
Text: other.IntoPointer(
|
||||||
|
strings.TrimSuffix(string(buffer), activeInformer.GetSuffix()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return elements, uint64(consumed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(buffer) > 0 {
|
||||||
|
elements = append(elements, NodeElement{Text: other.IntoPointer(string(buffer))})
|
||||||
|
}
|
||||||
|
return elements, uint64(consumed)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue