///|
/// A located, non-secret diagnostic. Line zero denotes an API error.
pub(all) struct Diagnostic {
  line : Int32
  message : String
} derive(Debug, Eq)

///|
suberror Failure {
  Problem(Diagnostic)
} derive(Debug)

///|
fn fail(line : Int32, message : String) -> Unit raise Failure {
  raise Problem({ line, message, })
}

///|
/// A typed instruction. Operands are indices in the validated node array.
priv struct Node {
  id : Int32
  op : String
  width : Int32
  args : Array[Int32]
  params : Array[Int32]
  value : UInt64
  symbol : String
  input_dependent : Bool
}

///|
/// An immutable validated model. No mutable internal arrays are returned.
pub struct Model {
  priv nodes : Array[Node]
  priv states : Array[Int32]
  priv inputs : Array[Int32]
  priv initial : Array[(Int32, Int32)]
  priv updates : Array[(Int32, Int32)]
  priv bad : Array[Int32]
  priv constraints : Array[Int32]
  priv outputs : Array[Int32]
}

///|
/// Parser and allocation limits. Widths are deliberately bounded to 32 bits.
pub(all) struct ParseLimits {
  max_lines : Int32
  max_line_length : Int32
  max_nodes : Int32
  max_width : Int32
} derive(Debug, Eq)

///|
pub fn ParseLimits::default() -> ParseLimits {
  { max_lines: 20000, max_line_length: 4096, max_nodes: 10000, max_width: 32, }
}

///|
/// Stable declaration metadata for assigning inputs and interpreting traces.
pub(all) struct Port {
  id : Int32
  width : Int32
  symbol : String
} derive(Debug, Eq)

///|
pub fn Model::state_ports(self : Model) -> Array[Port] {
  self.states.map(i => {
    id: self.nodes[i].id,
    width: self.nodes[i].width,
    symbol: self.nodes[i].symbol,
  })
}

///|
pub fn Model::input_ports(self : Model) -> Array[Port] {
  self.inputs.map(i => {
    id: self.nodes[i].id,
    width: self.nodes[i].width,
    symbol: self.nodes[i].symbol,
  })
}

///|
pub fn Model::node_count(self : Model) -> Int32 {
  self.nodes.length()
}

///|
pub fn Model::bad_count(self : Model) -> Int32 {
  self.bad.length()
}

///|
fn mask(width : Int32) -> UInt64 {
  (1UL << width) - 1UL
}