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

View file

@ -3193,6 +3193,69 @@ hi: ${x}
assert.Equal(t, "im a var", g.Objects[0].Label.Value) 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 { for _, tc := range tca {

View file

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