edge label working

This commit is contained in:
Alexander Wang 2023-07-10 21:18:18 -07:00
parent c9793b9a87
commit 05802edb07
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
6 changed files with 667 additions and 48 deletions

View file

@ -1,7 +1,6 @@
package d2compiler
import (
"encoding/json"
"encoding/xml"
"fmt"
"io"
@ -65,8 +64,6 @@ func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) {
g := d2graph.NewGraph()
g.AST = ast
c.compileBoard(g, m)
b, _ := json.MarshalIndent(m, "", " ")
println("\033[1;31m--- DEBUG:", string(b), "\033[m")
if len(c.err.Errors) > 0 {
return nil, c.err
}

View file

@ -3193,6 +3193,69 @@ hi: ${x}
assert.Equal(t, "im a var", g.Objects[0].Label.Value)
},
},
{
// TODO: text before/after substitutions
name: "combined",
skip: true,
run: func(t *testing.T) {
g := assertCompile(t, `
vars: {
x: im a var
}
hi: 1 ${x} 2
`, "")
assert.Equal(t, "1 im a var 2", g.Objects[0].Label.Value)
},
},
{
name: "edge label",
run: func(t *testing.T) {
g := assertCompile(t, `
vars: {
x: im a var
}
a -> b: ${x}
`, "")
assert.Equal(t, 1, len(g.Edges))
assert.Equal(t, "im a var", g.Edges[0].Label.Value)
},
},
}
for _, tc := range tca {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if tc.skip {
t.SkipNow()
}
tc.run(t)
})
}
})
t.Run("override", func(t *testing.T) {
t.Parallel()
tca := []struct {
name string
skip bool
run func(t *testing.T)
}{
{
name: "label",
run: func(t *testing.T) {
g := assertCompile(t, `
vars: {
x: im a var
}
hi: ${x}
hi: not a var
`, "")
assert.Equal(t, 1, len(g.Objects))
assert.Equal(t, "not a var", g.Objects[0].Label.Value)
},
},
}
for _, tc := range tca {

View file

@ -52,16 +52,15 @@ func Compile(ast *d2ast.Map, opts *CompileOptions) (*Map, error) {
defer c.popImportStack()
c.compileMap(m, ast, ast)
c.compileClasses(m)
c.compileVars(m)
c.compileSubstitutions(m)
c.overlayClasses(m)
c.overlayVars(m)
if !c.err.Empty() {
return nil, c.err
}
return m, nil
}
func (c *compiler) compileClasses(m *Map) {
func (c *compiler) overlayClasses(m *Map) {
classes := m.GetField("classes")
if classes == nil || classes.Map() == nil {
return
@ -94,49 +93,49 @@ func (c *compiler) compileClasses(m *Map) {
l.Fields = append(l.Fields, base)
}
c.compileClasses(l)
c.overlayClasses(l)
}
}
func (c *compiler) compileSubstitutions(m *Map) {
vars := m.GetField("vars")
for _, f := range m.Fields {
// No substitutions within vars itself
if f.Name == "vars" {
continue
func (c *compiler) resolveSubstitution(vars *Map, mk *d2ast.Key, substitution *d2ast.Substitution) d2ast.Scalar {
var resolved *Field
for _, p := range substitution.Path {
if vars == nil {
resolved = nil
break
}
for _, ref := range f.References {
if ref.Context.Key != nil && ref.Context.Key.Value.Substitution != nil {
var resolved *Field
m := vars
for _, p := range ref.Context.Key.Value.Substitution.Path {
r := m.Map().GetField(p.Unbox().ScalarString())
if r == nil {
resolved = nil
break
}
m = r
resolved = r
}
if resolved == nil {
c.errorf(ref.Context.Key, "could not resolve variable %s", strings.Join(ref.Context.Key.Value.Substitution.IDA(), "."))
} else {
// TODO do i need this
// ref.Context.Key.Value = d2ast.MakeValueBox(resolved.Primary().Value)
r := vars.GetField(p.Unbox().ScalarString())
if r == nil {
resolved = nil
break
}
vars = r.Map()
resolved = r
}
if resolved == nil {
c.errorf(mk, "could not resolve variable %s", strings.Join(substitution.IDA(), "."))
} else {
// TODO maps
return resolved.Primary().Value
}
return nil
}
// TODO maps
f.Primary_ = &Scalar{
parent: f,
Value: resolved.Primary().Value,
}
}
ref.Context.Key.Value.Substitution = nil
}
func (c *compiler) compileVars(m *Map, ast *d2ast.Map) {
for _, n := range ast.Nodes {
if n.MapKey != nil && n.MapKey.Key != nil && len(n.MapKey.Key.Path) == 1 && strings.EqualFold(n.MapKey.Key.Path[0].Unbox().ScalarString(), "vars") {
c.compileKey(&RefContext{
Key: n.MapKey,
Scope: ast,
ScopeMap: m,
ScopeAST: ast,
})
break
}
}
}
func (c *compiler) compileVars(m *Map) {
func (c *compiler) overlayVars(m *Map) {
vars := m.GetField("vars")
if vars == nil || vars.Map() == nil {
return
@ -169,7 +168,7 @@ func (c *compiler) compileVars(m *Map) {
l.Fields = append(l.Fields, base)
}
c.compileVars(l)
c.overlayVars(l)
}
}
@ -184,6 +183,10 @@ func (c *compiler) overlay(base *Map, f *Field) {
}
func (c *compiler) compileMap(dst *Map, ast, scopeAST *d2ast.Map) {
// When compiling a new board, compile vars before all else, as it might be referenced
if NodeBoardKind(dst) != "" {
c.compileVars(dst, ast)
}
for _, n := range ast.Nodes {
switch {
case n.MapKey != nil:
@ -279,7 +282,7 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext)
c.compileMap(f.Map(), refctx.Key.Value.Map, scopeAST)
switch NodeBoardKind(f) {
case BoardScenario, BoardStep:
c.compileClasses(f.Map())
c.overlayClasses(f.Map())
}
} else if refctx.Key.Value.Import != nil {
n, ok := c._import(refctx.Key.Value.Import)
@ -318,13 +321,18 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext)
c.updateLinks(f.Map())
switch NodeBoardKind(f) {
case BoardScenario, BoardStep:
c.compileClasses(f.Map())
c.overlayClasses(f.Map())
}
}
} else if refctx.Key.Value.Substitution != nil {
// b, _ := json.MarshalIndent(refctx.Key.Value.Substitution.IDA(), "", " ")
// println("\033[1;31m--- DEBUG:", string(b), "\033[m")
// println("\033[1;31m--- DEBUG:", "=======what===============", "\033[m")
vars := ParentBoard(f).Map().GetField("vars")
resolved := c.resolveSubstitution(vars.Map(), refctx.Key, refctx.Key.Value.Substitution)
if resolved != nil {
f.Primary_ = &Scalar{
parent: f,
Value: resolved,
}
}
} else if refctx.Key.Value.ScalarBox().Unbox() != nil {
// If the link is a board, we need to transform it into an absolute path.
if f.Name == "link" {
@ -502,6 +510,15 @@ func (c *compiler) compileEdges(refctx *RefContext) {
}
}
c.compileMap(e.Map_, refctx.Key.Value.Map, refctx.ScopeAST)
} else if refctx.Key.Value.Substitution != nil {
vars := ParentBoard(e).Map().GetField("vars")
resolved := c.resolveSubstitution(vars.Map(), refctx.Key, refctx.Key.Value.Substitution)
if resolved != nil {
e.Primary_ = &Scalar{
parent: e,
Value: resolved,
}
}
} else if refctx.Key.Value.ScalarBox().Unbox() != nil {
e.Primary_ = &Scalar{
parent: e,

View file

@ -0,0 +1,285 @@
{
"graph": {
"name": "",
"isFolderOnly": false,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,0:0:0-5:0:38",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,1:0:1-3:1:24",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,1:0:1-1:4:5",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,1:0:1-1:4:5",
"value": [
{
"string": "vars",
"raw_string": "vars"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,1:6:7-3:1:24",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,2:2:11-2:13:22",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,2:2:11-2:3:12",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,2:2:11-2:3:12",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,2:5:14-2:13:22",
"value": [
{
"string": "im a var",
"raw_string": "im a var"
}
]
}
}
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:0:25-4:12:37",
"edges": [
{
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:0:25-4:6:31",
"src": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:0:25-4:1:26",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:0:25-4:1:26",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"src_arrow": "",
"dst": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:5:30-4:6:31",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:5:30-4:6:31",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"dst_arrow": ">"
}
],
"primary": {},
"value": {
"substitution": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:8:33-4:12:37",
"spread": false,
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:10:35-4:11:36",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
}
}
}
}
]
},
"root": {
"id": "",
"id_val": "",
"attributes": {
"label": {
"value": ""
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": ""
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
"edges": [
{
"index": 0,
"isCurve": false,
"src_arrow": false,
"dst_arrow": true,
"references": [
{
"map_key_edge_index": 0
}
],
"attributes": {
"label": {
"value": "im a var"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": ""
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
],
"objects": [
{
"id": "a",
"id_val": "a",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:0:25-4:1:26",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:0:25-4:1:26",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
}
],
"attributes": {
"label": {
"value": "a"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "b",
"id_val": "b",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:5:30-4:6:31",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/edge_label.d2,4:5:30-4:6:31",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": 0
}
],
"attributes": {
"label": {
"value": "b"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
]
},
"err": null
}

View file

@ -87,7 +87,25 @@
]
},
"primary": {},
"value": {}
"value": {
"substitution": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,4:4:29-4:8:33",
"spread": false,
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/label.d2,4:6:31-4:7:32",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
}
}
}
}
]

View file

@ -0,0 +1,239 @@
{
"graph": {
"name": "",
"isFolderOnly": false,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,0:0:0-6:0:48",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,1:0:1-3:1:24",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,1:0:1-1:4:5",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,1:0:1-1:4:5",
"value": [
{
"string": "vars",
"raw_string": "vars"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,1:6:7-3:1:24",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,2:2:11-2:13:22",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,2:2:11-2:3:12",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,2:2:11-2:3:12",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,2:5:14-2:13:22",
"value": [
{
"string": "im a var",
"raw_string": "im a var"
}
]
}
}
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,4:0:25-4:8:33",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,4:0:25-4:2:27",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,4:0:25-4:2:27",
"value": [
{
"string": "hi",
"raw_string": "hi"
}
]
}
}
]
},
"primary": {},
"value": {
"substitution": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,4:4:29-4:8:33",
"spread": false,
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,4:6:31-4:7:32",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,5:0:34-5:13:47",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,5:0:34-5:2:36",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,5:0:34-5:2:36",
"value": [
{
"string": "hi",
"raw_string": "hi"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,5:4:38-5:13:47",
"value": [
{
"string": "not a var",
"raw_string": "not a var"
}
]
}
}
}
}
]
},
"root": {
"id": "",
"id_val": "",
"attributes": {
"label": {
"value": ""
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": ""
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
"edges": null,
"objects": [
{
"id": "hi",
"id_val": "hi",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,4:0:25-4:2:27",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,4:0:25-4:2:27",
"value": [
{
"string": "hi",
"raw_string": "hi"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
},
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,5:0:34-5:2:36",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/override/label.d2,5:0:34-5:2:36",
"value": [
{
"string": "hi",
"raw_string": "hi"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "not a var"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
]
},
"err": null
}