package d2ast
import (
"bytes"
"encoding"
"errors"
"fmt"
"math/big"
"path"
"strconv"
"strings"
"unicode"
"unicode/utf16"
"unicode/utf8"
"oss.terrastruct.com/util-go/xdefer"
)
type Node interface {
node()
Type () string
GetRange () Range
Children () []Node
}
var _ Node = &Comment {}
var _ Node = &BlockComment {}
var _ Node = &Null {}
var _ Node = &Boolean {}
var _ Node = &Number {}
var _ Node = &UnquotedString {}
var _ Node = &DoubleQuotedString {}
var _ Node = &SingleQuotedString {}
var _ Node = &BlockString {}
var _ Node = &Substitution {}
var _ Node = &Import {}
var _ Node = &Array {}
var _ Node = &Map {}
var _ Node = &Key {}
var _ Node = &KeyPath {}
var _ Node = &Edge {}
var _ Node = &EdgeIndex {}
type Range struct {
Path string
Start Position
End Position
}
var _ fmt .Stringer = Range {}
var _ encoding .TextMarshaler = Range {}
var _ encoding .TextUnmarshaler = &Range {}
func MakeRange (s string ) Range {
var r Range
_ = r .UnmarshalText ([]byte (s ))
return r
}
func (r Range ) String () string {
var s strings .Builder
if r .Path != "" {
s .WriteString (r .Path )
s .WriteByte (':' )
}
s .WriteString (r .Start .String ())
return s .String ()
}
func (r Range ) OneLine () bool {
return r .Start .Line == r .End .Line
}
func (r Range ) MarshalText () ([]byte , error ) {
start , _ := r .Start .MarshalText ()
end , _ := r .End .MarshalText ()
return []byte (fmt .Sprintf ("%s,%s-%s" , r .Path , start , end )), nil
}
func (r *Range ) UnmarshalText (b []byte ) (err error ) {
defer xdefer .Errorf (&err , "failed to unmarshal Range from %q" , b )
i := bytes .LastIndexByte (b , '-' )
if i == -1 {
return errors .New ("missing End field" )
}
end := b [i +1 :]
b = b [:i ]
i = bytes .LastIndexByte (b , ',' )
if i == -1 {
return errors .New ("missing Start field" )
}
start := b [i +1 :]
b = b [:i ]
r .Path = string (b )
err = r .Start .UnmarshalText (start )
if err != nil {
return err
}
return r .End .UnmarshalText (end )
}
func (r Range ) Before (r2 Range ) bool {
return r .Start .Before (r2 .Start )
}
type Position struct {
Line int
Column int
Byte int
}
var _ fmt .Stringer = Position {}
var _ encoding .TextMarshaler = Position {}
var _ encoding .TextUnmarshaler = &Position {}
func (p Position ) String () string {
return fmt .Sprintf ("%d:%d" , p .Line +1 , p .Column +1 )
}
func (p Position ) Debug () string {
return fmt .Sprintf ("%d:%d:%d" , p .Line , p .Column , p .Byte )
}
func (p Position ) MarshalText () ([]byte , error ) {
return []byte (fmt .Sprintf ("%d:%d:%d" , p .Line , p .Column , p .Byte )), nil
}
func (p *Position ) UnmarshalText (b []byte ) (err error ) {
defer xdefer .Errorf (&err , "failed to unmarshal Position from %q" , b )
fields := bytes .Split (b , []byte {':' })
if len (fields ) != 3 {
return errors .New ("expected three fields" )
}
p .Line , err = strconv .Atoi (string (fields [0 ]))
if err != nil {
return err
}
p .Column , err = strconv .Atoi (string (fields [1 ]))
if err != nil {
return err
}
p .Byte , err = strconv .Atoi (string (fields [2 ]))
return err
}
func (p *Position ) From (src *Position ) {
*p = *src
}
func (p Position ) Advance (r rune , byUTF16 bool ) Position {
size := utf8 .RuneLen (r )
if byUTF16 {
size = 1
r1 , r2 := utf16 .EncodeRune (r )
if r1 != '\uFFFD' && r2 != '\uFFFD' {
size = 2
}
}
if r == '\n' {
p .Line ++
p .Column = 0
} else {
p .Column += size
}
p .Byte += size
return p
}
func (p Position ) Subtract (r rune , byUTF16 bool ) Position {
size := utf8 .RuneLen (r )
if byUTF16 {
size = 1
r1 , r2 := utf16 .EncodeRune (r )
if r1 != '\uFFFD' && r2 != '\uFFFD' {
size = 2
}
}
if r == '\n' {
panic ("d2ast: cannot subtract newline from Position" )
} else {
p .Column -= size
}
p .Byte -= size
return p
}
func (p Position ) AdvanceString (s string , byUTF16 bool ) Position {
for _ , r := range s {
p = p .Advance (r , byUTF16 )
}
return p
}
func (p Position ) SubtractString (s string , byUTF16 bool ) Position {
for _ , r := range s {
p = p .Subtract (r , byUTF16 )
}
return p
}
func (p Position ) Before (p2 Position ) bool {
if p .Byte != p2 .Byte && p .Byte != -1 && p2 .Byte != -1 {
return p .Byte < p2 .Byte
}
if p .Line != p2 .Line {
return p .Line < p2 .Line
}
return p .Column < p2 .Column
}
type MapNode interface {
Node
mapNode()
}
var _ MapNode = &Comment {}
var _ MapNode = &BlockComment {}
var _ MapNode = &Key {}
var _ MapNode = &Substitution {}
var _ MapNode = &Import {}
type ArrayNode interface {
Node
arrayNode()
}
var _ ArrayNode = &Comment {}
var _ ArrayNode = &BlockComment {}
var _ ArrayNode = &Substitution {}
var _ ArrayNode = &Import {}
type Value interface {
ArrayNode
value()
}
var _ Value = &Array {}
var _ Value = &Map {}
type Scalar interface {
Value
scalar()
ScalarString () string
}
var _ Scalar = &Null {}
var _ Scalar = &Boolean {}
var _ Scalar = &Number {}
type String interface {
Scalar
SetString (string )
Copy () String
_string()
IsUnquoted () bool
}
var _ String = &UnquotedString {}
var _ String = &SingleQuotedString {}
var _ String = &DoubleQuotedString {}
var _ String = &BlockString {}
func (c *Comment ) node () {}
func (c *BlockComment ) node () {}
func (n *Null ) node () {}
func (b *Boolean ) node () {}
func (n *Number ) node () {}
func (s *UnquotedString ) node () {}
func (s *DoubleQuotedString ) node () {}
func (s *SingleQuotedString ) node () {}
func (s *BlockString ) node () {}
func (s *Substitution ) node () {}
func (i *Import ) node () {}
func (a *Array ) node () {}
func (m *Map ) node () {}
func (k *Key ) node () {}
func (k *KeyPath ) node () {}
func (e *Edge ) node () {}
func (i *EdgeIndex ) node () {}
func (c *Comment ) Type () string { return "comment" }
func (c *BlockComment ) Type () string { return "block comment" }
func (n *Null ) Type () string { return "null" }
func (b *Boolean ) Type () string { return "boolean" }
func (n *Number ) Type () string { return "number" }
func (s *UnquotedString ) Type () string { return "unquoted string" }
func (s *DoubleQuotedString ) Type () string { return "double quoted string" }
func (s *SingleQuotedString ) Type () string { return "single quoted string" }
func (s *BlockString ) Type () string { return s .Tag + " block string" }
func (s *Substitution ) Type () string { return "substitution" }
func (i *Import ) Type () string { return "import" }
func (a *Array ) Type () string { return "array" }
func (m *Map ) Type () string { return "map" }
func (k *Key ) Type () string { return "map key" }
func (k *KeyPath ) Type () string { return "key path" }
func (e *Edge ) Type () string { return "edge" }
func (i *EdgeIndex ) Type () string { return "edge index" }
func (c *Comment ) GetRange () Range { return c .Range }
func (c *BlockComment ) GetRange () Range { return c .Range }
func (n *Null ) GetRange () Range { return n .Range }
func (b *Boolean ) GetRange () Range { return b .Range }
func (n *Number ) GetRange () Range { return n .Range }
func (s *UnquotedString ) GetRange () Range { return s .Range }
func (s *DoubleQuotedString ) GetRange () Range { return s .Range }
func (s *SingleQuotedString ) GetRange () Range { return s .Range }
func (s *BlockString ) GetRange () Range { return s .Range }
func (s *Substitution ) GetRange () Range { return s .Range }
func (i *Import ) GetRange () Range { return i .Range }
func (a *Array ) GetRange () Range { return a .Range }
func (m *Map ) GetRange () Range { return m .Range }
func (k *Key ) GetRange () Range { return k .Range }
func (k *KeyPath ) GetRange () Range { return k .Range }
func (e *Edge ) GetRange () Range { return e .Range }
func (i *EdgeIndex ) GetRange () Range { return i .Range }
func (c *Comment ) mapNode () {}
func (c *BlockComment ) mapNode () {}
func (k *Key ) mapNode () {}
func (s *Substitution ) mapNode () {}
func (i *Import ) mapNode () {}
func (c *Comment ) arrayNode () {}
func (c *BlockComment ) arrayNode () {}
func (n *Null ) arrayNode () {}
func (b *Boolean ) arrayNode () {}
func (n *Number ) arrayNode () {}
func (s *UnquotedString ) arrayNode () {}
func (s *DoubleQuotedString ) arrayNode () {}
func (s *SingleQuotedString ) arrayNode () {}
func (s *BlockString ) arrayNode () {}
func (s *Substitution ) arrayNode () {}
func (i *Import ) arrayNode () {}
func (a *Array ) arrayNode () {}
func (m *Map ) arrayNode () {}
func (n *Null ) value () {}
func (b *Boolean ) value () {}
func (n *Number ) value () {}
func (s *UnquotedString ) value () {}
func (s *DoubleQuotedString ) value () {}
func (s *SingleQuotedString ) value () {}
func (s *BlockString ) value () {}
func (a *Array ) value () {}
func (m *Map ) value () {}
func (i *Import ) value () {}
func (n *Null ) scalar () {}
func (b *Boolean ) scalar () {}
func (n *Number ) scalar () {}
func (s *UnquotedString ) scalar () {}
func (s *DoubleQuotedString ) scalar () {}
func (s *SingleQuotedString ) scalar () {}
func (s *BlockString ) scalar () {}
func (c *Comment ) Children () []Node { return nil }
func (c *BlockComment ) Children () []Node { return nil }
func (n *Null ) Children () []Node { return nil }
func (b *Boolean ) Children () []Node { return nil }
func (n *Number ) Children () []Node { return nil }
func (s *SingleQuotedString ) Children () []Node { return nil }
func (s *BlockString ) Children () []Node { return nil }
func (ei *EdgeIndex ) Children () []Node { return nil }
func (s *UnquotedString ) Children () []Node {
var children []Node
for _ , box := range s .Value {
if box .Substitution != nil {
children = append (children , box .Substitution )
}
}
return children
}
func (s *DoubleQuotedString ) Children () []Node {
var children []Node
for _ , box := range s .Value {
if box .Substitution != nil {
children = append (children , box .Substitution )
}
}
return children
}
func (s *Substitution ) Children () []Node {
var children []Node
for _ , sb := range s .Path {
if sb != nil {
if child := sb .Unbox (); child != nil {
children = append (children , child )
}
}
}
return children
}
func (i *Import ) Children () []Node {
var children []Node
for _ , sb := range i .Path {
if sb != nil {
if child := sb .Unbox (); child != nil {
children = append (children , child )
}
}
}
return children
}
func (a *Array ) Children () []Node {
var children []Node
for _ , box := range a .Nodes {
if child := box .Unbox (); child != nil {
children = append (children , child )
}
}
return children
}
func (m *Map ) Children () []Node {
var children []Node
for _ , box := range m .Nodes {
if child := box .Unbox (); child != nil {
children = append (children , child )
}
}
return children
}
func (k *Key ) Children () []Node {
var children []Node
if k .Key != nil {
children = append (children , k .Key )
}
for _ , edge := range k .Edges {
if edge != nil {
children = append (children , edge )
}
}
if k .EdgeIndex != nil {
children = append (children , k .EdgeIndex )
}
if k .EdgeKey != nil {
children = append (children , k .EdgeKey )
}
if scalar := k .Primary .Unbox (); scalar != nil {
children = append (children , scalar )
}
if value := k .Value .Unbox (); value != nil {
children = append (children , value )
}
return children
}
func (kp *KeyPath ) Children () []Node {
var children []Node
for _ , sb := range kp .Path {
if sb != nil {
if child := sb .Unbox (); child != nil {
children = append (children , child )
}
}
}
return children
}
func (e *Edge ) Children () []Node {
var children []Node
if e .Src != nil {
children = append (children , e .Src )
}
if e .Dst != nil {
children = append (children , e .Dst )
}
return children
}
func Walk (node Node , fn func (Node ) bool ) {
if node == nil {
return
}
if !fn (node ) {
return
}
for _ , child := range node .Children () {
Walk (child , fn )
}
}
func (n *Null ) ScalarString () string { return "" }
func (b *Boolean ) ScalarString () string { return strconv .FormatBool (b .Value ) }
func (n *Number ) ScalarString () string { return n .Raw }
func (s *UnquotedString ) ScalarString () string {
if len (s .Value ) == 0 {
return ""
}
if s .Value [0 ].String == nil {
return ""
}
return *s .Value [0 ].String
}
func (s *DoubleQuotedString ) ScalarString () string {
if len (s .Value ) == 0 {
return ""
}
if s .Value [0 ].String == nil {
return ""
}
return *s .Value [0 ].String
}
func (s *SingleQuotedString ) ScalarString () string { return s .Value }
func (s *BlockString ) ScalarString () string { return s .Value }
func (s *UnquotedString ) SetString (s2 string ) { s .Value = []InterpolationBox {{String : &s2 }} }
func (s *DoubleQuotedString ) SetString (s2 string ) { s .Value = []InterpolationBox {{String : &s2 }} }
func (s *SingleQuotedString ) SetString (s2 string ) { s .Raw = "" ; s .Value = s2 }
func (s *BlockString ) SetString (s2 string ) { s .Value = s2 }
func (s *UnquotedString ) Copy () String { tmp := *s ; return &tmp }
func (s *DoubleQuotedString ) Copy () String { tmp := *s ; return &tmp }
func (s *SingleQuotedString ) Copy () String { tmp := *s ; return &tmp }
func (s *BlockString ) Copy () String { tmp := *s ; return &tmp }
func (s *UnquotedString ) _string () {}
func (s *DoubleQuotedString ) _string () {}
func (s *SingleQuotedString ) _string () {}
func (s *BlockString ) _string () {}
func (s *UnquotedString ) IsUnquoted () bool { return true }
func (s *DoubleQuotedString ) IsUnquoted () bool { return false }
func (s *SingleQuotedString ) IsUnquoted () bool { return false }
func (s *BlockString ) IsUnquoted () bool { return false }
type Comment struct {
Range Range `json:"range"`
Value string `json:"value"`
}
type BlockComment struct {
Range Range `json:"range"`
Value string `json:"value"`
}
type Null struct {
Range Range `json:"range"`
}
type Boolean struct {
Range Range `json:"range"`
Value bool `json:"value"`
}
type Number struct {
Range Range `json:"range"`
Raw string `json:"raw"`
Value *big .Rat `json:"value"`
}
type UnquotedString struct {
Range Range `json:"range"`
Value []InterpolationBox `json:"value"`
Pattern []string `json:"pattern,omitempty"`
}
func (s *UnquotedString ) Coalesce () {
var b strings .Builder
for _ , box := range s .Value {
if box .String == nil {
break
}
b .WriteString (*box .String )
}
s .SetString (b .String ())
}
func FlatUnquotedString (s string ) *UnquotedString {
return &UnquotedString {
Value : []InterpolationBox {{String : &s }},
}
}
type DoubleQuotedString struct {
Range Range `json:"range"`
Value []InterpolationBox `json:"value"`
}
func (s *DoubleQuotedString ) Coalesce () {
var b strings .Builder
for _ , box := range s .Value {
if box .String == nil {
break
}
b .WriteString (*box .String )
}
s .SetString (b .String ())
}
func FlatDoubleQuotedString (s string ) *DoubleQuotedString {
return &DoubleQuotedString {
Value : []InterpolationBox {{String : &s }},
}
}
type SingleQuotedString struct {
Range Range `json:"range"`
Raw string `json:"raw"`
Value string `json:"value"`
}
type BlockString struct {
Range Range `json:"range"`
Quote string `json:"quote"`
Tag string `json:"tag"`
Value string `json:"value"`
}
type Array struct {
Range Range `json:"range"`
Nodes []ArrayNodeBox `json:"nodes"`
}
type Map struct {
Range Range `json:"range"`
Nodes []MapNodeBox `json:"nodes"`
}
func (m *Map ) InsertAfter (cursor , n MapNode ) {
afterIndex := len (m .Nodes ) - 1
for i , n := range m .Nodes {
if n .Unbox () == cursor {
afterIndex = i
}
}
a := make ([]MapNodeBox , 0 , len (m .Nodes ))
a = append (a , m .Nodes [:afterIndex +1 ]...)
a = append (a , MakeMapNodeBox (n ))
a = append (a , m .Nodes [afterIndex +1 :]...)
m .Nodes = a
}
func (m *Map ) InsertBefore (cursor , n MapNode ) {
beforeIndex := len (m .Nodes )
for i , n := range m .Nodes {
if n .Unbox () == cursor {
beforeIndex = i
}
}
a := make ([]MapNodeBox , 0 , len (m .Nodes ))
a = append (a , m .Nodes [:beforeIndex ]...)
a = append (a , MakeMapNodeBox (n ))
a = append (a , m .Nodes [beforeIndex :]...)
m .Nodes = a
}
func (m *Map ) IsFileMap () bool {
return m .Range .Start .Line == 0 && m .Range .Start .Column == 0
}
func (m *Map ) HasFilter () bool {
for _ , n := range m .Nodes {
if n .MapKey != nil && (n .MapKey .Ampersand || n .MapKey .NotAmpersand ) {
return true
}
}
return false
}
type Key struct {
Range Range `json:"range"`
Ampersand bool `json:"ampersand,omitempty"`
NotAmpersand bool `json:"not_ampersand,omitempty"`
Key *KeyPath `json:"key,omitempty"`
Edges []*Edge `json:"edges,omitempty"`
EdgeIndex *EdgeIndex `json:"edge_index,omitempty"`
EdgeKey *KeyPath `json:"edge_key,omitempty"`
Primary ScalarBox `json:"primary,omitempty"`
Value ValueBox `json:"value"`
}
func (mk1 *Key ) D2OracleEquals (mk2 *Key ) bool {
if mk1 == nil && mk2 == nil {
return true
}
if (mk1 == nil ) || (mk2 == nil ) {
return false
}
if mk1 .Ampersand != mk2 .Ampersand {
return false
}
if mk1 .NotAmpersand != mk2 .NotAmpersand {
return false
}
if (mk1 .Key == nil ) != (mk2 .Key == nil ) {
return false
}
if (mk1 .EdgeIndex == nil ) != (mk2 .EdgeIndex == nil ) {
return false
}
if (mk1 .EdgeKey == nil ) != (mk2 .EdgeKey == nil ) {
return false
}
if len (mk1 .Edges ) != len (mk2 .Edges ) {
return false
}
if (mk1 .Value .Map == nil ) != (mk2 .Value .Map == nil ) {
if mk1 .Value .Map != nil && len (mk1 .Value .Map .Nodes ) > 0 {
return false
}
if mk2 .Value .Map != nil && len (mk2 .Value .Map .Nodes ) > 0 {
return false
}
} else if (mk1 .Value .Unbox () == nil ) != (mk2 .Value .Unbox () == nil ) {
return false
}
if mk1 .Key != nil {
if len (mk1 .Key .Path ) != len (mk2 .Key .Path ) {
return false
}
for i , id := range mk1 .Key .Path {
if id .Unbox ().ScalarString () != mk2 .Key .Path [i ].Unbox ().ScalarString () {
return false
}
}
}
if mk1 .EdgeKey != nil {
if len (mk1 .EdgeKey .Path ) != len (mk2 .EdgeKey .Path ) {
return false
}
for i , id := range mk1 .EdgeKey .Path {
if id .Unbox ().ScalarString () != mk2 .EdgeKey .Path [i ].Unbox ().ScalarString () {
return false
}
}
}
if mk1 .Value .Map != nil && len (mk1 .Value .Map .Nodes ) > 0 {
if len (mk1 .Value .Map .Nodes ) != len (mk2 .Value .Map .Nodes ) {
return false
}
for i := range mk1 .Value .Map .Nodes {
if !mk1 .Value .Map .Nodes [i ].MapKey .Equals (mk2 .Value .Map .Nodes [i ].MapKey ) {
return false
}
}
}
if mk1 .Value .Unbox () != nil {
if (mk1 .Value .ScalarBox ().Unbox () == nil ) != (mk2 .Value .ScalarBox ().Unbox () == nil ) {
return false
}
if mk1 .Value .ScalarBox ().Unbox () != nil {
if mk1 .Value .ScalarBox ().Unbox ().ScalarString () != mk2 .Value .ScalarBox ().Unbox ().ScalarString () {
return false
}
}
}
return true
}
func (mk1 *Key ) Equals (mk2 *Key ) bool {
if mk1 == nil && mk2 == nil {
return true
}
if (mk1 == nil ) || (mk2 == nil ) {
return false
}
if mk1 .Ampersand != mk2 .Ampersand {
return false
}
if mk1 .NotAmpersand != mk2 .NotAmpersand {
return false
}
if (mk1 .Key == nil ) != (mk2 .Key == nil ) {
return false
}
if (mk1 .EdgeIndex == nil ) != (mk2 .EdgeIndex == nil ) {
return false
}
if mk1 .EdgeIndex != nil {
if !mk1 .EdgeIndex .Equals (mk2 .EdgeIndex ) {
return false
}
}
if (mk1 .EdgeKey == nil ) != (mk2 .EdgeKey == nil ) {
return false
}
if len (mk1 .Edges ) != len (mk2 .Edges ) {
return false
}
for i := range mk1 .Edges {
if !mk1 .Edges [i ].Equals (mk2 .Edges [i ]) {
return false
}
}
if (mk1 .Value .Map == nil ) != (mk2 .Value .Map == nil ) {
if mk1 .Value .Map != nil && len (mk1 .Value .Map .Nodes ) > 0 {
return false
}
if mk2 .Value .Map != nil && len (mk2 .Value .Map .Nodes ) > 0 {
return false
}
} else if (mk1 .Value .Unbox () == nil ) != (mk2 .Value .Unbox () == nil ) {
return false
}
if mk1 .Key != nil {
if len (mk1 .Key .Path ) != len (mk2 .Key .Path ) {
return false
}
for i , id := range mk1 .Key .Path {
if id .Unbox ().ScalarString () != mk2 .Key .Path [i ].Unbox ().ScalarString () {
return false
}
}
}
if mk1 .EdgeKey != nil {
if len (mk1 .EdgeKey .Path ) != len (mk2 .EdgeKey .Path ) {
return false
}
for i , id := range mk1 .EdgeKey .Path {
if id .Unbox ().ScalarString () != mk2 .EdgeKey .Path [i ].Unbox ().ScalarString () {
return false
}
}
}
if mk1 .Value .Map != nil && len (mk1 .Value .Map .Nodes ) > 0 {
if len (mk1 .Value .Map .Nodes ) != len (mk2 .Value .Map .Nodes ) {
return false
}
for i := range mk1 .Value .Map .Nodes {
if !mk1 .Value .Map .Nodes [i ].MapKey .Equals (mk2 .Value .Map .Nodes [i ].MapKey ) {
return false
}
}
}
if mk1 .Value .Unbox () != nil {
if (mk1 .Value .ScalarBox ().Unbox () == nil ) != (mk2 .Value .ScalarBox ().Unbox () == nil ) {
return false
}
if mk1 .Value .ScalarBox ().Unbox () != nil {
if mk1 .Value .ScalarBox ().Unbox ().ScalarString () != mk2 .Value .ScalarBox ().Unbox ().ScalarString () {
return false
}
}
}
if mk1 .Primary .Unbox () != nil {
if (mk1 .Primary .Unbox () == nil ) != (mk2 .Primary .Unbox () == nil ) {
return false
}
if mk1 .Primary .ScalarString () != mk2 .Primary .ScalarString () {
return false
}
}
return true
}
func (mk *Key ) SetScalar (scalar ScalarBox ) {
if mk .Value .Unbox () != nil && mk .Value .ScalarBox ().Unbox () == nil {
mk .Primary = scalar
} else {
mk .Value = MakeValueBox (scalar .Unbox ())
}
}
func (mk *Key ) HasGlob () bool {
if mk .Key .HasGlob () {
return true
}
for _ , e := range mk .Edges {
if e .Src .HasGlob () || e .Dst .HasGlob () {
return true
}
}
if mk .EdgeIndex != nil && mk .EdgeIndex .Glob {
return true
}
if mk .EdgeKey .HasGlob () {
return true
}
return false
}
func (mk *Key ) HasTripleGlob () bool {
if mk .Key .HasTripleGlob () {
return true
}
for _ , e := range mk .Edges {
if e .Src .HasTripleGlob () || e .Dst .HasTripleGlob () {
return true
}
}
if mk .EdgeKey .HasTripleGlob () {
return true
}
return false
}
func (mk *Key ) HasMultiGlob () bool {
if mk .Key .HasMultiGlob () {
return true
}
for _ , e := range mk .Edges {
if e .Src .HasMultiGlob () || e .Dst .HasMultiGlob () {
return true
}
}
if mk .EdgeKey .HasMultiGlob () {
return true
}
return false
}
func (mk *Key ) SupportsGlobFilters () bool {
if mk .Key .HasGlob () && len (mk .Edges ) == 0 {
return true
}
if mk .EdgeIndex != nil && mk .EdgeIndex .Glob && mk .EdgeKey == nil {
return true
}
if mk .EdgeKey .HasGlob () {
return true
}
return false
}
func (mk *Key ) Copy () *Key {
mk2 := *mk
return &mk2
}
type KeyPath struct {
Range Range `json:"range"`
Path []*StringBox `json:"path"`
}
func MakeKeyPath (a []string ) *KeyPath {
kp := &KeyPath {}
for _ , el := range a {
kp .Path = append (kp .Path , MakeValueBox (RawString (el , true )).StringBox ())
}
return kp
}
func MakeKeyPathString (a []String ) *KeyPath {
kp := &KeyPath {}
for _ , el := range a {
kp .Path = append (kp .Path , MakeValueBox (RawString (el .ScalarString (), true )).StringBox ())
}
return kp
}
func (kp *KeyPath ) IDA () (ida []String ) {
for _ , el := range kp .Path {
ida = append (ida , el .Unbox ())
}
return ida
}
func (kp *KeyPath ) StringIDA () (ida []string ) {
for _ , el := range kp .Path {
ida = append (ida , el .Unbox ().ScalarString ())
}
return ida
}
func (kp *KeyPath ) Copy () *KeyPath {
kp2 := *kp
kp2 .Path = nil
kp2 .Path = append (kp2 .Path , kp .Path ...)
return &kp2
}
func (kp *KeyPath ) Last () *StringBox {
return kp .Path [len (kp .Path )-1 ]
}
func IsDoubleGlob (pattern []string ) bool {
return len (pattern ) == 3 && pattern [0 ] == "*" && pattern [1 ] == "" && pattern [2 ] == "*"
}
func IsTripleGlob (pattern []string ) bool {
return len (pattern ) == 5 && pattern [0 ] == "*" && pattern [1 ] == "" && pattern [2 ] == "*" && pattern [3 ] == "" && pattern [4 ] == "*"
}
func (kp *KeyPath ) HasGlob () bool {
if kp == nil {
return false
}
for _ , el := range kp .Path {
if el .UnquotedString != nil && len (el .UnquotedString .Pattern ) > 0 {
return true
}
}
return false
}
func (kp *KeyPath ) FirstGlob () int {
if kp == nil {
return -1
}
for i , el := range kp .Path {
if el .UnquotedString != nil && len (el .UnquotedString .Pattern ) > 0 {
return i
}
}
return -1
}
func (kp *KeyPath ) HasTripleGlob () bool {
if kp == nil {
return false
}
for _ , el := range kp .Path {
if el .UnquotedString != nil && IsTripleGlob (el .UnquotedString .Pattern ) {
return true
}
}
return false
}
func (kp *KeyPath ) HasMultiGlob () bool {
if kp == nil {
return false
}
for _ , el := range kp .Path {
if el .UnquotedString != nil && (IsDoubleGlob (el .UnquotedString .Pattern ) || IsTripleGlob (el .UnquotedString .Pattern )) {
return true
}
}
return false
}
func (kp1 *KeyPath ) Equals (kp2 *KeyPath ) bool {
if len (kp1 .Path ) != len (kp2 .Path ) {
return false
}
for i , id := range kp1 .Path {
if id .Unbox ().ScalarString () != kp2 .Path [i ].Unbox ().ScalarString () {
return false
}
}
return true
}
type Edge struct {
Range Range `json:"range"`
Src *KeyPath `json:"src"`
SrcArrow string `json:"src_arrow"`
Dst *KeyPath `json:"dst"`
DstArrow string `json:"dst_arrow"`
}
func (e1 *Edge ) Equals (e2 *Edge ) bool {
if !e1 .Src .Equals (e2 .Src ) {
return false
}
if e1 .SrcArrow != e2 .SrcArrow {
return false
}
if !e1 .Dst .Equals (e2 .Dst ) {
return false
}
if e1 .DstArrow != e2 .DstArrow {
return false
}
return true
}
type EdgeIndex struct {
Range Range `json:"range"`
Int *int `json:"int"`
Glob bool `json:"glob"`
}
func (ei1 *EdgeIndex ) Equals (ei2 *EdgeIndex ) bool {
if ei1 .Int != ei2 .Int {
return false
}
if ei1 .Glob != ei2 .Glob {
return false
}
return true
}
type Substitution struct {
Range Range `json:"range"`
Spread bool `json:"spread"`
Path []*StringBox `json:"path"`
}
type Import struct {
Range Range `json:"range"`
Spread bool `json:"spread"`
Pre string `json:"pre"`
Path []*StringBox `json:"path"`
}
type MapNodeBox struct {
Comment *Comment `json:"comment,omitempty"`
BlockComment *BlockComment `json:"block_comment,omitempty"`
Substitution *Substitution `json:"substitution,omitempty"`
Import *Import `json:"import,omitempty"`
MapKey *Key `json:"map_key,omitempty"`
}
func MakeMapNodeBox (n MapNode ) MapNodeBox {
var box MapNodeBox
switch n := n .(type ) {
case *Comment :
box .Comment = n
case *BlockComment :
box .BlockComment = n
case *Substitution :
box .Substitution = n
case *Import :
box .Import = n
case *Key :
box .MapKey = n
}
return box
}
func (mb MapNodeBox ) Unbox () MapNode {
switch {
case mb .Comment != nil :
return mb .Comment
case mb .BlockComment != nil :
return mb .BlockComment
case mb .Substitution != nil :
return mb .Substitution
case mb .Import != nil :
return mb .Import
case mb .MapKey != nil :
return mb .MapKey
default :
return nil
}
}
func (mb MapNodeBox ) IsBoardNode () bool {
if mb .MapKey == nil || mb .MapKey .Key == nil || len (mb .MapKey .Key .Path ) != 1 {
return false
}
switch mb .MapKey .Key .Path [0 ].Unbox ().ScalarString () {
case "layers" , "scenarios" , "steps" :
return true
default :
return false
}
}
type ArrayNodeBox struct {
Comment *Comment `json:"comment,omitempty"`
BlockComment *BlockComment `json:"block_comment,omitempty"`
Substitution *Substitution `json:"substitution,omitempty"`
Import *Import `json:"import,omitempty"`
Null *Null `json:"null,omitempty"`
Boolean *Boolean `json:"boolean,omitempty"`
Number *Number `json:"number,omitempty"`
UnquotedString *UnquotedString `json:"unquoted_string,omitempty"`
DoubleQuotedString *DoubleQuotedString `json:"double_quoted_string,omitempty"`
SingleQuotedString *SingleQuotedString `json:"single_quoted_string,omitempty"`
BlockString *BlockString `json:"block_string,omitempty"`
Array *Array `json:"array,omitempty"`
Map *Map `json:"map,omitempty"`
}
func MakeArrayNodeBox (an ArrayNode ) ArrayNodeBox {
var ab ArrayNodeBox
switch an := an .(type ) {
case *Comment :
ab .Comment = an
case *BlockComment :
ab .BlockComment = an
case *Substitution :
ab .Substitution = an
case *Import :
ab .Import = an
case *Null :
ab .Null = an
case *Boolean :
ab .Boolean = an
case *Number :
ab .Number = an
case *UnquotedString :
ab .UnquotedString = an
case *DoubleQuotedString :
ab .DoubleQuotedString = an
case *SingleQuotedString :
ab .SingleQuotedString = an
case *BlockString :
ab .BlockString = an
case *Array :
ab .Array = an
case *Map :
ab .Map = an
}
return ab
}
func (ab ArrayNodeBox ) Unbox () ArrayNode {
switch {
case ab .Comment != nil :
return ab .Comment
case ab .BlockComment != nil :
return ab .BlockComment
case ab .Substitution != nil :
return ab .Substitution
case ab .Import != nil :
return ab .Import
case ab .Null != nil :
return ab .Null
case ab .Boolean != nil :
return ab .Boolean
case ab .Number != nil :
return ab .Number
case ab .UnquotedString != nil :
return ab .UnquotedString
case ab .DoubleQuotedString != nil :
return ab .DoubleQuotedString
case ab .SingleQuotedString != nil :
return ab .SingleQuotedString
case ab .BlockString != nil :
return ab .BlockString
case ab .Array != nil :
return ab .Array
case ab .Map != nil :
return ab .Map
default :
return nil
}
}
type ValueBox struct {
Null *Null `json:"null,omitempty"`
Boolean *Boolean `json:"boolean,omitempty"`
Number *Number `json:"number,omitempty"`
UnquotedString *UnquotedString `json:"unquoted_string,omitempty"`
DoubleQuotedString *DoubleQuotedString `json:"double_quoted_string,omitempty"`
SingleQuotedString *SingleQuotedString `json:"single_quoted_string,omitempty"`
BlockString *BlockString `json:"block_string,omitempty"`
Array *Array `json:"array,omitempty"`
Map *Map `json:"map,omitempty"`
Import *Import `json:"import,omitempty"`
}
func (vb ValueBox ) Unbox () Value {
switch {
case vb .Null != nil :
return vb .Null
case vb .Boolean != nil :
return vb .Boolean
case vb .Number != nil :
return vb .Number
case vb .UnquotedString != nil :
return vb .UnquotedString
case vb .DoubleQuotedString != nil :
return vb .DoubleQuotedString
case vb .SingleQuotedString != nil :
return vb .SingleQuotedString
case vb .BlockString != nil :
return vb .BlockString
case vb .Array != nil :
return vb .Array
case vb .Map != nil :
return vb .Map
case vb .Import != nil :
return vb .Import
default :
return nil
}
}
func MakeValueBox (v Value ) ValueBox {
var vb ValueBox
switch v := v .(type ) {
case *Null :
vb .Null = v
case *Boolean :
vb .Boolean = v
case *Number :
vb .Number = v
case *UnquotedString :
vb .UnquotedString = v
case *DoubleQuotedString :
vb .DoubleQuotedString = v
case *SingleQuotedString :
vb .SingleQuotedString = v
case *BlockString :
vb .BlockString = v
case *Array :
vb .Array = v
case *Map :
vb .Map = v
case *Import :
vb .Import = v
}
return vb
}
func (vb ValueBox ) ScalarBox () ScalarBox {
var sb ScalarBox
sb .Null = vb .Null
sb .Boolean = vb .Boolean
sb .Number = vb .Number
sb .UnquotedString = vb .UnquotedString
sb .DoubleQuotedString = vb .DoubleQuotedString
sb .SingleQuotedString = vb .SingleQuotedString
sb .BlockString = vb .BlockString
return sb
}
func (vb ValueBox ) StringBox () *StringBox {
var sb StringBox
sb .UnquotedString = vb .UnquotedString
sb .DoubleQuotedString = vb .DoubleQuotedString
sb .SingleQuotedString = vb .SingleQuotedString
sb .BlockString = vb .BlockString
return &sb
}
type ScalarBox struct {
Null *Null `json:"null,omitempty"`
Boolean *Boolean `json:"boolean,omitempty"`
Number *Number `json:"number,omitempty"`
UnquotedString *UnquotedString `json:"unquoted_string,omitempty"`
DoubleQuotedString *DoubleQuotedString `json:"double_quoted_string,omitempty"`
SingleQuotedString *SingleQuotedString `json:"single_quoted_string,omitempty"`
BlockString *BlockString `json:"block_string,omitempty"`
}
func (sb ScalarBox ) Unbox () Scalar {
switch {
case sb .Null != nil :
return sb .Null
case sb .Boolean != nil :
return sb .Boolean
case sb .Number != nil :
return sb .Number
case sb .UnquotedString != nil :
return sb .UnquotedString
case sb .DoubleQuotedString != nil :
return sb .DoubleQuotedString
case sb .SingleQuotedString != nil :
return sb .SingleQuotedString
case sb .BlockString != nil :
return sb .BlockString
default :
return nil
}
}
func (sb ScalarBox ) ScalarString () string {
return sb .Unbox ().ScalarString ()
}
type StringBox struct {
UnquotedString *UnquotedString `json:"unquoted_string,omitempty"`
DoubleQuotedString *DoubleQuotedString `json:"double_quoted_string,omitempty"`
SingleQuotedString *SingleQuotedString `json:"single_quoted_string,omitempty"`
BlockString *BlockString `json:"block_string,omitempty"`
}
func (sb *StringBox ) Unbox () String {
switch {
case sb .UnquotedString != nil :
return sb .UnquotedString
case sb .DoubleQuotedString != nil :
return sb .DoubleQuotedString
case sb .SingleQuotedString != nil :
return sb .SingleQuotedString
case sb .BlockString != nil :
return sb .BlockString
default :
return nil
}
}
func (sb *StringBox ) ScalarString () string {
return sb .Unbox ().ScalarString ()
}
type InterpolationBox struct {
String *string `json:"string,omitempty"`
StringRaw *string `json:"raw_string,omitempty"`
Substitution *Substitution `json:"substitution,omitempty"`
}
var UnquotedKeySpecials = string ([]rune {'#' , ';' , '\n' , '\\' , '{' , '}' , '[' , ']' , '\'' , '"' , '|' , ':' , '.' , '-' , '<' , '>' , '*' , '&' , '(' , ')' , '@' , '&' })
var UnquotedValueSpecials = string ([]rune {'#' , ';' , '\n' , '\\' , '{' , '}' , '[' , ']' , '\'' , '"' , '|' , '$' , '@' })
func RawString (s string , inKey bool ) String {
if s == "" {
return FlatDoubleQuotedString (s )
}
if inKey {
for i , r := range s {
switch r {
case '-' :
if i +1 < len (s ) && s [i +1 ] != '-' {
continue
}
}
if strings .ContainsRune (UnquotedKeySpecials , r ) {
if !strings .ContainsRune (s , '"' ) {
return FlatDoubleQuotedString (s )
}
if strings .ContainsRune (s , '\n' ) {
return FlatDoubleQuotedString (s )
}
return &SingleQuotedString {Value : s }
}
}
} else if s == "null" || strings .ContainsAny (s , UnquotedValueSpecials ) {
if !strings .ContainsRune (s , '"' ) && !strings .ContainsRune (s , '$' ) {
return FlatDoubleQuotedString (s )
}
if strings .ContainsRune (s , '\n' ) {
return FlatDoubleQuotedString (s )
}
return &SingleQuotedString {Value : s }
}
if hasSurroundingWhitespace (s ) {
return FlatDoubleQuotedString (s )
}
return FlatUnquotedString (s )
}
func RawStringBox (s string , inKey bool ) *StringBox {
return MakeValueBox (RawString (s , inKey )).StringBox ()
}
func hasSurroundingWhitespace(s string ) bool {
r , _ := utf8 .DecodeRuneInString (s )
r2 , _ := utf8 .DecodeLastRuneInString (s )
return unicode .IsSpace (r ) || unicode .IsSpace (r2 )
}
func (s *Substitution ) IDA () (ida []string ) {
for _ , el := range s .Path {
ida = append (ida , el .Unbox ().ScalarString ())
}
return ida
}
func (i *Import ) IDA () (ida []String ) {
for _ , el := range i .Path [1 :] {
ida = append (ida , el .Unbox ())
}
return ida
}
func (i *Import ) PathWithPre () string {
if len (i .Path ) == 0 {
return ""
}
return path .Join (i .Pre , i .Path [0 ].Unbox ().ScalarString ())
}
func (i *Import ) Dir () string {
return path .Dir (i .PathWithPre ())
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .