# Tests that the evaluator resolves various forms of self-referential cycles
# without errors or hangs. Covers arithmetic cycles (math), tautological list
# cycles (list.t0), list cycles through external bindings (list.t1), and
# mutual struct cycles with two (nodes.t2) and three (nodes.t3) participants.
-- in.cue --
math: {
	a: b - 100
	b: a + 100
	b: 200
}

a: 100

// list.t0: tautological cycle — c[0] = c[0] adds no constraint,
// so c resolves to a list with one unconstrained element.
list: t0: c: [c[0]]

// list.t1: cycles where an external binding (a=100) breaks the cycle.
// p1 and p2 test different element orderings; both resolve to [100, 100].
list: t1: p1: c: [c[1], a]
list: t1: p2: c: [a, c[0]]

// nodes.t1: self-referential struct; tests commutativity of &.
nodes: t1: p1: s1: s1 & {a: 1}
nodes: t1: p2: s1: {a: 1} & s1
// nodes.t2: two-node mutual cycle; field order must not affect the result.
nodes: t2: {
	s1: s2 & {a: 1}
	s2: s1 & {b: 2}
}
// nodes.t3: three-node mutual cycle; all 6 orderings must yield equal results.
nodes: t3: {
	s1: s2 & {a: 1}
	s2: s3 & {b: 2}
	s3: s1 & {c: 3}
}
-- out/compile --
--- in.cue
{
  math: {
    a: (〈0;b〉 - 100)
    b: (〈0;a〉 + 100)
    b: 200
  }
  a: 100
  list: {
    t0: {
      c: [
        〈1;c〉[0],
      ]
    }
  }
  list: {
    t1: {
      p1: {
        c: [
          〈1;c〉[1],
          〈4;a〉,
        ]
      }
    }
  }
  list: {
    t1: {
      p2: {
        c: [
          〈4;a〉,
          〈1;c〉[0],
        ]
      }
    }
  }
  nodes: {
    t1: {
      p1: {
        s1: (〈0;s1〉 & {
          a: 1
        })
      }
    }
  }
  nodes: {
    t1: {
      p2: {
        s1: ({
          a: 1
        } & 〈0;s1〉)
      }
    }
  }
  nodes: {
    t2: {
      s1: (〈0;s2〉 & {
        a: 1
      })
      s2: (〈0;s1〉 & {
        b: 2
      })
    }
  }
  nodes: {
    t3: {
      s1: (〈0;s2〉 & {
        a: 1
      })
      s2: (〈0;s3〉 & {
        b: 2
      })
      s3: (〈0;s1〉 & {
        c: 3
      })
    }
  }
}
