///|
/// A deprecated-syntax rule the parser warns about: one per kind of the
/// compiler's `DeprecatedSyntaxWarning`.
pub(all) enum Rule {
  DeprecatedListPrepend
  DeprecatedListPattern
  DeprecatedListCatchAllPattern
  DeprecatedListSpreadAsVariablePattern
  DeprecatedRecordSpreadPattern
  DeprecatedEmptyClauseGuard
  DeprecatedTargetShorthand
} derive(Eq, Debug, Hash)

///|
/// The rule's name, as a diagnostic names it.
pub fn Rule::name(self : Rule) -> String {
  match self {
    DeprecatedListPrepend => "deprecated-list-prepend"
    DeprecatedListPattern => "deprecated-list-pattern"
    DeprecatedListCatchAllPattern => "deprecated-list-catch-all-pattern"
    DeprecatedListSpreadAsVariablePattern =>
      "deprecated-list-spread-as-variable-pattern"
    DeprecatedRecordSpreadPattern => "deprecated-record-spread-pattern"
    DeprecatedEmptyClauseGuard => "deprecated-empty-clause-guard"
    DeprecatedTargetShorthand => "deprecated-target-shorthand"
  }
}

///|
pub fn Rule::all() -> Array[Rule] {
  [
    DeprecatedListPrepend,
    DeprecatedListPattern,
    DeprecatedListCatchAllPattern,
    DeprecatedListSpreadAsVariablePattern,
    DeprecatedRecordSpreadPattern,
    DeprecatedEmptyClauseGuard,
    DeprecatedTargetShorthand,
  ]
}

///|
/// What the parser accepts: the reserved words, the attribute names
/// (`@external`, …), the target names, and the deprecated syntax it warns
/// about. `Dialect::gleam_1_19()` is the default and the only built-in.
///
/// ```mbt check
/// test {
///   let d = @dialect.Dialect::gleam_1_19()
///   inspect(d.knows_attribute("deprecated"), content="true")
///   inspect(d.warns(DeprecatedListPrepend), content="true")
/// }
/// ```
pub(all) struct Dialect {
  name : String
  keywords : ArrayView[String]
  attributes : ArrayView[String]
  targets : ArrayView[String]
  deprecations : ArrayView[Rule]
} derive(Eq, Debug)

///|
/// Gleam 1.19: the compiler's 22 reserved words, the four attributes, the
/// two targets, and every deprecation warning on.
pub fn Dialect::gleam_1_19() -> Dialect {
  {
    name: "gleam-1.19",
    keywords: [
      "as", "assert", "auto", "case", "const", "delegate", "derive", "echo", "else",
      "fn", "if", "implement", "import", "let", "macro", "opaque", "panic", "pub",
      "test", "todo", "type", "use",
    ][:],
    attributes: ["external", "target", "deprecated", "internal"][:],
    targets: ["erlang", "javascript"][:],
    deprecations: Rule::all()[:],
  }
}

///|
pub fn Dialect::warns(self : Dialect, rule : Rule) -> Bool {
  self.deprecations.contains(rule)
}

///|
pub fn Dialect::knows_attribute(self : Dialect, name : String) -> Bool {
  self.attributes.contains(name)
}

///|
pub fn Dialect::knows_target(self : Dialect, name : String) -> Bool {
  self.targets.contains(name)
}

///|
/// The Gleam versions with a built-in dialect, as `from_version` reads
/// them.
pub fn Dialect::known_versions() -> Array[String] {
  ["1.19"]
}

///|
/// The built-in dialect for a Gleam version (`"1.19"`), or `None`.
///
/// ```mbt check
/// test {
///   debug_inspect(
///     @dialect.Dialect::from_version("1.19").map(d => d.version()),
///     content="Some(\"1.19\")",
///   )
/// }
/// ```
pub fn Dialect::from_version(version : String) -> Dialect? {
  match version {
    "1.19" => Some(Dialect::gleam_1_19())
    _ => None
  }
}

///|
/// The Gleam version this dialect follows (`"1.19"` for `gleam-1.19`).
pub fn Dialect::version(self : Dialect) -> String {
  if self.name.has_prefix("gleam-") {
    self.name[6:].to_owned()
  } else {
    self.name
  }
}