///|
/// Represents an interned symbol. Symbols with the same representation share the same unique ID, allowing for O(1) equality checks.
struct Symbol {
  id : Int
  repr : String
}

///|
/// Represents an S-expression, which can be an atom (Symbol, String, Int, Double, Bool, Char) or a list of S-expressions.
pub(all) enum Sexp {
  Symbol(Symbol)
  String(String)
  List(Array[Sexp])
  Int(Int)
  Double(Double)
  Bool(Bool)
  Char(Char)
} derive(Eq, Hash)

///|
/// Represents an error that occurred during S-expression parsing.
suberror ParseError {
  ParseError(String)
} derive(Show, Eq)

///|
priv enum Token {
  OpenParen
  CloseParen
  BlockCommentBegin
  Symbol(Symbol)
  String(String)
  Int(Int)
  Double(Double)
  Bool(Bool)
  Char(Char)
}

///|
priv struct Position {
  mut line : Int
  mut col : Int
}

///|
priv struct Lexer {
  input_iter : RevertableIter[Char]
  pos : Position
}

///|
/// Represents a path within an S-expression structure, used for locating errors during deserialization.
enum SexpPath {
  Root
  Key(SexpPath, Symbol)
  Index(SexpPath, Int)
}