diff --git a/d2ir/compile.go b/d2ir/compile.go index ba3744d3f..fa84c49f6 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -43,18 +43,22 @@ func (c *compiler) compileMap(dst *Map, ast *d2ast.Map) { for _, n := range ast.Nodes { switch { case n.MapKey != nil: - c.compileKey(dst, n.MapKey) + c.compileKey(dst, &RefContext{ + Key: n.MapKey, + Scope: ast, + }) case n.Substitution != nil: panic("TODO") } } } -func (c *compiler) compileKey(dst *Map, k *d2ast.Key) { - if len(k.Edges) == 0 { - c.compileField(dst, k) +func (c *compiler) compileKey(dst *Map, refctx *RefContext) { + if len(refctx.Key.Edges) == 0 { + c.compileField(dst, refctx.Key) + dst.appendFieldReferences(0, refctx.Key.Key, refctx) } else { - c.compileEdges(dst, k) + c.compileEdges(dst, refctx) } } @@ -78,15 +82,14 @@ func (c *compiler) compileField(dst *Map, k *d2ast.Key) { c.compileArray(a, k.Value.Array) f.Composite = a } else if k.Value.Map != nil { - if f_m, ok := f.Composite.(*Map); ok { - c.compileMap(f_m, k.Value.Map) - } else { - m := &Map{ + f_m := ToMap(f) + if f_m == nil { + f_m = &Map{ parent: f, } - c.compileMap(m, k.Value.Map) - f.Composite = m + f.Composite = f_m } + c.compileMap(f_m, k.Value.Map) } else if k.Value.ScalarBox().Unbox() != nil { f.Primary = &Scalar{ parent: f, @@ -95,79 +98,88 @@ func (c *compiler) compileField(dst *Map, k *d2ast.Key) { } } -func (c *compiler) compileEdges(dst *Map, k *d2ast.Key) { - if k.Key != nil && len(k.Key.Path) > 0 { - f, err := dst.EnsureField(d2format.KeyPath(k.Key)) +func (c *compiler) compileEdges(dst *Map, refctx *RefContext) { + if refctx.Key.Key != nil && len(refctx.Key.Key.Path) > 0 { + f, err := dst.EnsureField(d2format.KeyPath(refctx.Key.Key)) if err != nil { - c.errorf(k, err.Error()) + c.errorf(refctx.Key.Key, err.Error()) return } - if f_m, ok := f.Composite.(*Map); ok { - dst = f_m - } else { - m := &Map{ + dst.appendFieldReferences(0, refctx.Key.Key, refctx) + if _, ok := f.Composite.(*Array); ok { + c.errorf(refctx.Key.Key, "cannot index into array") + return + } + f_m := ToMap(f) + if f_m == nil { + f_m = &Map{ parent: f, } - f.Composite = m - dst = m + f.Composite = f_m } + dst = f_m } - eida := NewEdgeIDs(k) + eida := NewEdgeIDs(refctx.Key) for i, eid := range eida { var e *Edge if eid.Index != nil { ea := dst.GetEdges(eid) if len(ea) == 0 { - c.errorf(k.Edges[i], "indexed edge does not exist") + c.errorf(refctx.Key.Edges[i], "indexed edge does not exist") continue } e = ea[0] } else { _, err := dst.EnsureField(eid.SrcPath) if err != nil { - c.errorf(k.Edges[i].Src, err.Error()) + c.errorf(refctx.Key.Edges[i].Src, err.Error()) continue } _, err = dst.EnsureField(eid.DstPath) if err != nil { - c.errorf(k.Edges[i].Dst, err.Error()) + c.errorf(refctx.Key.Edges[i].Dst, err.Error()) continue } e, err = dst.EnsureEdge(eid) if err != nil { - c.errorf(k.Edges[i], err.Error()) + c.errorf(refctx.Key.Edges[i], err.Error()) continue } } - if k.EdgeKey != nil { + refctx = refctx.Copy() + refctx.Edge = refctx.Key.Edges[i] + dst.appendEdgeReferences(e, refctx) + + if refctx.Key.EdgeKey != nil { if e.Map == nil { e.Map = &Map{ parent: e, } } tmpk := &d2ast.Key{ - Range: k.EdgeKey.Range, - Key: k.EdgeKey, + Range: refctx.Key.EdgeKey.Range, + Key: refctx.Key.EdgeKey, } c.compileField(e.Map, tmpk) + e.Map.appendFieldReferences(0, refctx.Key.EdgeKey, refctx) } else { - if k.Primary.Unbox() != nil { + if refctx.Key.Primary.Unbox() != nil { e.Primary = &Scalar{ parent: e, - Value: k.Primary.Unbox(), + Value: refctx.Key.Primary.Unbox(), } - } else if k.Value.Map != nil { + } else if refctx.Key.Value.Map != nil { if e.Map == nil { e.Map = &Map{ parent: e, } } - c.compileMap(e.Map, k.Value.Map) - } else if k.Value.Unbox() != nil { - c.errorf(k.Value.Unbox(), "edges cannot be assigned arrays") + c.compileMap(e.Map, refctx.Key.Value.Map) + } else if refctx.Key.Value.Unbox() != nil { + c.errorf(refctx.Key.Value.Unbox(), "edges cannot be assigned arrays") continue } } diff --git a/d2ir/d2ir.go b/d2ir/d2ir.go index 66a566acd..b3983548d 100644 --- a/d2ir/d2ir.go +++ b/d2ir/d2ir.go @@ -338,7 +338,7 @@ func (kr FieldReference) EdgeDest() bool { } func (kr FieldReference) InEdge() bool { - return kr.KeyPath != kr.Context.Key.Key + return kr.Context.Edge != nil } type EdgeReference struct { @@ -351,6 +351,11 @@ type RefContext struct { Scope *d2ast.Map } +func (rc *RefContext) Copy() *RefContext { + tmp := *rc + return &tmp +} + // UnresolvedScopeMap is scope prior to interpreting _ // It does this by finding the referenced *Map of rc.Scope func (rc *RefContext) UnresolvedScopeMap(m *Map) *Map { diff --git a/testdata/d2ir/TestCompile/edge/nested.exp.json b/testdata/d2ir/TestCompile/edge/nested.exp.json index 171f32700..e3ae5deca 100644 --- a/testdata/d2ir/TestCompile/edge/nested.exp.json +++ b/testdata/d2ir/TestCompile/edge/nested.exp.json @@ -79,22 +79,190 @@ "composite": { "fields": [ { - "name": "y" + "name": "y", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/nested.d2,0:0:0-0:4:4", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + } + } + ] } ], "edges": null - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/nested.d2,0:0:0-0:4:4", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + } + } + ] }, { "name": "z", "composite": { "fields": [ { - "name": "p" + "name": "p", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:9:9-0:10:10", + "value": [ + { + "string": "p", + "raw_string": "p" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/nested.d2,0:6:6-0:10:10", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:7:7-0:8:8", + "value": [ + { + "string": "z", + "raw_string": "z" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:9:9-0:10:10", + "value": [ + { + "string": "p", + "raw_string": "p" + } + ] + } + } + ] + } + } + ] } ], "edges": null - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:7:7-0:8:8", + "value": [ + { + "string": "z", + "raw_string": "z" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/nested.d2,0:6:6-0:10:10", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:7:7-0:8:8", + "value": [ + { + "string": "z", + "raw_string": "z" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/edge/nested.d2,0:9:9-0:10:10", + "value": [ + { + "string": "p", + "raw_string": "p" + } + ] + } + } + ] + } + } + ] } ], "edges": [ @@ -111,7 +279,10 @@ ], "dst_arrow": true, "index": 0 - } + }, + "references": [ + {} + ] } ] } diff --git a/testdata/d2ir/TestCompile/edge/root.exp.json b/testdata/d2ir/TestCompile/edge/root.exp.json index 110559953..2e9d3451b 100644 --- a/testdata/d2ir/TestCompile/edge/root.exp.json +++ b/testdata/d2ir/TestCompile/edge/root.exp.json @@ -53,10 +53,72 @@ "base": { "fields": [ { - "name": "x" + "name": "x", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/root.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/root.d2,0:0:0-0:2:2", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/root.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + } + } + ] }, { - "name": "y" + "name": "y", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/root.d2,0:5:5-0:6:6", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/root.d2,0:4:4-0:6:6", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/root.d2,0:5:5-0:6:6", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + } + } + ] } ], "edges": [ @@ -71,7 +133,10 @@ ], "dst_arrow": true, "index": 0 - } + }, + "references": [ + {} + ] } ] } diff --git a/testdata/d2ir/TestCompile/edge/underscore.exp.json b/testdata/d2ir/TestCompile/edge/underscore.exp.json index a1076d021..720a7ec8d 100644 --- a/testdata/d2ir/TestCompile/edge/underscore.exp.json +++ b/testdata/d2ir/TestCompile/edge/underscore.exp.json @@ -97,11 +97,73 @@ "composite": { "fields": [ { - "name": "z" + "name": "z", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/underscore.d2,0:12:12-0:13:13", + "value": [ + { + "string": "z", + "raw_string": "z" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/underscore.d2,0:11:11-0:14:14", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/underscore.d2,0:12:12-0:13:13", + "value": [ + { + "string": "z", + "raw_string": "z" + } + ] + } + } + ] + } + } + ] } ], "edges": null - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/edge/underscore.d2,0:0:0-0:1:1", + "value": [ + { + "string": "p", + "raw_string": "p" + } + ] + } + }, + "key_path": { + "range": "TestCompile/edge/underscore.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/edge/underscore.d2,0:0:0-0:1:1", + "value": [ + { + "string": "p", + "raw_string": "p" + } + ] + } + } + ] + } + } + ] }, { "name": "x" @@ -120,7 +182,10 @@ ], "dst_arrow": true, "index": 0 - } + }, + "references": [ + {} + ] } ] } diff --git a/testdata/d2ir/TestCompile/field/array.exp.json b/testdata/d2ir/TestCompile/field/array.exp.json index cd5a6697e..99972608e 100644 --- a/testdata/d2ir/TestCompile/field/array.exp.json +++ b/testdata/d2ir/TestCompile/field/array.exp.json @@ -96,7 +96,38 @@ } } ] - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/array.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/array.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/array.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + } + } + ] } ], "edges": null diff --git a/testdata/d2ir/TestCompile/field/label.exp.json b/testdata/d2ir/TestCompile/field/label.exp.json index 86d9d7079..f7e0f8f67 100644 --- a/testdata/d2ir/TestCompile/field/label.exp.json +++ b/testdata/d2ir/TestCompile/field/label.exp.json @@ -51,7 +51,38 @@ } ] } - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/label.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/label.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/label.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + } + } + ] } ], "edges": null diff --git a/testdata/d2ir/TestCompile/field/nested.exp.json b/testdata/d2ir/TestCompile/field/nested.exp.json index 3c77060e2..68cced08d 100644 --- a/testdata/d2ir/TestCompile/field/nested.exp.json +++ b/testdata/d2ir/TestCompile/field/nested.exp.json @@ -66,11 +66,95 @@ } ] } - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/nested.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/field/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + } + } + ] } ], "edges": null - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/nested.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/field/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + } + } + ] } ], "edges": null diff --git a/testdata/d2ir/TestCompile/field/primary/nested.exp.json b/testdata/d2ir/TestCompile/field/primary/nested.exp.json index 870609c5d..c3237d7d9 100644 --- a/testdata/d2ir/TestCompile/field/primary/nested.exp.json +++ b/testdata/d2ir/TestCompile/field/primary/nested.exp.json @@ -99,15 +99,130 @@ "composite": { "fields": [ { - "name": "pqrs" + "name": "pqrs", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:11:11-0:15:15", + "value": [ + { + "string": "pqrs", + "raw_string": "pqrs" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/primary/nested.d2,0:11:11-0:16:16", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:11:11-0:15:15", + "value": [ + { + "string": "pqrs", + "raw_string": "pqrs" + } + ] + } + } + ] + } + } + ] } ], "edges": null - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/primary/nested.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + } + } + ] } ], "edges": null - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/primary/nested.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "TestCompile/field/primary/nested.d2,0:2:2-0:3:3", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + } + } + ] } ], "edges": null diff --git a/testdata/d2ir/TestCompile/field/primary/root.exp.json b/testdata/d2ir/TestCompile/field/primary/root.exp.json index 69c46b633..86a8ee87a 100644 --- a/testdata/d2ir/TestCompile/field/primary/root.exp.json +++ b/testdata/d2ir/TestCompile/field/primary/root.exp.json @@ -84,11 +84,73 @@ "composite": { "fields": [ { - "name": "pqrs" + "name": "pqrs", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/primary/root.d2,0:9:9-0:13:13", + "value": [ + { + "string": "pqrs", + "raw_string": "pqrs" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/primary/root.d2,0:9:9-0:14:14", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/primary/root.d2,0:9:9-0:13:13", + "value": [ + { + "string": "pqrs", + "raw_string": "pqrs" + } + ] + } + } + ] + } + } + ] } ], "edges": null - } + }, + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/primary/root.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/primary/root.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/primary/root.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + } + } + ] } ], "edges": null diff --git a/testdata/d2ir/TestCompile/field/root.exp.json b/testdata/d2ir/TestCompile/field/root.exp.json index c4ef7e3f4..bed994d89 100644 --- a/testdata/d2ir/TestCompile/field/root.exp.json +++ b/testdata/d2ir/TestCompile/field/root.exp.json @@ -30,7 +30,38 @@ "base": { "fields": [ { - "name": "x" + "name": "x", + "references": [ + { + "string": { + "unquoted_string": { + "range": "TestCompile/field/root.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + "key_path": { + "range": "TestCompile/field/root.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/field/root.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + } + } + ] } ], "edges": null