// What the scanner extracts from a type declaration, and all the emitter
// needs to know about it.
//
// Deliberately does not carry any MoonBit *types*: thanks to backward type
// inference, generated code never has to name the type of a field or a
// variant payload, so the generator never has to render one.

///|
/// A type marked with `#serde.derive(...)`.
struct Target {
  name : String
  /// Type parameters, e.g. `["T"]` for `Foo[T]`. Each gets a trait bound on
  /// the generated impl.
  params : Array[String]
  /// Whether the type itself is public, which decides whether the impl can be.
  public : Bool
  shape : Shape
  serialize : Bool
  deserialize : Bool
}

///|
/// Which of the data model's struct forms a type maps onto.
///
/// The two degenerate forms are separated out for the same reason serde
/// separates them: a struct wrapping exactly one value is a wrapper, not a
/// one-element tuple, and a struct with nothing in it carries no more
/// information than unit. Both have their own `Serializer` methods, whose
/// defaults widen to the general form, so a format that draws no distinction
/// still writes what `TupleStruct` and `Record` would have written.
enum Shape {
  /// `struct Foo {}` — no fields at all. Not the same as a record whose
  /// fields are all `#serde.skip`ed: that one still has a shape, and stays a
  /// `Record` with nothing left to write.
  UnitStruct
  /// `struct Foo(Int)` — exactly one positional field, written as the value
  /// it wraps rather than as a sequence of one.
  NewtypeStruct
  /// `struct Foo { a : Int }`
  Record(Array[Field])
  /// `struct Foo(Int, Int)`
  TupleStruct(Int32)
  /// `enum Foo { ... }`
  Variant(Array[Case])
}

///|
struct Field {
  /// The MoonBit field name.
  ident : String
  /// The name it is serialized under, after `#serde.rename`.
  name : String
  /// True when the declared type is `T?`, in which case an absent field
  /// deserializes to `None` instead of being an error.
  optional : Bool
  /// `#serde.skip`: left out of the output entirely, and filled from
  /// `Default::default()` on the way back in.
  skip : Bool
}

///|
struct Case {
  ident : String
  name : String
  payload : Payload
}

///|
/// Which of serde's four variant forms this case maps onto.
enum Payload {
  /// `Empty`
  Unit
  /// `Circle(Double)`
  Newtype
  /// `Rect(Double, Double)`
  Tuple(Int32)
  /// `Tagged(name~ : String, size~ : Int)`
  Struct(Array[Field])
}

///|
/// A problem with the *attributes*, as opposed to a parse error. Carries a
/// location prefix so the message reads like a compiler diagnostic.
suberror DeriveError {
  DeriveError(where_~ : String, message~ : String)
}

///|
impl Show for DeriveError with fn output(self, logger) {
  let DeriveError(where_~, message~) = self
  logger <+ "\{where_}: \{message}"
}