///|
/// TOML value types
pub enum TomlValue {
String(String)
Integer(Int64)
Float(Double)
Boolean(Bool)
DateTime(String) // ISO 8601 datetime string
Array(Array[TomlValue])
Table(Map[String, TomlValue])
} derive(Eq, Show)
///|
/// Parser error type
pub(all) suberror ParseError {
UnexpectedChar(Int, Char) // position, char
UnexpectedEof
InvalidEscape(Int, Char)
InvalidNumber(Int, String)
InvalidDateTime(Int, String)
DuplicateKey(String)
InvalidKey(Int, String)
} derive(Eq, Show)
///|
/// Parser state
priv struct Parser {
input : String
mut pos : Int
}
///|
/// Create a new parser
fn Parser::new(input : String) -> Parser {
{ input, pos: 0 }
}
///|
/// Check if at end of input
fn Parser::is_eof(self : Parser) -> Bool {
self.pos >= self.input.length()
}
///|
/// Peek current character without consuming
fn Parser::peek(self : Parser) -> Char? {
if self.is_eof() {
None
} else {
self.input.get_char(self.pos)
}
}
///|
/// Get current character and advance
fn Parser::next(self : Parser) -> Char? {
match self.peek() {
Some(ch) => {
self.pos += 1
Some(ch)
}
None => None
}
}
///|
/// Skip whitespace and comments
fn Parser::skip_whitespace(self : Parser) -> Unit {
while not(self.is_eof()) {
match self.peek() {
Some(' ' | '\t' | '\r') => {
self.pos += 1
continue
}
Some('#') =>
// Skip comment until end of line
while not(self.is_eof()) {
match self.next() {
Some('\n') => break
_ => continue
}
}
_ => break
}
}
}