///|
enum Token {
  LBracket(Loc)
  RBracket(Loc)
  Comma(Loc)
  Colon(Loc)
  LBrace(Loc)
  RBrace(Loc)
  Equal(Loc)
  LParen(Loc)
  RParen(Loc)
  Semi(Loc)
  True(Loc)
  False(Loc)
  For(Loc)
  As(Loc)
  Import(Loc)
  String(Loc, String)
  Int(Loc, Int)
  LIdent(Loc, String)
  PkgName(Loc, String)
  Eof(Loc)
} derive(Eq)

///|
impl Show for Token with output(self, logger) -> Unit {
  match self {
    LBracket(loc) => logger.write_string("LBracket(\{loc})")
    RBracket(loc) => logger.write_string("RBracket(\{loc})")
    Comma(loc) => logger.write_string("Comma(\{loc})")
    Colon(loc) => logger.write_string("Colon(\{loc})")
    LBrace(loc) => logger.write_string("LBrace(\{loc})")
    RBrace(loc) => logger.write_string("RBrace(\{loc})")
    Equal(loc) => logger.write_string("Equal(\{loc})")
    LParen(loc) => logger.write_string("LParen(\{loc})")
    RParen(loc) => logger.write_string("RParen(\{loc})")
    Semi(loc) => logger.write_string("Semi(\{loc})")
    True(loc) => logger.write_string("True(\{loc})")
    False(loc) => logger.write_string("False(\{loc})")
    For(loc) => logger.write_string("For(\{loc})")
    As(loc) => logger.write_string("As(\{loc})")
    Import(loc) => logger.write_string("Import(\{loc})")
    String(loc, s) => logger.write_string("String(\{loc}, \{s})")
    Int(loc, n) => logger.write_string("Int(\{loc}, \{n})")
    LIdent(loc, s) => logger.write_string("LIdent(\{loc}, \{s})")
    PkgName(loc, s) => logger.write_string("PkgName(\{loc}, \{s})")
    Eof(loc) => logger.write_string("Eof(\{loc})")
  }
}

///|
enum TokenKind {
  LBracket
  RBracket
  Comma
  Colon
  LBrace
  RBrace
  Equal
  LParen
  RParen
  Semi
  True
  False
  For
  As
  Import
  String
  Int
  LIdent
  PkgName
  Eof
} derive(Eq)

///|
impl Show for TokenKind with output(self, logger) -> Unit {
  logger.write_string(
    match self {
      LBracket => "LBracket"
      RBracket => "RBracket"
      Comma => "Comma"
      Colon => "Colon"
      LBrace => "LBrace"
      RBrace => "RBrace"
      Equal => "Equal"
      LParen => "LParen"
      RParen => "RParen"
      Semi => "Semi"
      True => "True"
      False => "False"
      For => "For"
      As => "As"
      Import => "Import"
      String => "String"
      Int => "Int"
      LIdent => "LIdent"
      PkgName => "PkgName"
      Eof => "Eof"
    },
  )
}

///|
fn Token::kind(self : Token) -> TokenKind {
  match self {
    LBracket(_) => LBracket
    RBracket(_) => RBracket
    Comma(_) => Comma
    Colon(_) => Colon
    LBrace(_) => LBrace
    RBrace(_) => RBrace
    Equal(_) => Equal
    LParen(_) => LParen
    RParen(_) => RParen
    Semi(_) => Semi
    True(_) => True
    False(_) => False
    For(_) => For
    As(_) => As
    String(_, _) => String
    Int(_, _) => Int
    LIdent(_, _) => LIdent
    PkgName(_, _) => PkgName
    Import(_) => Import
    Eof(_) => Eof
  }
}

///|
fn Token::range(self : Token) -> Loc {
  match self {
    LBracket(loc)
    | RBracket(loc)
    | Comma(loc)
    | Colon(loc)
    | LBrace(loc)
    | RBrace(loc)
    | Equal(loc)
    | LParen(loc)
    | RParen(loc)
    | Semi(loc)
    | True(loc)
    | False(loc)
    | For(loc)
    | As(loc)
    | Import(loc)
    | Eof(loc)
    | String(loc, _)
    | Int(loc, _)
    | LIdent(loc, _)
    | PkgName(loc, _) => loc
  }
}