d2ir: Add d2ir -> d2ast for stringifying the IR
This commit is contained in:
parent
91149543f5
commit
10ca5e2ce1
3 changed files with 134 additions and 28 deletions
|
|
@ -650,6 +650,14 @@ type KeyPath struct {
|
||||||
Path []*StringBox `json:"path"`
|
Path []*StringBox `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MakeKeyPath(a []string) *KeyPath {
|
||||||
|
var kp *KeyPath
|
||||||
|
for _, el := range a {
|
||||||
|
kp.Path = append(kp.Path, MakeValueBox(RawString(el, true)).StringBox())
|
||||||
|
}
|
||||||
|
return kp
|
||||||
|
}
|
||||||
|
|
||||||
type Edge struct {
|
type Edge struct {
|
||||||
Range Range `json:"range"`
|
Range Range `json:"range"`
|
||||||
|
|
||||||
|
|
@ -731,6 +739,37 @@ type ArrayNodeBox struct {
|
||||||
Map *Map `json:"map,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 *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 {
|
func (ab ArrayNodeBox) Unbox() ArrayNode {
|
||||||
switch {
|
switch {
|
||||||
case ab.Comment != nil:
|
case ab.Comment != nil:
|
||||||
|
|
|
||||||
|
|
@ -214,12 +214,7 @@ func testCompileField(t *testing.T) {
|
||||||
assertField(t, m, 1, 0, nil)
|
assertField(t, m, 1, 0, nil)
|
||||||
|
|
||||||
f := assertField(t, m, 0, 0, nil, "x")
|
f := assertField(t, m, 0, 0, nil, "x")
|
||||||
f_a, ok := f.Composite.(*d2ir.Array)
|
assert.String(t, `[1; 2; 3; 4]`, f.Composite.String())
|
||||||
if !ok {
|
|
||||||
t.Fatalf("unexpected type: %T", f.Composite)
|
|
||||||
} else {
|
|
||||||
assert.Equal(t, 4, len(f_a.Values))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
116
d2ir/d2ir.go
116
d2ir/d2ir.go
|
|
@ -1,7 +1,6 @@
|
||||||
package d2ir
|
package d2ir
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -12,7 +11,9 @@ import (
|
||||||
|
|
||||||
type Node interface {
|
type Node interface {
|
||||||
node()
|
node()
|
||||||
|
ast() d2ast.Node
|
||||||
Copy(newp Parent) Node
|
Copy(newp Parent) Node
|
||||||
|
fmt.Stringer
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Node = &Scalar{}
|
var _ Node = &Scalar{}
|
||||||
|
|
@ -68,6 +69,12 @@ func (n *Map) value() {}
|
||||||
func (n *Array) composite() {}
|
func (n *Array) composite() {}
|
||||||
func (n *Map) composite() {}
|
func (n *Map) composite() {}
|
||||||
|
|
||||||
|
func (n *Scalar) String() string { return d2format.Format(n.ast()) }
|
||||||
|
func (n *Field) String() string { return d2format.Format(n.ast()) }
|
||||||
|
func (n *Edge) String() string { return d2format.Format(n.ast()) }
|
||||||
|
func (n *Array) String() string { return d2format.Format(n.ast()) }
|
||||||
|
func (n *Map) String() string { return d2format.Format(n.ast()) }
|
||||||
|
|
||||||
type Scalar struct {
|
type Scalar struct {
|
||||||
parent Parent
|
parent Parent
|
||||||
Value d2ast.Scalar `json:"value"`
|
Value d2ast.Scalar `json:"value"`
|
||||||
|
|
@ -91,10 +98,6 @@ func (s *Scalar) Equal(s2 *Scalar) bool {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scalar) String() string {
|
|
||||||
return d2format.Format(s.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Map struct {
|
type Map struct {
|
||||||
parent Parent
|
parent Parent
|
||||||
Fields []*Field `json:"fields"`
|
Fields []*Field `json:"fields"`
|
||||||
|
|
@ -160,6 +163,21 @@ type EdgeID struct {
|
||||||
Index *int `json:"index"`
|
Index *int `json:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewEdgeIDs(k *d2ast.Key) (eida []*EdgeID) {
|
||||||
|
for _, ke := range k.Edges {
|
||||||
|
eida = append(eida, &EdgeID{
|
||||||
|
SrcPath: d2format.KeyPath(ke.Src),
|
||||||
|
SrcArrow: ke.SrcArrow == "<",
|
||||||
|
DstPath: d2format.KeyPath(ke.Dst),
|
||||||
|
DstArrow: ke.DstArrow == ">",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if k.EdgeIndex != nil && k.EdgeIndex.Int != nil {
|
||||||
|
eida[0].Index = k.EdgeIndex.Int
|
||||||
|
}
|
||||||
|
return eida
|
||||||
|
}
|
||||||
|
|
||||||
func (eid *EdgeID) Copy() *EdgeID {
|
func (eid *EdgeID) Copy() *EdgeID {
|
||||||
tmp := *eid
|
tmp := *eid
|
||||||
eid = &tmp
|
eid = &tmp
|
||||||
|
|
@ -447,25 +465,79 @@ func (m *Map) EnsureEdge(eid *EdgeID) (*Edge, error) {
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Map) String() string {
|
func (s *Scalar) ast() d2ast.Node {
|
||||||
b, err := json.Marshal(m)
|
return s.Value
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("d2ir: failed to marshal d2ir.Map: %v", err))
|
|
||||||
}
|
|
||||||
return string(b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEdgeIDs(k *d2ast.Key) (eida []*EdgeID) {
|
func (f *Field) ast() d2ast.Node {
|
||||||
for _, ke := range k.Edges {
|
k := &d2ast.Key{
|
||||||
eida = append(eida, &EdgeID{
|
Key: &d2ast.KeyPath{
|
||||||
SrcPath: d2format.KeyPath(ke.Src),
|
Path: []*d2ast.StringBox{
|
||||||
SrcArrow: ke.SrcArrow == "<",
|
d2ast.MakeValueBox(d2ast.RawString(f.Name, true)).StringBox(),
|
||||||
DstPath: d2format.KeyPath(ke.Dst),
|
},
|
||||||
DstArrow: ke.DstArrow == ">",
|
},
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if k.EdgeIndex != nil && k.EdgeIndex.Int != nil {
|
|
||||||
eida[0].Index = k.EdgeIndex.Int
|
if f.Primary != nil {
|
||||||
|
k.Primary = d2ast.MakeValueBox(f.Primary.ast().(d2ast.Value)).ScalarBox()
|
||||||
}
|
}
|
||||||
return eida
|
if f.Composite != nil {
|
||||||
|
k.Value = d2ast.MakeValueBox(f.Composite.ast().(d2ast.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Edge) ast() d2ast.Node {
|
||||||
|
astEdge := &d2ast.Edge{}
|
||||||
|
|
||||||
|
astEdge.Src = d2ast.MakeKeyPath(e.ID.SrcPath)
|
||||||
|
if e.ID.SrcArrow {
|
||||||
|
astEdge.SrcArrow = "<"
|
||||||
|
}
|
||||||
|
astEdge.Dst = d2ast.MakeKeyPath(e.ID.DstPath)
|
||||||
|
if e.ID.DstArrow {
|
||||||
|
astEdge.DstArrow = ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
k := &d2ast.Key{
|
||||||
|
Edges: []*d2ast.Edge{astEdge},
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Primary != nil {
|
||||||
|
k.Primary = d2ast.MakeValueBox(e.Primary.ast().(d2ast.Value)).ScalarBox()
|
||||||
|
}
|
||||||
|
if e.Map != nil {
|
||||||
|
k.Value = d2ast.MakeValueBox(e.Map.ast().(*d2ast.Map))
|
||||||
|
}
|
||||||
|
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Array) ast() d2ast.Node {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
astArray := &d2ast.Array{}
|
||||||
|
for _, av := range a.Values {
|
||||||
|
astArray.Nodes = append(astArray.Nodes, d2ast.MakeArrayNodeBox(av.ast().(d2ast.ArrayNode)))
|
||||||
|
}
|
||||||
|
return astArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Map) ast() d2ast.Node {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
astMap := &d2ast.Map{}
|
||||||
|
if m.parent != nil {
|
||||||
|
astMap.Range = d2ast.MakeRange(",1:0:0-1:0:0")
|
||||||
|
}
|
||||||
|
for _, f := range m.Fields {
|
||||||
|
astMap.Nodes = append(astMap.Nodes, d2ast.MakeMapNodeBox(f.ast().(d2ast.MapNode)))
|
||||||
|
}
|
||||||
|
for _, e := range m.Edges {
|
||||||
|
astMap.Nodes = append(astMap.Nodes, d2ast.MakeMapNodeBox(e.ast().(d2ast.MapNode)))
|
||||||
|
}
|
||||||
|
return astMap
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue