This commit is contained in:
Alexander Wang 2023-07-12 14:53:28 -07:00
parent 85bfad19a6
commit 4b7b636657
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
5 changed files with 1058 additions and 1 deletions

View file

@ -3392,6 +3392,25 @@ z: ${x}
assert.Equal(t, 1, len(g.Objects[1].Children))
},
},
{
name: "spread",
run: func(t *testing.T) {
g := assertCompile(t, `
vars: {
x: all {
a: b
b: c
}
}
z: {
...${x}
c
}
`, "")
assert.Equal(t, "z", g.Objects[1].ID)
assert.Equal(t, 3, len(g.Objects[1].Children))
},
},
}
for _, tc := range tca {
@ -3712,6 +3731,37 @@ hi
`, "d2/testdata/d2compiler/TestCompile2/vars/errors/edge.d2:3:3: vars cannot contain an edge")
},
},
{
name: "spread-non-map",
run: func(t *testing.T) {
assertCompile(t, `
vars: {
x: all
}
z: {
...${x}
c
}
`, `d2/testdata/d2compiler/TestCompile2/vars/errors/spread-non-map.d2:6:3: cannot spread non-map into map`)
},
},
{
name: "spread-non-solo",
// NOTE: this doesn't get parsed correctly and so the error message isn't exactly right, but the important thing is that it errors
run: func(t *testing.T) {
assertCompile(t, `
vars: {
x: {
a: b
}
}
z: {
d: ...${x}
c
}
`, `d2/testdata/d2compiler/TestCompile2/vars/errors/spread-non-solo.d2:8:2: cannot substitute map variable "x" as part of a string`)
},
},
}
for _, tc := range tca {

View file

@ -143,14 +143,33 @@ func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) {
c.errorf(node.LastRef().AST(), `could not resolve variable "%s"`, strings.Join(box.Substitution.IDA(), "."))
return
}
if box.Substitution.Spread {
if resolvedField.Composite == nil {
c.errorf(box.Substitution, "cannot spread non-map into map")
continue
}
// TODO arrays
if resolvedField.Map() != nil {
OverlayMap(ParentMap(node), resolvedField.Map())
}
// Remove the placeholder field
f := node.(*Field)
m := f.parent.(*Map)
for i, f2 := range m.Fields {
if f == f2 {
m.Fields = append(m.Fields[:i], m.Fields[i+1:]...)
break
}
}
}
if resolvedField.Primary() == nil {
if len(s.Value) > 1 {
c.errorf(node.LastRef().AST(), `cannot substitute map variable "%s" as part of a string`, strings.Join(box.Substitution.IDA(), "."))
return
}
} else {
// If lone and unquoted, replace with value of sub
if len(s.Value) == 1 {
// If lone and unquoted, replace with value of sub
node.Primary().Value = resolvedField.Primary().Value
} else {
s.Value[i].String = go2.Pointer(resolvedField.Primary().String())
@ -255,6 +274,21 @@ func (c *compiler) compileMap(dst *Map, ast, scopeAST *d2ast.Map) {
ScopeMap: dst,
ScopeAST: scopeAST,
})
case n.Substitution != nil:
if !n.Substitution.Spread {
c.errorf(n.Import, "invalid non-spread substitution in map")
continue
}
// placeholder field to be resolved at the end
f := &Field{
parent: dst,
Primary_: &Scalar{
Value: &d2ast.UnquotedString{
Value: []d2ast.InterpolationBox{{Substitution: n.Substitution}},
},
},
}
dst.Fields = append(dst.Fields, f)
case n.Import != nil:
impn, ok := c._import(n.Import)
if !ok {
@ -619,6 +653,7 @@ func (c *compiler) compileArray(dst *Array, a *d2ast.Array, scopeAST *d2ast.Map)
irv = n
}
case *d2ast.Substitution:
// TODO
// panic("TODO")
}

View file

@ -0,0 +1,469 @@
{
"graph": {
"name": "",
"isFolderOnly": false,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,0:0:0-11:0:62",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,1:0:1-6:1:40",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,1:0:1-1:4:5",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,1:0:1-1:4:5",
"value": [
{
"string": "vars",
"raw_string": "vars"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,1:6:7-6:1:40",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,2:1:10-5:3:38",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,2:1:10-2:2:11",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,2:1:10-2:2:11",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
},
"primary": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,2:4:13-2:7:16",
"value": [
{
"string": "all",
"raw_string": "all"
}
]
}
},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,2:8:17-5:3:38",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,3:2:21-3:6:25",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,3:2:21-3:3:22",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,3:2:21-3:3:22",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,3:5:24-3:6:25",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,4:4:30-4:8:34",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,4:4:30-4:5:31",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,4:4:30-4:5:31",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,4:7:33-4:8:34",
"value": [
{
"string": "c",
"raw_string": "c"
}
]
}
}
}
}
]
}
}
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,7:0:41-10:1:61",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,7:0:41-7:1:42",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,7:0:41-7:1:42",
"value": [
{
"string": "z",
"raw_string": "z"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,7:3:44-10:1:61",
"nodes": [
{
"substitution": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,8:2:48-8:9:55",
"spread": true,
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,8:7:53-8:8:54",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,9:2:58-9:3:59",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,9:2:58-9:3:59",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,9:2:58-9:3:59",
"value": [
{
"string": "c",
"raw_string": "c"
}
]
}
}
]
},
"primary": {},
"value": {}
}
}
]
}
}
}
}
]
},
"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": "a",
"id_val": "a",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,3:2:21-3:3:22",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,3:2:21-3:3:22",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "b"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "z",
"id_val": "z",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,7:0:41-7:1:42",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,7:0:41-7:1:42",
"value": [
{
"string": "z",
"raw_string": "z"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "z"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "c",
"id_val": "c",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,9:2:58-9:3:59",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,9:2:58-9:3:59",
"value": [
{
"string": "c",
"raw_string": "c"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "c"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "vars",
"id_val": "vars",
"attributes": {
"label": {
"value": "vars"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "x",
"id_val": "x",
"attributes": {
"label": {
"value": "x"
},
"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/spread.d2,4:4:30-4:5:31",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/spread.d2,4:4:30-4:5:31",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "c"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
]
},
"err": null
}

View file

@ -0,0 +1,492 @@
{
"graph": {
"name": "",
"isFolderOnly": false,
"ast": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,0:0:0-11:0:62",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,1:0:1-6:1:40",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,1:0:1-1:4:5",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,1:0:1-1:4:5",
"value": [
{
"string": "vars",
"raw_string": "vars"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,1:6:7-6:1:40",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,2:1:10-5:3:38",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,2:1:10-2:2:11",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,2:1:10-2:2:11",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
},
"primary": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,2:4:13-2:7:16",
"value": [
{
"string": "all",
"raw_string": "all"
}
]
}
},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,2:8:17-5:3:38",
"nodes": [
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,3:2:21-3:6:25",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,3:2:21-3:3:22",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,3:2:21-3:3:22",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,3:5:24-3:6:25",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,4:4:30-4:8:34",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,4:4:30-4:5:31",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,4:4:30-4:5:31",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"primary": {},
"value": {
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,4:7:33-4:8:34",
"value": [
{
"string": "c",
"raw_string": "c"
}
]
}
}
}
}
]
}
}
}
}
]
}
}
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,7:0:41-10:1:61",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,7:0:41-7:1:42",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,7:0:41-7:1:42",
"value": [
{
"string": "z",
"raw_string": "z"
}
]
}
}
]
},
"primary": {},
"value": {
"map": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,7:3:44-10:1:61",
"nodes": [
{
"substitution": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,8:2:48-8:9:55",
"spread": true,
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,8:7:53-8:8:54",
"value": [
{
"string": "x",
"raw_string": "x"
}
]
}
}
]
}
},
{
"map_key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,9:2:58-9:3:59",
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,9:2:58-9:3:59",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,9:2:58-9:3:59",
"value": [
{
"string": "c",
"raw_string": "c"
}
]
}
}
]
},
"primary": {},
"value": {}
}
}
]
}
}
}
}
]
},
"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": "z",
"id_val": "z",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,7:0:41-7:1:42",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,7:0:41-7:1:42",
"value": [
{
"string": "z",
"raw_string": "z"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "z"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "\"\"",
"id_val": "",
"attributes": {
"label": {
"value": "all"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "a",
"id_val": "a",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,3:2:21-3:3:22",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,3:2:21-3:3:22",
"value": [
{
"string": "a",
"raw_string": "a"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "b"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "vars",
"id_val": "vars",
"attributes": {
"label": {
"value": "vars"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "x",
"id_val": "x",
"attributes": {
"label": {
"value": "x"
},
"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/variadic.d2,4:4:30-4:5:31",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,4:4:30-4:5:31",
"value": [
{
"string": "b",
"raw_string": "b"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "c"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
},
{
"id": "c",
"id_val": "c",
"references": [
{
"key": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,9:2:58-9:3:59",
"path": [
{
"unquoted_string": {
"range": "d2/testdata/d2compiler/TestCompile2/vars/basic/variadic.d2,9:2:58-9:3:59",
"value": [
{
"string": "c",
"raw_string": "c"
}
]
}
}
]
},
"key_path_index": 0,
"map_key_edge_index": -1
}
],
"attributes": {
"label": {
"value": "c"
},
"labelDimensions": {
"width": 0,
"height": 0
},
"style": {},
"near_key": null,
"shape": {
"value": "rectangle"
},
"direction": {
"value": ""
},
"constraint": null
},
"zIndex": 0
}
]
},
"err": null
}

View file

@ -0,0 +1,11 @@
{
"graph": null,
"err": {
"errs": [
{
"range": "d2/testdata/d2compiler/TestCompile2/vars/errors/spread-non-map.d2,5:2:26-5:9:33",
"errmsg": "d2/testdata/d2compiler/TestCompile2/vars/errors/spread-non-map.d2:6:3: cannot spread non-map into map"
}
]
}
}