-- in.cue --
// A simple discriminated element
#AC: {
	k: "simple"
	d: #C
}

// A recursive discriminated element
#AS: {
	k: "complex"
	d: #S
}

#R: {
	a: #AC | #AS
}

// The structure of the recursive element
#S: {
	n: string
	r: [string]: #R
}

// The structure of the simple element
#C: {
	n: string
}

#sub: {
	$p=#p: #AS
	dict: [string]: _

	for rn, rd in $p.d.r if rd.a.k == "complex" {
		let subs = #sub & {#p: rd.a}
		for sn, sd in subs.dict {
			dict: "\(rn)_\(sn)": sd
		}
	}
	for rn, rd in $p.d.r if rd.a.k == "simple" {
		dict: "\(rn)": rd
	}
}

// Data
_test: {
	c1: #AC
	c1: d: {
		n: "c1"
	}


	s3: #AS
	s3: d: {
		n: "s3"
		r: r1: a:c1
	}

	s2: #AS
	s2: d: {
		n: "s2"
		r: {
			r1: a: c1
			r2: a: s3
		}
	}

	s1: #AS
	s1: d: {
		n: "s1"
		r: {
			r1: a: c1
			r2: a: s2
		}
	}
}

//  Test

out: #sub & {#p: _test.s1}
-- diff/todo/p3 --
Reordering
-- out/evalalpha/stats --
Leaks:  937
Freed:  0
Reused: 0
Allocs: 937
Retain: 0

Unifications: 389
Conjuncts:    1464
Disjuncts:    110

CloseIDElems: 16099
NumCloseIDs: 407
-- out/evalalpha --
(struct){
  #AC: (#struct){
    k: (string){ "simple" }
    d: ~(#C)
  }
  #AS: (#struct){
    k: (string){ "complex" }
    d: ~(#S)
  }
  #R: (#struct){
    a: (#struct){ |((#struct){
        k: (string){ "simple" }
        d: ~(#C)
      }, (#struct){
        k: (string){ "complex" }
        d: ~(#S)
      }) }
  }
  #S: (#struct){
    n: (string){ string }
    r: (#struct){
    }
  }
  #C: (#struct){
    n: (string){ string }
  }
  #sub: (#struct){
    #p: ~(#AS)
    dict: (#struct){
    }
    let subs#1multi = (〈3;#sub〉 & {
      #p: 〈2;rd〉.a
    })
  }
  _test: (struct){
    c1: (#struct){
      d: (#struct){
        n: (string){ "c1" }
      }
      k: (string){ "simple" }
    }
    s3: (#struct){
      d: (#struct){
        n: (string){ "s3" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              d: (#struct){
                n: (string){ "c1" }
              }
              k: (string){ "simple" }
            }
          }
        }
      }
      k: (string){ "complex" }
    }
    s2: (#struct){
      d: (#struct){
        n: (string){ "s2" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              d: (#struct){
                n: (string){ "c1" }
              }
              k: (string){ "simple" }
            }
          }
          r2: (#struct){
            a: (#struct){
              d: (#struct){
                n: (string){ "s3" }
                r: (#struct){
                  r1: (#struct){
                    a: (#struct){
                      d: (#struct){
                        n: (string){ "c1" }
                      }
                      k: (string){ "simple" }
                    }
                  }
                }
              }
              k: (string){ "complex" }
            }
          }
        }
      }
      k: (string){ "complex" }
    }
    s1: (#struct){
      d: (#struct){
        n: (string){ "s1" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              d: (#struct){
                n: (string){ "c1" }
              }
              k: (string){ "simple" }
            }
          }
          r2: (#struct){
            a: (#struct){
              d: (#struct){
                n: (string){ "s2" }
                r: (#struct){
                  r1: (#struct){
                    a: (#struct){
                      d: (#struct){
                        n: (string){ "c1" }
                      }
                      k: (string){ "simple" }
                    }
                  }
                  r2: (#struct){
                    a: (#struct){
                      d: (#struct){
                        n: (string){ "s3" }
                        r: (#struct){
                          r1: (#struct){
                            a: (#struct){
                              d: (#struct){
                                n: (string){ "c1" }
                              }
                              k: (string){ "simple" }
                            }
                          }
                        }
                      }
                      k: (string){ "complex" }
                    }
                  }
                }
              }
              k: (string){ "complex" }
            }
          }
        }
      }
      k: (string){ "complex" }
    }
  }
  out: (#struct){
    #p: (#struct){
      d: (#struct){
        n: (string){ "s1" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              d: (#struct){
                n: (string){ "c1" }
              }
              k: (string){ "simple" }
            }
          }
          r2: (#struct){
            a: (#struct){
              d: (#struct){
                n: (string){ "s2" }
                r: (#struct){
                  r1: (#struct){
                    a: (#struct){
                      d: (#struct){
                        n: (string){ "c1" }
                      }
                      k: (string){ "simple" }
                    }
                  }
                  r2: (#struct){
                    a: (#struct){
                      d: (#struct){
                        n: (string){ "s3" }
                        r: (#struct){
                          r1: (#struct){
                            a: (#struct){
                              d: (#struct){
                                n: (string){ "c1" }
                              }
                              k: (string){ "simple" }
                            }
                          }
                        }
                      }
                      k: (string){ "complex" }
                    }
                  }
                }
              }
              k: (string){ "complex" }
            }
          }
        }
      }
      k: (string){ "complex" }
    }
    dict: (#struct){
      r1: (#struct){
        a: (#struct){
          d: (#struct){
            n: (string){ "c1" }
          }
          k: (string){ "simple" }
        }
      }
      r2_r1: (#struct){
        a: (#struct){
          d: (#struct){
            n: (string){ "c1" }
          }
          k: (string){ "simple" }
        }
      }
      r2_r2_r1: (#struct){
        a: (#struct){
          d: (#struct){
            n: (string){ "c1" }
          }
          k: (string){ "simple" }
        }
      }
    }
    let subs#1multi = (〈3;#sub〉 & {
      #p: 〈2;rd〉.a
    })
  }
}
-- diff/-out/evalalpha/stats<==>+out/eval/stats --
diff old new
--- old
+++ new
@@ -1,9 +1,12 @@
-Leaks:  6
-Freed:  3232
-Reused: 3213
-Allocs: 25
-Retain: 26
-
-Unifications: 2588
-Conjuncts:    12056
-Disjuncts:    3258
+Leaks:  937
+Freed:  0
+Reused: 0
+Allocs: 937
+Retain: 0
+
+Unifications: 389
+Conjuncts:    1464
+Disjuncts:    110
+
+CloseIDElems: 16099
+NumCloseIDs: 407
-- diff/-out/evalalpha<==>+out/eval --
diff old new
--- old
+++ new
@@ -1,31 +1,19 @@
 (struct){
   #AC: (#struct){
     k: (string){ "simple" }
-    d: (#struct){
-      n: (string){ string }
-    }
+    d: ~(#C)
   }
   #AS: (#struct){
     k: (string){ "complex" }
-    d: (#struct){
-      n: (string){ string }
-      r: (#struct){
-      }
-    }
+    d: ~(#S)
   }
   #R: (#struct){
     a: (#struct){ |((#struct){
         k: (string){ "simple" }
-        d: (#struct){
-          n: (string){ string }
-        }
+        d: ~(#C)
       }, (#struct){
         k: (string){ "complex" }
-        d: (#struct){
-          n: (string){ string }
-          r: (#struct){
-          }
-        }
+        d: ~(#S)
       }) }
   }
   #S: (#struct){
@@ -37,14 +25,7 @@
     n: (string){ string }
   }
   #sub: (#struct){
-    #p: (#struct){
-      k: (string){ "complex" }
-      d: (#struct){
-        n: (string){ string }
-        r: (#struct){
-        }
-      }
-    }
+    #p: ~(#AS)
     dict: (#struct){
     }
     let subs#1multi = (〈3;#sub〉 & {
@@ -53,190 +34,190 @@
   }
   _test: (struct){
     c1: (#struct){
-      k: (string){ "simple" }
       d: (#struct){
         n: (string){ "c1" }
       }
+      k: (string){ "simple" }
     }
     s3: (#struct){
-      k: (string){ "complex" }
       d: (#struct){
         n: (string){ "s3" }
         r: (#struct){
           r1: (#struct){
             a: (#struct){
-              k: (string){ "simple" }
-              d: (#struct){
-                n: (string){ "c1" }
-              }
-            }
-          }
-        }
-      }
+              d: (#struct){
+                n: (string){ "c1" }
+              }
+              k: (string){ "simple" }
+            }
+          }
+        }
+      }
+      k: (string){ "complex" }
     }
     s2: (#struct){
-      k: (string){ "complex" }
       d: (#struct){
         n: (string){ "s2" }
         r: (#struct){
           r1: (#struct){
             a: (#struct){
-              k: (string){ "simple" }
-              d: (#struct){
-                n: (string){ "c1" }
-              }
-            }
-          }
-          r2: (#struct){
-            a: (#struct){
-              k: (string){ "complex" }
+              d: (#struct){
+                n: (string){ "c1" }
+              }
+              k: (string){ "simple" }
+            }
+          }
+          r2: (#struct){
+            a: (#struct){
               d: (#struct){
                 n: (string){ "s3" }
                 r: (#struct){
                   r1: (#struct){
                     a: (#struct){
-                      k: (string){ "simple" }
-                      d: (#struct){
-                        n: (string){ "c1" }
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
+                      d: (#struct){
+                        n: (string){ "c1" }
+                      }
+                      k: (string){ "simple" }
+                    }
+                  }
+                }
+              }
+              k: (string){ "complex" }
+            }
+          }
+        }
+      }
+      k: (string){ "complex" }
     }
     s1: (#struct){
-      k: (string){ "complex" }
-      d: (#struct){
-        n: (string){ "s1" }
-        r: (#struct){
-          r1: (#struct){
-            a: (#struct){
-              k: (string){ "simple" }
-              d: (#struct){
-                n: (string){ "c1" }
-              }
-            }
-          }
-          r2: (#struct){
-            a: (#struct){
-              k: (string){ "complex" }
-              d: (#struct){
-                n: (string){ "s2" }
-                r: (#struct){
-                  r1: (#struct){
-                    a: (#struct){
-                      k: (string){ "simple" }
-                      d: (#struct){
-                        n: (string){ "c1" }
-                      }
-                    }
-                  }
-                  r2: (#struct){
-                    a: (#struct){
-                      k: (string){ "complex" }
-                      d: (#struct){
-                        n: (string){ "s3" }
-                        r: (#struct){
-                          r1: (#struct){
-                            a: (#struct){
-                              k: (string){ "simple" }
-                              d: (#struct){
-                                n: (string){ "c1" }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
+      d: (#struct){
+        n: (string){ "s1" }
+        r: (#struct){
+          r1: (#struct){
+            a: (#struct){
+              d: (#struct){
+                n: (string){ "c1" }
+              }
+              k: (string){ "simple" }
+            }
+          }
+          r2: (#struct){
+            a: (#struct){
+              d: (#struct){
+                n: (string){ "s2" }
+                r: (#struct){
+                  r1: (#struct){
+                    a: (#struct){
+                      d: (#struct){
+                        n: (string){ "c1" }
+                      }
+                      k: (string){ "simple" }
+                    }
+                  }
+                  r2: (#struct){
+                    a: (#struct){
+                      d: (#struct){
+                        n: (string){ "s3" }
+                        r: (#struct){
+                          r1: (#struct){
+                            a: (#struct){
+                              d: (#struct){
+                                n: (string){ "c1" }
+                              }
+                              k: (string){ "simple" }
+                            }
+                          }
+                        }
+                      }
+                      k: (string){ "complex" }
+                    }
+                  }
+                }
+              }
+              k: (string){ "complex" }
+            }
+          }
+        }
+      }
+      k: (string){ "complex" }
     }
   }
   out: (#struct){
     #p: (#struct){
-      k: (string){ "complex" }
-      d: (#struct){
-        n: (string){ "s1" }
-        r: (#struct){
-          r1: (#struct){
-            a: (#struct){
-              k: (string){ "simple" }
-              d: (#struct){
-                n: (string){ "c1" }
-              }
-            }
-          }
-          r2: (#struct){
-            a: (#struct){
-              k: (string){ "complex" }
-              d: (#struct){
-                n: (string){ "s2" }
-                r: (#struct){
-                  r1: (#struct){
-                    a: (#struct){
-                      k: (string){ "simple" }
-                      d: (#struct){
-                        n: (string){ "c1" }
-                      }
-                    }
-                  }
-                  r2: (#struct){
-                    a: (#struct){
-                      k: (string){ "complex" }
-                      d: (#struct){
-                        n: (string){ "s3" }
-                        r: (#struct){
-                          r1: (#struct){
-                            a: (#struct){
-                              k: (string){ "simple" }
-                              d: (#struct){
-                                n: (string){ "c1" }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
+      d: (#struct){
+        n: (string){ "s1" }
+        r: (#struct){
+          r1: (#struct){
+            a: (#struct){
+              d: (#struct){
+                n: (string){ "c1" }
+              }
+              k: (string){ "simple" }
+            }
+          }
+          r2: (#struct){
+            a: (#struct){
+              d: (#struct){
+                n: (string){ "s2" }
+                r: (#struct){
+                  r1: (#struct){
+                    a: (#struct){
+                      d: (#struct){
+                        n: (string){ "c1" }
+                      }
+                      k: (string){ "simple" }
+                    }
+                  }
+                  r2: (#struct){
+                    a: (#struct){
+                      d: (#struct){
+                        n: (string){ "s3" }
+                        r: (#struct){
+                          r1: (#struct){
+                            a: (#struct){
+                              d: (#struct){
+                                n: (string){ "c1" }
+                              }
+                              k: (string){ "simple" }
+                            }
+                          }
+                        }
+                      }
+                      k: (string){ "complex" }
+                    }
+                  }
+                }
+              }
+              k: (string){ "complex" }
+            }
+          }
+        }
+      }
+      k: (string){ "complex" }
     }
     dict: (#struct){
       r1: (#struct){
         a: (#struct){
-          k: (string){ "simple" }
-          d: (#struct){
-            n: (string){ "c1" }
-          }
+          d: (#struct){
+            n: (string){ "c1" }
+          }
+          k: (string){ "simple" }
         }
       }
       r2_r1: (#struct){
         a: (#struct){
-          k: (string){ "simple" }
-          d: (#struct){
-            n: (string){ "c1" }
-          }
+          d: (#struct){
+            n: (string){ "c1" }
+          }
+          k: (string){ "simple" }
         }
       }
       r2_r2_r1: (#struct){
         a: (#struct){
-          k: (string){ "simple" }
-          d: (#struct){
-            n: (string){ "c1" }
-          }
+          d: (#struct){
+            n: (string){ "c1" }
+          }
+          k: (string){ "simple" }
         }
       }
     }
-- out/eval/stats --
Leaks:  6
Freed:  3232
Reused: 3213
Allocs: 25
Retain: 26

Unifications: 2588
Conjuncts:    12056
Disjuncts:    3258
-- out/eval --
(struct){
  #AC: (#struct){
    k: (string){ "simple" }
    d: (#struct){
      n: (string){ string }
    }
  }
  #AS: (#struct){
    k: (string){ "complex" }
    d: (#struct){
      n: (string){ string }
      r: (#struct){
      }
    }
  }
  #R: (#struct){
    a: (#struct){ |((#struct){
        k: (string){ "simple" }
        d: (#struct){
          n: (string){ string }
        }
      }, (#struct){
        k: (string){ "complex" }
        d: (#struct){
          n: (string){ string }
          r: (#struct){
          }
        }
      }) }
  }
  #S: (#struct){
    n: (string){ string }
    r: (#struct){
    }
  }
  #C: (#struct){
    n: (string){ string }
  }
  #sub: (#struct){
    #p: (#struct){
      k: (string){ "complex" }
      d: (#struct){
        n: (string){ string }
        r: (#struct){
        }
      }
    }
    dict: (#struct){
    }
    let subs#1multi = (〈3;#sub〉 & {
      #p: 〈2;rd〉.a
    })
  }
  _test: (struct){
    c1: (#struct){
      k: (string){ "simple" }
      d: (#struct){
        n: (string){ "c1" }
      }
    }
    s3: (#struct){
      k: (string){ "complex" }
      d: (#struct){
        n: (string){ "s3" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              k: (string){ "simple" }
              d: (#struct){
                n: (string){ "c1" }
              }
            }
          }
        }
      }
    }
    s2: (#struct){
      k: (string){ "complex" }
      d: (#struct){
        n: (string){ "s2" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              k: (string){ "simple" }
              d: (#struct){
                n: (string){ "c1" }
              }
            }
          }
          r2: (#struct){
            a: (#struct){
              k: (string){ "complex" }
              d: (#struct){
                n: (string){ "s3" }
                r: (#struct){
                  r1: (#struct){
                    a: (#struct){
                      k: (string){ "simple" }
                      d: (#struct){
                        n: (string){ "c1" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    s1: (#struct){
      k: (string){ "complex" }
      d: (#struct){
        n: (string){ "s1" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              k: (string){ "simple" }
              d: (#struct){
                n: (string){ "c1" }
              }
            }
          }
          r2: (#struct){
            a: (#struct){
              k: (string){ "complex" }
              d: (#struct){
                n: (string){ "s2" }
                r: (#struct){
                  r1: (#struct){
                    a: (#struct){
                      k: (string){ "simple" }
                      d: (#struct){
                        n: (string){ "c1" }
                      }
                    }
                  }
                  r2: (#struct){
                    a: (#struct){
                      k: (string){ "complex" }
                      d: (#struct){
                        n: (string){ "s3" }
                        r: (#struct){
                          r1: (#struct){
                            a: (#struct){
                              k: (string){ "simple" }
                              d: (#struct){
                                n: (string){ "c1" }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  out: (#struct){
    #p: (#struct){
      k: (string){ "complex" }
      d: (#struct){
        n: (string){ "s1" }
        r: (#struct){
          r1: (#struct){
            a: (#struct){
              k: (string){ "simple" }
              d: (#struct){
                n: (string){ "c1" }
              }
            }
          }
          r2: (#struct){
            a: (#struct){
              k: (string){ "complex" }
              d: (#struct){
                n: (string){ "s2" }
                r: (#struct){
                  r1: (#struct){
                    a: (#struct){
                      k: (string){ "simple" }
                      d: (#struct){
                        n: (string){ "c1" }
                      }
                    }
                  }
                  r2: (#struct){
                    a: (#struct){
                      k: (string){ "complex" }
                      d: (#struct){
                        n: (string){ "s3" }
                        r: (#struct){
                          r1: (#struct){
                            a: (#struct){
                              k: (string){ "simple" }
                              d: (#struct){
                                n: (string){ "c1" }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    dict: (#struct){
      r1: (#struct){
        a: (#struct){
          k: (string){ "simple" }
          d: (#struct){
            n: (string){ "c1" }
          }
        }
      }
      r2_r1: (#struct){
        a: (#struct){
          k: (string){ "simple" }
          d: (#struct){
            n: (string){ "c1" }
          }
        }
      }
      r2_r2_r1: (#struct){
        a: (#struct){
          k: (string){ "simple" }
          d: (#struct){
            n: (string){ "c1" }
          }
        }
      }
    }
    let subs#1multi = (〈3;#sub〉 & {
      #p: 〈2;rd〉.a
    })
  }
}
-- out/compile --
--- in.cue
{
  #AC: {
    k: "simple"
    d: 〈1;#C〉
  }
  #AS: {
    k: "complex"
    d: 〈1;#S〉
  }
  #R: {
    a: (〈1;#AC〉|〈1;#AS〉)
  }
  #S: {
    n: string
    r: {
      [string]: 〈2;#R〉
    }
  }
  #C: {
    n: string
  }
  #sub: {
    #p: 〈1;#AS〉
    dict: {
      [string]: _
    }
    for rn, rd in 〈0;#p〉.d.r if (〈0;rd〉.a.k == "complex") {
      let subs#1multi = (〈3;#sub〉 & {
        #p: 〈2;rd〉.a
      })
      for sn, sd in 〈0;let subs#1〉.dict {
        dict: {
          "\(〈4;rn〉)_\(〈2;sn〉)": 〈2;sd〉
        }
      }
    }
    for rn, rd in 〈0;#p〉.d.r if (〈0;rd〉.a.k == "simple") {
      dict: {
        "\(〈2;rn〉)": 〈2;rd〉
      }
    }
  }
  _test: {
    c1: 〈1;#AC〉
    c1: {
      d: {
        n: "c1"
      }
    }
    s3: 〈1;#AS〉
    s3: {
      d: {
        n: "s3"
        r: {
          r1: {
            a: 〈4;c1〉
          }
        }
      }
    }
    s2: 〈1;#AS〉
    s2: {
      d: {
        n: "s2"
        r: {
          r1: {
            a: 〈4;c1〉
          }
          r2: {
            a: 〈4;s3〉
          }
        }
      }
    }
    s1: 〈1;#AS〉
    s1: {
      d: {
        n: "s1"
        r: {
          r1: {
            a: 〈4;c1〉
          }
          r2: {
            a: 〈4;s2〉
          }
        }
      }
    }
  }
  out: (〈0;#sub〉 & {
    #p: 〈1;_test〉.s1
  })
}
