sexp

    A simple S-expression parser and serializer for MoonBit.

    s-expression
    parser
    serialization
    sexp
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    7 months ago
    Downloads
    1K

    #Sexp for MoonBit

    A robust S-expression parser and serializer for MoonBit, supporting efficient parsing, serialization, and type-safe conversion between S-expressions and MoonBit types.

    #S-Expression Format Specification

    This library parses a standard variant of S-expressions.

    #Atoms

    • Symbols: Sequences of characters excluding whitespace and delimiters ()";.
      • Examples: foo, bar-baz, +, <=, 123?.
      • Note: A lone - is parsed as a Symbol.
    • Integers: Signed 64-bit integers.
      • Examples: 123, +42, -99.
    • Doubles: Floating point numbers.
      • Examples: 3.14, -0.001, 1.2e10.
    • Strings: Enclosed in double quotes. Supports standard escape sequences:
      • \n (newline), \r (CR), \t (tab), \b (backspace), \f (formfeed).
      • \" (quote), \\ (backslash).
      • \uXXXX (unicode codepoint).
    • Booleans: #t (true) and #f (false).
    • Characters: Prefixed with #\.
      • Literal char: #\a, #\Z.
      • Unicode: #\u00A9.
      • Constants: #\space, #\newline, #\tab, #\return, #\backspace, #\nul.

    #Structure

    • Lists: Enclosed in parentheses ( ... ).
      • Example: (1 2 "three" (nested 4)).

    #Comments

    • Line Comments: Start with ; and continue to the end of the line.
      • Example: ; This is a comment.
    • S-expression Comments: #; discards the immediately following S-expression.
      • Example: (1 #; (ignored 2 3) 4) parses as (1 4).

    #Installation

    Add the dependency to your moon.pkg.json:

    { "import": [ "sennenki/sexp" ] }

    #Parsing

    Use parse to parse a single S-expression from a string.

    ///|
    test "parsing" {
    let s = "(list 1 2 3)"
    // Parse returns a Result, use `try!` to unwrap
    let sexp = parse(s)
    inspect(sexp, content="(list 1 2 3)")
    }

    Use parse_many to parse a sequence of S-expressions.

    ///|
    test "parsing multiple" {
    let s = "1 2 3"
    let sexps = try! parse_many(s)
    inspect(sexps, content="[1, 2, 3]")
    }

    #Type Conversion

    The library provides ToSexp and FromSexp traits for seamless conversion. Built-in types like Int, String, Bool, Double, Array, Map, Unit and Tuples are supported.

    ///|
    test "conversion" {
    let val = [1, 2, 3]
    // Convert to Sexp
    let sexp = to_sexp(val)
    inspect(sexp, content="(1 2 3)")

    // Convert back
    let back : Array[Int] = try! from_sexp(sexp)
    inspect(back, content="[1, 2, 3]")
    }

    #Custom Types

    Implement ToSexp and FromSexp for your custom structures.

    ///|
    struct User {
    name : String
    age : Int
    } derive(Show, Eq)

    ///|
    impl ToSexp for User with to_sexp(self) {
    List([Symbol(Symbol::new("user")), String(self.name), Int(self.age)])
    }

    ///|
    impl FromSexp for User with from_sexp(sexp, path) {
    match sexp {
    List([Symbol(s), String(name), Int(age)]) =>
    // Note: Symbol comparison should ideally check interned ID if possible,
    // or use the derived Eq.
    if s == Symbol::new("user") {
    { name, age }
    } else {
    raise SexpError("Expected 'user' symbol", path)
    }
    _ => raise SexpError("Invalid user format", path)
    }
    }

    ///|
    test "custom type" {
    let user = { name: "Alice", age: 30 }
    let sexp = to_sexp(user)
    inspect(sexp, content="(user \"Alice\" 30)")
    let back : User = try! from_sexp(sexp)
    assert_eq(back, user)
    }

    #Error Handling

    Errors during parsing or conversion are reported with ParseError or SexpError, including path information for structural errors.

    ///|
    test "error handling" {
    let sexp = Sexp::List([String("not-user"), Int(42)])
    // Attempting to decode into User
    let result : Result[User, SexpError] = try! from_sexp(sexp)
    // You can inspect the error path to find where it failed
    inspect(result, content="Err(SexpError at : Invalid user format)")
    }

    FromSexp

    pub(open) trait FromSexp {
    from_sexp(Sexp, SexpPath) -> Self raise SexpError
    sexp_path_key(Self) -> Symbol? = _
    }

    A trait for types that can be constructed from an S-expression.
    impl FromSexp for Unit
    impl FromSexp for Bool
    impl FromSexp for Char
    impl FromSexp for Int
    impl FromSexp for Int64
    impl FromSexp for UInt
    impl FromSexp for UInt64
    impl FromSexp for Float
    impl FromSexp for Double
    impl FromSexp for String
    impl FromSexp for Option[T]
    impl FromSexp for Result[T, E]
    impl FromSexp for FixedArray[T]
    impl FromSexp for Bytes
    impl FromSexp for Array[T]
    impl FromSexp for ArrayView[T]
    impl FromSexp for Map[K, V]
    impl FromSexp for Tuple2[T, U]

    ToSexp

    pub(open) trait ToSexp {
    to_sexp(Self) -> Sexp
    }

    A trait for types that can be converted to an S-expression.
    impl ToSexp for Unit
    impl ToSexp for Bool
    impl ToSexp for Char
    impl ToSexp for Int
    impl ToSexp for Int64
    impl ToSexp for UInt
    impl ToSexp for UInt64
    impl ToSexp for Float
    impl ToSexp for Double
    impl ToSexp for String
    impl ToSexp for Option[T]
    impl ToSexp for Result[T, E]
    impl ToSexp for FixedArray[T]
    impl ToSexp for Bytes
    impl ToSexp for Array[T]
    impl ToSexp for ArrayView[T]
    impl ToSexp for Map[K, V]
    impl ToSexp for Tuple2[T, U]
    impl ToSexp for BytesView

    ParseError

    type ParseError

    Represents an error that occurred during S-expression parsing.
    impl Eq for ParseError
    impl Show for ParseError

    SexpError

    pub(all) suberror SexpError {
    SexpError(String, SexpPath)
    }

    Represents an error that occurred when converting an S-expression to a specific type. Contains a message and the path to the element where the error occurred.
    impl Show for SexpError

    Sexp

    pub(all) enum Sexp {
    Symbol(Symbol)
    String(String)
    List(Array[Sexp])
    Int(Int)
    Double(Double)
    Bool(Bool)
    Char(Char)
    }

    Represents an S-expression, which can be an atom (Symbol, String, Int, Double, Bool, Char) or a list of S-expressions.
    impl Eq for Sexp
    impl Hash for Sexp
    impl Show for Sexp
    impl FromSexp for Sexp
    impl ToSexp for Sexp

    SexpPath

    type SexpPath

    Represents a path within an S-expression structure, used for locating errors during deserialization.
    impl Show for SexpPath

    SexpPath::add_index

    fn SexpPath::add_index(self : SexpPath, index : Int) -> SexpPath

    Adds an index segment to the path, used when navigating a list.

    SexpPath::add_key

    fn SexpPath::add_key(self : SexpPath, key : Symbol) -> SexpPath

    Adds a key segment to the path, typically used when navigating a Map-like structure represented as an association list.

    SexpPath::add_string_key

    fn SexpPath::add_string_key(self : SexpPath, key : String) -> SexpPath

    Adds a string key segment to the path by converting the string to a Symbol.

    Symbol

    type Symbol

    Represents an interned symbol. Symbols with the same representation share the same unique ID, allowing for O(1) equality checks.
    impl Eq for Symbol
    impl Hash for Symbol
    impl Show for Symbol
    impl FromSexp for Symbol
    impl ToSexp for Symbol

    Symbol::new

    fn Symbol::new(str : String) -> Symbol

    Creates a new Symbol from a string.

    If the symbol already exists in the global symbol table, the existing symbol is returned. This ensures that Symbols with the same string representation are always identical.

    from_sexp

    fn[T : FromSexp] from_sexp(sexp : Sexp) -> T raise SexpError

    parse

    fn parse(input : StringView) -> Sexp raise ParseError

    Parses a single S-expression from the input string view.

    Errors

    Returns ParseError if the input parses to more than one S-expression or if the syntax is invalid.

    parse_many

    fn parse_many(input : StringView) -> Array[Sexp] raise ParseError

    Parses multiple S-expressions from the input string view.

    Returns an array containing all parsed S-expressions.

    to_sexp

    fn[T : ToSexp] to_sexp(value : T) -> Sexp

    Converts a value to an S-expression.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io