toml_parser

A pure MoonBit TOML parser supporting strings, numbers, booleans, arrays, tables, and comments

toml
parser
config
configuration
moon add tonyfettes/toml_parser@0.1.0
Download zip
Version
0.1.0
License
Apache-2.0
Last updated
9 months ago
Downloads
18
README

#TOML Parser

A pure MoonBit implementation of a TOML (Tom's Obvious, Minimal Language) parser. This parser supports TOML v1.0 features including strings, numbers, booleans, arrays, tables, and inline tables.

#Features

  • ✅ Parse TOML strings, integers, floats, and booleans
  • ✅ Support for arrays and inline tables
  • ✅ Table sections with [section] syntax
  • ✅ Comments with #
  • ✅ Escape sequences in strings
  • ✅ Literal strings with single quotes
  • ✅ Number formatting with underscores
  • ✅ Scientific notation for floats
  • ✅ Comprehensive error handling
  • ✅ Type-safe API for accessing values

#Installation

Add this package to your MoonBit project using:

moon add tonyfettes/toml_parser

#Usage

#Basic Example

///|
test "basic usage" {
let toml_text = "name = \"Alice\"\nage = 30\nenabled = true"
let value = @toml_parser.parse(toml_text) catch {
err => {
println(err.to_string())
fail("parse failed")
}
}

// Access values from the parsed TOML
let name = value.get("name").unwrap().as_string().unwrap()
let age = value.get("age").unwrap().as_int().unwrap()
let enabled = value.get("enabled").unwrap().as_bool().unwrap()
inspect(name, content="Alice")
inspect(age, content="30")
inspect(enabled, content="true")
}

#Parsing Tables

///|
test "table parsing" {
let toml_text =
#|[server]
#|host = "localhost"
#|port = 8080
#|
let result = @toml_parser.parse(toml_text) catch { _ => fail("parse failed") }
let server = result.get("server").unwrap().as_table().unwrap()
inspect(server.get("host").unwrap().as_string().unwrap(), content="localhost")
inspect(server.get("port").unwrap().as_int().unwrap(), content="8080")
}

#Parsing Arrays

///|
test "array parsing" {
let toml_text = "numbers = [1, 2, 3, 4, 5]"
let result = @toml_parser.parse(toml_text) catch { _ => fail("parse failed") }
let numbers = result.get("numbers").unwrap().as_array().unwrap()
inspect(numbers.length(), content="5")
inspect(numbers[0].as_int().unwrap(), content="1")
inspect(numbers[4].as_int().unwrap(), content="5")
}

#Inline Tables

///|
test "inline table" {
let toml_text = "person = { name = \"Bob\", age = 25 }"
let result = @toml_parser.parse(toml_text) catch { _ => fail("parse failed") }
let person = result.get("person").unwrap().as_table().unwrap()
inspect(person.get("name").unwrap().as_string().unwrap(), content="Bob")
inspect(person.get("age").unwrap().as_int().unwrap(), content="25")
}

#Complex Document

///|
test "complex document" {
let config =
#|# Application configuration
#|title = "My App"
#|
#|[database]
#|server = "192.168.1.1"
#|ports = [8001, 8002, 8003]
#|enabled = true
#|
#|[owner]
#|name = "Tom"
#|email = "tom@example.com"
#|
let result = @toml_parser.parse(config) catch { _ => fail("parse failed") }
inspect(result.get("title").unwrap().as_string().unwrap(), content="My App")
let db = result.get("database").unwrap().as_table().unwrap()
inspect(db.get("server").unwrap().as_string().unwrap(), content="192.168.1.1")
inspect(db.get("enabled").unwrap().as_bool().unwrap(), content="true")
let ports = db.get("ports").unwrap().as_array().unwrap()
inspect(ports.length(), content="3")
}

#API Reference

#Types

#TomlValue

The main enum representing TOML values:

///|
pub enum TomlValue {
String(String)
Integer(Int64)
Float(Double)
Boolean(Bool)
DateTime(String)
Array(Array[TomlValue])
Table(Map[String, TomlValue])
}

#ParseError

Error types returned when parsing fails:

///|
pub suberror ParseError {
UnexpectedChar(Int, Char) // position, character
UnexpectedEof
InvalidEscape(Int, Char)
InvalidNumber(Int, String)
InvalidDateTime(Int, String)
DuplicateKey(String)
InvalidKey(Int, String)
}

#Functions

#parse(input : String) -> TomlValue raise ParseError

Parses a TOML string and returns a TomlValue. Use catch to handle errors.

///|
test "parse function" {
let result = @toml_parser.parse("key = \"value\"") catch {
_ => fail("parse failed")
}
inspect(result.get("key").unwrap().as_string().unwrap(), content="value")
}

#Value Access Methods

  • TomlValue::get(self, key : String) -> TomlValue? - Get value by key from table
  • TomlValue::as_string(self) -> String? - Convert to String
  • TomlValue::as_int(self) -> Int64? - Convert to Int64
  • TomlValue::as_float(self) -> Double? - Convert to Double
  • TomlValue::as_bool(self) -> Bool? - Convert to Bool
  • TomlValue::as_array(self) -> Array[TomlValue]? - Convert to Array
  • TomlValue::as_table(self) -> Map[String, TomlValue]? - Convert to Table
  • TomlValue::to_string(self) -> String - Pretty print the value

#Supported TOML Features

#Data Types

  • Strings: Basic strings ("...") and literal strings ('...')
  • Integers: Decimal integers with optional underscores (1_000_000)
  • Floats: Decimal floats with optional scientific notation (1.5e10)
  • Booleans: true and false
  • Arrays: Homogeneous or heterogeneous arrays ([1, 2, 3])
  • Tables: Key-value maps ({ key = "value" })

#Syntax Features

  • Comments: Lines starting with # or inline comments
  • Escape Sequences: \t, \n, \r, \\, \"
  • Table Sections: [section.name]
  • Inline Tables: { key1 = value1, key2 = value2 }
  • Multiline Arrays: Arrays can span multiple lines
  • Trailing Commas: Allowed in arrays and inline tables

#Running the Example

cd toml_parser moon run cmd/main

This will parse and display a sample TOML configuration file.

#Running Tests

moon test

The test suite includes comprehensive tests for:
  • Basic data types
  • Arrays and tables
  • Comments and whitespace
  • Escape sequences
  • Error handling
  • Complex nested structures

#Limitations

This is a basic TOML parser implementation. Some advanced TOML v1.0 features are not yet supported:

  • Array of tables ([[section]])
  • Dotted keys (physical.color = "orange")
  • Multi-line basic strings
  • Multi-line literal strings
  • DateTime types (currently parsed as strings)
  • Hexadecimal, octal, and binary integer formats

#License

This project is open source and available for use in your MoonBit projects.

#Contributing

Contributions are welcome! Feel free to submit issues or pull requests to improve the parser.

#
ParseError

pub(all) suberror ParseError {
UnexpectedChar(Int, Char)
UnexpectedEof
InvalidEscape(Int, Char)
InvalidNumber(Int, String)
InvalidDateTime(Int, String)
DuplicateKey(String)
InvalidKey(Int, String)
}

Parser error type
impl Eq for ParseError
impl Show for ParseError

#
TomlValue

pub enum TomlValue {
String(String)
Integer(Int64)
Float(Double)
Boolean(Bool)
DateTime(String)
Array(Array[TomlValue])
Table(Map[String, TomlValue])
}

TOML value types
impl Eq for TomlValue
impl Show for TomlValue

#
TomlValue::as_array

fn TomlValue::as_array(self : TomlValue) -> Array[TomlValue]?

Convert TomlValue to Array

#
TomlValue::as_bool

fn TomlValue::as_bool(self : TomlValue) -> Bool?

Convert TomlValue to Bool

#
TomlValue::as_float

fn TomlValue::as_float(self : TomlValue) -> Double?

Convert TomlValue to Double

#
TomlValue::as_int

fn TomlValue::as_int(self : TomlValue) -> Int64?

Convert TomlValue to Int64

#
TomlValue::as_string

fn TomlValue::as_string(self : TomlValue) -> String?

Convert TomlValue to String

#
TomlValue::as_table

fn TomlValue::as_table(self : TomlValue) -> Map[String, TomlValue]?

Convert TomlValue to Table

#
TomlValue::get

fn TomlValue::get(self : TomlValue, key : String) -> TomlValue?

Get a value from a table by key

#
parse

fn parse(input : String) -> TomlValue raise ParseError

Parse a TOML document