d2compiler: Integrate d2ir (wip)
This commit is contained in:
parent
3e7bdc5468
commit
154c7e8947
5 changed files with 149 additions and 112 deletions
|
|
@ -111,13 +111,13 @@ func (c *compiler) compileMap(obj *d2graph.Object, m *d2ir.Map) {
|
||||||
|
|
||||||
switch obj.Attributes.Shape.Value {
|
switch obj.Attributes.Shape.Value {
|
||||||
case d2target.ShapeClass:
|
case d2target.ShapeClass:
|
||||||
c.compileClass(obj, m)
|
c.compileClass(obj)
|
||||||
case d2target.ShapeSQLTable:
|
case d2target.ShapeSQLTable:
|
||||||
c.compileSQLTable(obj, m)
|
c.compileSQLTable(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range m.Edges {
|
for _, e := range m.Edges {
|
||||||
c.compileEdge(obj, m, e)
|
c.compileEdge(obj, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
|
||||||
|
|
||||||
obj = obj.EnsureChild([]string{f.Name})
|
obj = obj.EnsureChild([]string{f.Name})
|
||||||
if f.Primary() != nil {
|
if f.Primary() != nil {
|
||||||
c.compileLabel(obj, f)
|
c.compileLabel(obj.Attributes, f)
|
||||||
}
|
}
|
||||||
if f.Map() != nil {
|
if f.Map() != nil {
|
||||||
c.compileMap(obj, f.Map())
|
c.compileMap(obj, f.Map())
|
||||||
|
|
@ -167,11 +167,11 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) {
|
||||||
attrs.Label.MapKey = f.LastPrimaryKey()
|
attrs.Label.MapKey = f.LastPrimaryKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) compileReserved(attrs *d2graph.Attributes, f d2ir.Node) {
|
func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||||
scalar := f.Primary().Value
|
scalar := f.Primary().Value
|
||||||
switch f.Name {
|
switch f.Name {
|
||||||
case "label":
|
case "label":
|
||||||
c.compileLabel(obj, f)
|
c.compileLabel(attrs, f)
|
||||||
case "shape":
|
case "shape":
|
||||||
in := d2target.IsShape(scalar.ScalarString())
|
in := d2target.IsShape(scalar.ScalarString())
|
||||||
if !in {
|
if !in {
|
||||||
|
|
@ -233,7 +233,13 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f d2ir.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) compileStyle(attrs *d2graph.Attributes, f d2ir.Node) {
|
func (c *compiler) compileStyle(attrs *d2graph.Attributes, m *d2ir.Map) {
|
||||||
|
for _, f := range m.Fields {
|
||||||
|
c.compileStyleField(attrs, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compiler) compileStyleField(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||||
scalar := f.Primary().Value
|
scalar := f.Primary().Value
|
||||||
err := attrs.Style.Apply(f.Name, scalar.ScalarString())
|
err := attrs.Style.Apply(f.Name, scalar.ScalarString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -286,7 +292,7 @@ func (c *compiler) compileStyle(attrs *d2graph.Attributes, f d2ir.Node) {
|
||||||
func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
|
func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
|
||||||
edge, err := obj.Connect(e.ID.SrcPath, e.ID.DstPath, e.ID.SrcArrow, e.ID.DstArrow, "")
|
edge, err := obj.Connect(e.ID.SrcPath, e.ID.DstPath, e.ID.SrcArrow, e.ID.DstArrow, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.errorf(e, err.Error())
|
c.errorf(e.References[0].AST(), err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,7 +303,7 @@ func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
|
||||||
for _, f := range e.Map().Fields {
|
for _, f := range e.Map().Fields {
|
||||||
_, ok := d2graph.ReservedKeywords[f.Name]
|
_, ok := d2graph.ReservedKeywords[f.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
c.errorf(mk, `edge map keys must be reserved keywords`)
|
c.errorf(f.References[0].AST(), `edge map keys must be reserved keywords`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.compileEdgeField(edge, f)
|
c.compileEdgeField(edge, f)
|
||||||
|
|
@ -320,7 +326,7 @@ func (c *compiler) compileEdgeField(edge *d2graph.Edge, f *d2ir.Field) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Primary() != nil {
|
if f.Primary() != nil {
|
||||||
c.compileLabel(edge, f)
|
c.compileLabel(edge.Attributes, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Name == "source-arrowhead" || f.Name == "target-arrowhead" {
|
if f.Name == "source-arrowhead" || f.Name == "target-arrowhead" {
|
||||||
|
|
@ -341,6 +347,7 @@ func (c *compiler) compileArrowheads(edge *d2graph.Edge, f *d2ir.Field) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f2 := range f.Map().Fields {
|
for _, f2 := range f.Map().Fields {
|
||||||
|
keyword := strings.ToLower(f2.Name)
|
||||||
_, isReserved := d2graph.ReservedKeywords[keyword]
|
_, isReserved := d2graph.ReservedKeywords[keyword]
|
||||||
if isReserved {
|
if isReserved {
|
||||||
c.compileReserved(attrs, f2)
|
c.compileReserved(attrs, f2)
|
||||||
|
|
@ -352,7 +359,7 @@ func (c *compiler) compileArrowheads(edge *d2graph.Edge, f *d2ir.Field) {
|
||||||
c.compileStyle(attrs, f2.Map())
|
c.compileStyle(attrs, f2.Map())
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
c.errorf(mk, `source-arrowhead/target-arrowhead map keys must be reserved keywords`)
|
c.errorf(f2.LastRef().AST(), `source-arrowhead/target-arrowhead map keys must be reserved keywords`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -370,24 +377,7 @@ var ShortToFullLanguageAliases = map[string]string{
|
||||||
}
|
}
|
||||||
var FullToShortLanguageAliases map[string]string
|
var FullToShortLanguageAliases map[string]string
|
||||||
|
|
||||||
func (c *compiler) compileShapes(obj *d2graph.Object) {
|
|
||||||
for _, obj := range obj.ChildrenArray {
|
|
||||||
switch obj.Attributes.Shape.Value {
|
|
||||||
case d2target.ShapeClass:
|
|
||||||
c.compileClass(obj)
|
|
||||||
case d2target.ShapeSQLTable:
|
|
||||||
c.compileSQLTable(obj)
|
|
||||||
}
|
|
||||||
c.compileShapes(obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *compiler) compileClass(obj *d2graph.Object) {
|
func (c *compiler) compileClass(obj *d2graph.Object) {
|
||||||
if len(m.Edges) > 0 {
|
|
||||||
c.errorf(m.Edges[0].LastAST(), "class shapes cannot have edges inside")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Class = &d2target.Class{}
|
obj.Class = &d2target.Class{}
|
||||||
for _, f := range obj.ChildrenArray {
|
for _, f := range obj.ChildrenArray {
|
||||||
visiblity := "public"
|
visiblity := "public"
|
||||||
|
|
@ -436,15 +426,7 @@ func (c *compiler) compileClass(obj *d2graph.Object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) compileSQLTable(obj *d2graph.Object) {
|
func (c *compiler) compileSQLTable(obj *d2graph.Object) {
|
||||||
if len(m.Edges) > 0 {
|
|
||||||
c.errorf(m.Edges[0].LastAST(), "sql_table shapes cannot have edges inside")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.SQLTable = &d2target.SQLTable{}
|
obj.SQLTable = &d2target.SQLTable{}
|
||||||
|
|
||||||
parentID := obj.Parent.AbsID()
|
|
||||||
tableIDPrefix := obj.AbsID() + "."
|
|
||||||
for _, col := range obj.ChildrenArray {
|
for _, col := range obj.ChildrenArray {
|
||||||
typ := col.Attributes.Label.Value
|
typ := col.Attributes.Label.Value
|
||||||
if typ == col.IDVal {
|
if typ == col.IDVal {
|
||||||
|
|
@ -480,12 +462,13 @@ func (c *compiler) compileSQLTable(obj *d2graph.Object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) validateKeys(obj *d2graph.Object, m *d2ir.Map) {
|
func (c *compiler) validateKeys(obj *d2graph.Object, m *d2ir.Map) {
|
||||||
for _, n := range m.Fields {
|
for _, f := range m.Fields {
|
||||||
c.validateKey(obj, f)
|
c.validateKey(obj, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
||||||
|
keyword := strings.ToLower(f.Name)
|
||||||
_, isReserved := d2graph.ReservedKeywords[keyword]
|
_, isReserved := d2graph.ReservedKeywords[keyword]
|
||||||
if isReserved {
|
if isReserved {
|
||||||
switch obj.Attributes.Shape.Value {
|
switch obj.Attributes.Shape.Value {
|
||||||
|
|
@ -526,7 +509,7 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if len(obj.Children) > 0 && (f.Name == "width" || f.Name == "height") {
|
if len(obj.Children) > 0 && (f.Name == "width" || f.Name == "height") {
|
||||||
c.errorf(f.LastPrimaryKey(), mk.Range.End, fmt.Sprintf("%s cannot be used on container: %s", f.Name, obj.AbsID()))
|
c.errorf(f.LastPrimaryKey(), fmt.Sprintf("%s cannot be used on container: %s", f.Name, obj.AbsID()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -540,12 +523,12 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.Attributes.Shape.Value == d2target.ShapeImage {
|
if obj.Attributes.Shape.Value == d2target.ShapeImage {
|
||||||
c.errorf(mk, "image shapes cannot have children.")
|
c.errorf(obj.Attributes.Shape.MapKey, "image shapes cannot have children.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = obj.HasChild([]string{f.Name})
|
obj, ok := obj.HasChild([]string{f.Name})
|
||||||
if f.Map() != nil {
|
if ok && f.Map() != nil {
|
||||||
c.validateKeys(obj, f.Map())
|
c.validateKeys(obj, f.Map())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -973,7 +973,18 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
|
||||||
}
|
}
|
||||||
e.initIndex()
|
e.initIndex()
|
||||||
|
|
||||||
|
addSQLTableColumnIndexes(e, srcID, dstID, obj, src, dst)
|
||||||
|
|
||||||
|
obj.Graph.Edges = append(obj.Graph.Edges, e)
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addSQLTableColumnIndexes(e *Edge, srcID, dstID []string, obj, src, dst *Object) {
|
||||||
if src.Attributes.Shape.Value == d2target.ShapeSQLTable {
|
if src.Attributes.Shape.Value == d2target.ShapeSQLTable {
|
||||||
|
if src == dst {
|
||||||
|
// Ignore edge to column inside table.
|
||||||
|
return
|
||||||
|
}
|
||||||
objAbsID := obj.AbsIDArray()
|
objAbsID := obj.AbsIDArray()
|
||||||
srcAbsID := src.AbsIDArray()
|
srcAbsID := src.AbsIDArray()
|
||||||
if len(objAbsID) + len(srcID) > len(srcAbsID) {
|
if len(objAbsID) + len(srcID) > len(srcAbsID) {
|
||||||
|
|
@ -1001,10 +1012,6 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
obj.Graph.Edges = append(obj.Graph.Edges, e)
|
|
||||||
return e, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Treat undirectional/bidirectional edge here and in HasEdge flipped. Same with
|
// TODO: Treat undirectional/bidirectional edge here and in HasEdge flipped. Same with
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,16 @@ func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
|
||||||
|
|
||||||
func Compile(ast *d2ast.Map) (*Map, error) {
|
func Compile(ast *d2ast.Map) (*Map, error) {
|
||||||
c := &compiler{}
|
c := &compiler{}
|
||||||
m := &Map{}
|
m := &Map{
|
||||||
|
parent: &Field{
|
||||||
|
Name: "",
|
||||||
|
References: []*FieldReference{{
|
||||||
|
Context: &RefContext{
|
||||||
|
Scope: ast,
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
c.compileMap(m, ast)
|
c.compileMap(m, ast)
|
||||||
c.compileScenarios(m)
|
c.compileScenarios(m)
|
||||||
c.compileSteps(m)
|
c.compileSteps(m)
|
||||||
|
|
@ -160,7 +169,7 @@ func (c *compiler) compileEdges(dst *Map, refctx *RefContext) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
e = ea[0]
|
e = ea[0]
|
||||||
e.References = append(e.References, EdgeReference{
|
e.References = append(e.References, &EdgeReference{
|
||||||
Context: refctx,
|
Context: refctx,
|
||||||
})
|
})
|
||||||
dst.appendFieldReferences(0, refctx.Edge.Src, refctx)
|
dst.appendFieldReferences(0, refctx.Edge.Src, refctx)
|
||||||
|
|
|
||||||
166
d2ir/d2ir.go
166
d2ir/d2ir.go
|
|
@ -30,11 +30,6 @@ type Node interface {
|
||||||
LastPrimaryKey() *d2ast.Key
|
LastPrimaryKey() *d2ast.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
type Reference interface {
|
|
||||||
reference()
|
|
||||||
AST() d2ast.Node
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Node = &Scalar{}
|
var _ Node = &Scalar{}
|
||||||
var _ Node = &Field{}
|
var _ Node = &Field{}
|
||||||
var _ Node = &Edge{}
|
var _ Node = &Edge{}
|
||||||
|
|
@ -109,6 +104,26 @@ func (n *Edge) String() string { return d2format.Format(n.ast()) }
|
||||||
func (n *Array) 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()) }
|
func (n *Map) String() string { return d2format.Format(n.ast()) }
|
||||||
|
|
||||||
|
func (n *Scalar) LastRef() Reference { return parentRef(n) }
|
||||||
|
func (n *Map) LastRef() Reference { return parentRef(n) }
|
||||||
|
func (n *Array) LastRef() Reference { return parentRef(n) }
|
||||||
|
|
||||||
|
func (n *Scalar) LastPrimaryKey() *d2ast.Key { return parentPrimaryKey(n) }
|
||||||
|
func (n *Map) LastPrimaryKey() *d2ast.Key { return parentPrimaryKey(n) }
|
||||||
|
func (n *Array) LastPrimaryKey() *d2ast.Key { return parentPrimaryKey(n) }
|
||||||
|
|
||||||
|
type Reference interface {
|
||||||
|
reference()
|
||||||
|
// Most specific AST node for the reference.
|
||||||
|
AST() d2ast.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Reference = &FieldReference{}
|
||||||
|
var _ Reference = &EdgeReference{}
|
||||||
|
|
||||||
|
func (r *FieldReference) reference() {}
|
||||||
|
func (r *EdgeReference) reference() {}
|
||||||
|
|
||||||
type Scalar struct {
|
type Scalar struct {
|
||||||
parent Node
|
parent Node
|
||||||
Value d2ast.Scalar `json:"value"`
|
Value d2ast.Scalar `json:"value"`
|
||||||
|
|
@ -174,18 +189,14 @@ func (m *Map) CopyBase(newParent Node) *Map {
|
||||||
|
|
||||||
// Root reports whether the Map is the root of the D2 tree.
|
// Root reports whether the Map is the root of the D2 tree.
|
||||||
func (m *Map) Root() bool {
|
func (m *Map) Root() bool {
|
||||||
return m.parent == nil
|
// m.parent exists even on the root map as we store the root AST in
|
||||||
}
|
// m.parent.References[0].Context.Map for reporting error messages about the whole IR.
|
||||||
|
// Or if otherwise needed.
|
||||||
func (f *Map) LastRef() *MapReference {
|
f, ok := m.parent.(*Field)
|
||||||
if f.parent == nil {
|
if !ok {
|
||||||
return nil
|
return false
|
||||||
}
|
}
|
||||||
return f.References[len(f.References)-1]
|
return f.Name == ""
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Map) LastAST() d2ast.Node {
|
|
||||||
return f.LastRef().String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LayerKind string
|
type LayerKind string
|
||||||
|
|
@ -199,25 +210,26 @@ const (
|
||||||
// NodeLayerKind reports whether n represents the root of a layer.
|
// NodeLayerKind reports whether n represents the root of a layer.
|
||||||
// n should be *Field or *Map
|
// n should be *Field or *Map
|
||||||
func NodeLayerKind(n Node) LayerKind {
|
func NodeLayerKind(n Node) LayerKind {
|
||||||
|
var f *Field
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *Field:
|
case *Field:
|
||||||
n = ParentField(n)
|
f = ParentField(n)
|
||||||
if n != nil {
|
|
||||||
switch n.Name {
|
|
||||||
case "layers":
|
|
||||||
return LayerLayer
|
|
||||||
case "scenarios":
|
|
||||||
return LayerScenario
|
|
||||||
case "steps":
|
|
||||||
return LayerStep
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *Map:
|
case *Map:
|
||||||
f := ParentField(n)
|
f = ParentField(n)
|
||||||
if f == nil {
|
}
|
||||||
return LayerLayer
|
if f == nil {
|
||||||
}
|
return ""
|
||||||
return NodeLayerKind(f)
|
}
|
||||||
|
switch f.Name {
|
||||||
|
case "layers":
|
||||||
|
return LayerLayer
|
||||||
|
case "scenarios":
|
||||||
|
return LayerScenario
|
||||||
|
case "steps":
|
||||||
|
return LayerStep
|
||||||
|
case "":
|
||||||
|
// root
|
||||||
|
return LayerLayer
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -230,7 +242,7 @@ type Field struct {
|
||||||
Primary_ *Scalar `json:"primary,omitempty"`
|
Primary_ *Scalar `json:"primary,omitempty"`
|
||||||
Composite Composite `json:"composite,omitempty"`
|
Composite Composite `json:"composite,omitempty"`
|
||||||
|
|
||||||
References []FieldReference `json:"references,omitempty"`
|
References []*FieldReference `json:"references,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) Copy(newParent Node) Node {
|
func (f *Field) Copy(newParent Node) Node {
|
||||||
|
|
@ -238,7 +250,7 @@ func (f *Field) Copy(newParent Node) Node {
|
||||||
f = &tmp
|
f = &tmp
|
||||||
|
|
||||||
f.parent = newParent.(*Map)
|
f.parent = newParent.(*Map)
|
||||||
f.References = append([]FieldReference(nil), f.References...)
|
f.References = append([]*FieldReference(nil), f.References...)
|
||||||
if f.Primary_ != nil {
|
if f.Primary_ != nil {
|
||||||
f.Primary_ = f.Primary_.Copy(f).(*Scalar)
|
f.Primary_ = f.Primary_.Copy(f).(*Scalar)
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +260,7 @@ func (f *Field) Copy(newParent Node) Node {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) LastPrimaryRef() *FieldReference {
|
func (f *Field) lastPrimaryRef() *FieldReference {
|
||||||
inEdge := ParentEdge(f) != nil
|
inEdge := ParentEdge(f) != nil
|
||||||
for i := len(f.References) - 1; i >= 0; i-- {
|
for i := len(f.References) - 1; i >= 0; i-- {
|
||||||
fr := f.References[i]
|
fr := f.References[i]
|
||||||
|
|
@ -266,21 +278,17 @@ func (f *Field) LastPrimaryRef() *FieldReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) LastPrimaryKey() *d2ast.Key {
|
func (f *Field) LastPrimaryKey() *d2ast.Key {
|
||||||
fr := f.LastModification()
|
fr := f.lastPrimaryRef()
|
||||||
if fr == nil {
|
if fr == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fr.Context.Key
|
return fr.Context.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) LastRef() *FieldReference {
|
func (f *Field) LastRef() Reference {
|
||||||
return f.References[len(f.References)-1]
|
return f.References[len(f.References)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) LastAST() d2ast.Node {
|
|
||||||
return f.LastRef().String
|
|
||||||
}
|
|
||||||
|
|
||||||
type EdgeID struct {
|
type EdgeID struct {
|
||||||
SrcPath []string `json:"src_path"`
|
SrcPath []string `json:"src_path"`
|
||||||
SrcArrow bool `json:"src_arrow"`
|
SrcArrow bool `json:"src_arrow"`
|
||||||
|
|
@ -396,7 +404,7 @@ type Edge struct {
|
||||||
Primary_ *Scalar `json:"primary,omitempty"`
|
Primary_ *Scalar `json:"primary,omitempty"`
|
||||||
Map_ *Map `json:"map,omitempty"`
|
Map_ *Map `json:"map,omitempty"`
|
||||||
|
|
||||||
References []EdgeReference `json:"references,omitempty"`
|
References []*EdgeReference `json:"references,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Edge) Copy(newParent Node) Node {
|
func (e *Edge) Copy(newParent Node) Node {
|
||||||
|
|
@ -404,7 +412,7 @@ func (e *Edge) Copy(newParent Node) Node {
|
||||||
e = &tmp
|
e = &tmp
|
||||||
|
|
||||||
e.parent = newParent.(*Map)
|
e.parent = newParent.(*Map)
|
||||||
e.References = append([]EdgeReference(nil), e.References...)
|
e.References = append([]*EdgeReference(nil), e.References...)
|
||||||
if e.Primary_ != nil {
|
if e.Primary_ != nil {
|
||||||
e.Primary_ = e.Primary_.Copy(e).(*Scalar)
|
e.Primary_ = e.Primary_.Copy(e).(*Scalar)
|
||||||
}
|
}
|
||||||
|
|
@ -414,7 +422,7 @@ func (e *Edge) Copy(newParent Node) Node {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Edge) LastPrimaryRef() *EdgeReference {
|
func (e *Edge) lastPrimaryRef() *EdgeReference {
|
||||||
for i := len(e.References) - 1; i >= 0; i-- {
|
for i := len(e.References) - 1; i >= 0; i-- {
|
||||||
fr := e.References[i]
|
fr := e.References[i]
|
||||||
if fr.Context.Key.EdgeKey == nil {
|
if fr.Context.Key.EdgeKey == nil {
|
||||||
|
|
@ -425,21 +433,17 @@ func (e *Edge) LastPrimaryRef() *EdgeReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Edge) LastPrimaryKey() *d2ast.Key {
|
func (e *Edge) LastPrimaryKey() *d2ast.Key {
|
||||||
fr := f.LastModification()
|
er := e.lastPrimaryRef()
|
||||||
if fr == nil {
|
if er == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fr.Context.Key
|
return er.Context.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Edge) LastRef() *EdgeReference {
|
func (e *Edge) LastRef() Reference {
|
||||||
return e.References[len(e.References)-1]
|
return e.References[len(e.References)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Edge) LastAST() d2ast.Node {
|
|
||||||
return e.LastRef().Context.Edge
|
|
||||||
}
|
|
||||||
|
|
||||||
type Array struct {
|
type Array struct {
|
||||||
parent Node
|
parent Node
|
||||||
Values []Value `json:"values"`
|
Values []Value `json:"values"`
|
||||||
|
|
@ -464,27 +468,39 @@ type FieldReference struct {
|
||||||
Context *RefContext `json:"context"`
|
Context *RefContext `json:"context"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kr FieldReference) KeyPathIndex() int {
|
func (fr *FieldReference) KeyPathIndex() int {
|
||||||
for i, sb := range kr.KeyPath.Path {
|
for i, sb := range fr.KeyPath.Path {
|
||||||
if sb.Unbox() == kr.String {
|
if sb.Unbox() == fr.String {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("d2ir.KeyReference.KeyPathIndex: String not in KeyPath?")
|
panic("d2ir.KeyReference.KeyPathIndex: String not in KeyPath?")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kr FieldReference) EdgeDest() bool {
|
func (fr *FieldReference) EdgeDest() bool {
|
||||||
return kr.KeyPath == kr.Context.Edge.Dst
|
return fr.KeyPath == fr.Context.Edge.Dst
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kr FieldReference) InEdge() bool {
|
func (fr *FieldReference) InEdge() bool {
|
||||||
return kr.Context.Edge != nil
|
return fr.Context.Edge != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fr *FieldReference) AST() d2ast.Node {
|
||||||
|
if fr.String == nil {
|
||||||
|
// Root map.
|
||||||
|
return fr.Context.Scope
|
||||||
|
}
|
||||||
|
return fr.String
|
||||||
}
|
}
|
||||||
|
|
||||||
type EdgeReference struct {
|
type EdgeReference struct {
|
||||||
Context *RefContext `json:"context"`
|
Context *RefContext `json:"context"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (er *EdgeReference) AST() d2ast.Node {
|
||||||
|
return er.Context.Edge
|
||||||
|
}
|
||||||
|
|
||||||
type RefContext struct {
|
type RefContext struct {
|
||||||
Edge *d2ast.Edge `json:"edge"`
|
Edge *d2ast.Edge `json:"edge"`
|
||||||
Key *d2ast.Key `json:"key"`
|
Key *d2ast.Key `json:"key"`
|
||||||
|
|
@ -628,7 +644,7 @@ func (m *Map) ensureField(i int, kp *d2ast.KeyPath, refctx *RefContext) (*Field,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
f.References = append(f.References, FieldReference{
|
f.References = append(f.References, &FieldReference{
|
||||||
String: kp.Path[i].Unbox(),
|
String: kp.Path[i].Unbox(),
|
||||||
KeyPath: kp,
|
KeyPath: kp,
|
||||||
Context: refctx,
|
Context: refctx,
|
||||||
|
|
@ -651,7 +667,7 @@ func (m *Map) ensureField(i int, kp *d2ast.KeyPath, refctx *RefContext) (*Field,
|
||||||
f := &Field{
|
f := &Field{
|
||||||
parent: m,
|
parent: m,
|
||||||
Name: head,
|
Name: head,
|
||||||
References: []FieldReference{{
|
References: []*FieldReference{{
|
||||||
String: kp.Path[i].Unbox(),
|
String: kp.Path[i].Unbox(),
|
||||||
KeyPath: kp,
|
KeyPath: kp,
|
||||||
Context: refctx,
|
Context: refctx,
|
||||||
|
|
@ -773,7 +789,7 @@ func (m *Map) CreateEdge(eid *EdgeID, refctx *RefContext) (*Edge, error) {
|
||||||
e := &Edge{
|
e := &Edge{
|
||||||
parent: m,
|
parent: m,
|
||||||
ID: eid,
|
ID: eid,
|
||||||
References: []EdgeReference{{
|
References: []*EdgeReference{{
|
||||||
Context: refctx,
|
Context: refctx,
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
@ -868,7 +884,7 @@ func (m *Map) appendFieldReferences(i int, kp *d2ast.KeyPath, refctx *RefContext
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f.References = append(f.References, FieldReference{
|
f.References = append(f.References, &FieldReference{
|
||||||
String: sb.Unbox(),
|
String: sb.Unbox(),
|
||||||
KeyPath: kp,
|
KeyPath: kp,
|
||||||
Context: refctx,
|
Context: refctx,
|
||||||
|
|
@ -945,3 +961,27 @@ func hasLayerKeywords(ida ...string) int {
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parentRef(n Node) Reference {
|
||||||
|
f := ParentField(n)
|
||||||
|
if f != nil {
|
||||||
|
return f.LastRef()
|
||||||
|
}
|
||||||
|
e := ParentEdge(n)
|
||||||
|
if e != nil {
|
||||||
|
return e.LastRef()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parentPrimaryKey(n Node) *d2ast.Key {
|
||||||
|
f := ParentField(n)
|
||||||
|
if f != nil {
|
||||||
|
return f.LastPrimaryKey()
|
||||||
|
}
|
||||||
|
e := ParentEdge(n)
|
||||||
|
if e != nil {
|
||||||
|
return e.LastPrimaryKey()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,10 @@ func TestCopy(t *testing.T) {
|
||||||
Composite: a,
|
Composite: a,
|
||||||
}
|
}
|
||||||
e := &d2ir.Edge{
|
e := &d2ir.Edge{
|
||||||
|
|
||||||
Primary_: s,
|
Primary_: s,
|
||||||
Map_: m2,
|
Map_: m2,
|
||||||
}
|
}
|
||||||
m := &d2ir.Map{
|
m := &d2ir.Map{
|
||||||
|
|
||||||
Fields: []*d2ir.Field{f},
|
Fields: []*d2ir.Field{f},
|
||||||
Edges: []*d2ir.Edge{e},
|
Edges: []*d2ir.Edge{e},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue