d2/d2ir/compile.go

208 lines
4.2 KiB
Go
Raw Normal View History

2023-01-16 11:52:37 +00:00
package d2ir
import (
"oss.terrastruct.com/d2/d2ast"
"oss.terrastruct.com/d2/d2parser"
)
type compiler struct {
err d2parser.ParseError
}
func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
2023-01-18 10:06:44 +00:00
c.err.Errors = append(c.err.Errors, d2parser.Errorf(n, f, v...).(d2ast.Error))
2023-01-16 11:52:37 +00:00
}
2023-01-18 10:06:44 +00:00
func Compile(ast *d2ast.Map) (*Layer, error) {
l := &Layer{
2023-01-18 01:39:31 +00:00
AST: ast,
2023-01-18 10:08:41 +00:00
}
l.Map = &Map{
parent: l,
2023-01-18 01:39:31 +00:00
}
c := &compiler{}
2023-01-18 10:06:44 +00:00
c.compile(l)
2023-01-16 11:52:37 +00:00
if !c.err.Empty() {
2023-01-18 01:39:31 +00:00
return nil, c.err
2023-01-16 11:52:37 +00:00
}
2023-01-18 10:06:44 +00:00
return l, nil
2023-01-18 01:39:31 +00:00
}
2023-01-18 10:06:44 +00:00
func (c *compiler) compile(l *Layer) {
c.compileMap(l.Map, l.AST)
2023-01-16 11:52:37 +00:00
}
func (c *compiler) compileMap(dst *Map, ast *d2ast.Map) {
for _, n := range ast.Nodes {
switch {
case n.MapKey != nil:
2023-01-18 05:28:33 +00:00
c.compileKey(dst, &RefContext{
Key: n.MapKey,
Scope: ast,
})
2023-01-16 11:52:37 +00:00
case n.Substitution != nil:
panic("TODO")
}
}
}
2023-01-18 05:28:33 +00:00
func (c *compiler) compileKey(dst *Map, refctx *RefContext) {
if len(refctx.Key.Edges) == 0 {
2023-01-18 10:06:44 +00:00
c.compileField(dst, refctx.Key.Key, refctx)
2023-01-16 11:52:37 +00:00
} else {
2023-01-18 05:28:33 +00:00
c.compileEdges(dst, refctx)
2023-01-16 11:52:37 +00:00
}
}
2023-01-18 10:06:44 +00:00
func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext) {
f, err := dst.EnsureField(kp, refctx)
2023-01-16 11:52:37 +00:00
if err != nil {
2023-01-18 10:06:44 +00:00
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
2023-01-16 11:52:37 +00:00
return
}
2023-01-18 10:06:44 +00:00
if refctx.Key.Primary.Unbox() != nil {
2023-01-16 11:52:37 +00:00
f.Primary = &Scalar{
parent: f,
2023-01-18 10:06:44 +00:00
Value: refctx.Key.Primary.Unbox(),
2023-01-16 11:52:37 +00:00
}
}
2023-01-18 10:06:44 +00:00
if refctx.Key.Value.Array != nil {
2023-01-16 11:52:37 +00:00
a := &Array{
parent: f,
}
2023-01-18 10:06:44 +00:00
c.compileArray(a, refctx.Key.Value.Array)
2023-01-16 11:52:37 +00:00
f.Composite = a
2023-01-18 10:06:44 +00:00
} else if refctx.Key.Value.Map != nil {
2023-01-18 05:28:33 +00:00
f_m := ToMap(f)
if f_m == nil {
f_m = &Map{
2023-01-16 11:52:37 +00:00
parent: f,
}
2023-01-18 05:28:33 +00:00
f.Composite = f_m
2023-01-16 11:52:37 +00:00
}
2023-01-18 10:06:44 +00:00
c.compileMap(f_m, refctx.Key.Value.Map)
} else if refctx.Key.Value.ScalarBox().Unbox() != nil {
2023-01-16 11:52:37 +00:00
f.Primary = &Scalar{
parent: f,
2023-01-18 10:06:44 +00:00
Value: refctx.Key.Value.ScalarBox().Unbox(),
2023-01-16 11:52:37 +00:00
}
}
}
2023-01-18 05:28:33 +00:00
func (c *compiler) compileEdges(dst *Map, refctx *RefContext) {
2023-01-18 10:06:44 +00:00
if refctx.Key.Key != nil {
f, err := dst.EnsureField(refctx.Key.Key, refctx)
2023-01-16 11:52:37 +00:00
if err != nil {
2023-01-18 10:06:44 +00:00
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
2023-01-16 11:52:37 +00:00
return
}
2023-01-18 05:28:33 +00:00
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{
2023-01-16 11:52:37 +00:00
parent: f,
}
2023-01-18 05:28:33 +00:00
f.Composite = f_m
2023-01-16 11:52:37 +00:00
}
2023-01-18 05:28:33 +00:00
dst = f_m
2023-01-16 11:52:37 +00:00
}
2023-01-18 05:28:33 +00:00
eida := NewEdgeIDs(refctx.Key)
2023-01-16 11:52:37 +00:00
for i, eid := range eida {
2023-01-18 10:06:44 +00:00
refctx = refctx.Copy()
refctx.Edge = refctx.Key.Edges[i]
2023-01-16 11:52:37 +00:00
var e *Edge
if eid.Index != nil {
ea := dst.GetEdges(eid)
if len(ea) == 0 {
2023-01-18 10:06:44 +00:00
c.errorf(refctx.Edge, "indexed edge does not exist")
2023-01-16 11:52:37 +00:00
continue
}
e = ea[0]
2023-01-18 10:06:44 +00:00
e.References = append(e.References, EdgeReference{
Context: refctx,
})
dst.appendFieldReferences(0, refctx.Edge.Src, refctx)
dst.appendFieldReferences(0, refctx.Edge.Dst, refctx)
2023-01-16 11:52:37 +00:00
} else {
2023-01-18 10:06:44 +00:00
_, err := dst.EnsureField(refctx.Edge.Src, refctx)
2023-01-17 12:44:14 +00:00
if err != nil {
2023-01-18 10:06:44 +00:00
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
2023-01-17 12:44:14 +00:00
continue
}
2023-01-18 10:06:44 +00:00
_, err = dst.EnsureField(refctx.Edge.Dst, refctx)
2023-01-17 12:44:14 +00:00
if err != nil {
2023-01-18 10:06:44 +00:00
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
2023-01-17 12:44:14 +00:00
continue
}
2023-01-18 10:06:44 +00:00
e, err = dst.CreateEdge(eid, refctx)
2023-01-16 11:52:37 +00:00
if err != nil {
2023-01-18 10:06:44 +00:00
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
2023-01-16 11:52:37 +00:00
continue
}
}
2023-01-18 05:28:33 +00:00
if refctx.Key.EdgeKey != nil {
2023-01-16 11:52:37 +00:00
if e.Map == nil {
e.Map = &Map{
parent: e,
}
}
2023-01-18 10:06:44 +00:00
c.compileField(e.Map, refctx.Key.EdgeKey, refctx)
2023-01-16 11:52:37 +00:00
} else {
2023-01-18 05:28:33 +00:00
if refctx.Key.Primary.Unbox() != nil {
2023-01-16 11:52:37 +00:00
e.Primary = &Scalar{
parent: e,
2023-01-18 05:28:33 +00:00
Value: refctx.Key.Primary.Unbox(),
2023-01-16 11:52:37 +00:00
}
2023-01-18 05:28:33 +00:00
} else if refctx.Key.Value.Map != nil {
2023-01-16 11:52:37 +00:00
if e.Map == nil {
e.Map = &Map{
parent: e,
}
}
2023-01-18 05:28:33 +00:00
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")
2023-01-16 11:52:37 +00:00
continue
}
}
}
}
func (c *compiler) compileArray(dst *Array, a *d2ast.Array) {
2023-01-16 12:48:45 +00:00
for _, an := range a.Nodes {
var irv Value
switch v := an.Unbox().(type) {
case *d2ast.Array:
ira := &Array{
parent: dst,
}
c.compileArray(ira, v)
irv = ira
case *d2ast.Map:
irm := &Map{
parent: dst,
}
c.compileMap(irm, v)
irv = irm
case d2ast.Scalar:
irv = &Scalar{
parent: dst,
Value: v,
}
2023-01-16 15:45:13 +00:00
case *d2ast.Substitution:
panic("TODO")
2023-01-16 12:48:45 +00:00
}
dst.Values = append(dst.Values, irv)
}
2023-01-16 11:52:37 +00:00
}