ns jsonexample fn main() let rawJson: String = match io::readFile("myDoc.json") Success(s) => s, Failure(err) => exit(err) end let o: obj = match parseJsonObj(rawJson) Success(o) => o, Failure(err) => exit(err) end assertEq!(o.a.b.c[0], 42) end fn parseJsonObj(s: String) -> obj let lexer = JsonLexer(s) let parser = JsonParser(lexer) parser.object() end enum JsonToken LBrace, RBrace, LSquare, RSquare, Comma, String(String), Number(Number), Boolean(Boolean) end class String pub fn matchAt(startIndex: Int, matchers: Map R), opts: obj { ignoreWhitespace: boolean, endIndex: Int }) -> Option todo!() end end class JsonLexer(val source: String) var index: Int pub fn nextToken() -> Option let token: Option = source.matchAt(index, [ /\{/ => JsonToken::LBrace, /}/ => JsonToken::RBrace, /\[/ => JsonToken::LSquare, /]/ => JsonToken::RSquare, /[0-9]+/ => { rawNumber: String => JsonToken::Number(number::parse(rawNumber))) } /true/ => JsonToken::Boolean(true), /false/ => JsonToken::False(false), // The following is not a good way for matching strings but whatever /"%w*"/ => { stringWithQuotes => JsonToken::String(stringWithQuotes[1..-1]) } ], ignoreWhitespace: true) match token? JsonToken::LBrace | JsonToken::RBrace | JsonToken::LSquare | JsonToken::RSquare | JsonToken::Comma => do index++ end JsonToken::String(s) => index += s.len() + 2, JsonToken::Number(n) => index += n.toString().len(), JsonToken::Boolean(b) => match b true => do index += 4 end false => do index += 5 end end end token end end class JsonParser(val lexer: JsonLexer) macro expect!($tokenType) match lexer.nextToken() Some(JsonToken::$tokenType) => do end, _ => panic! "Expected ${$tokenType}" end end pub fn object() -> obj expect!(LBrace) let result = obj {} while keyValue() is Some((key, value)) do result[key] = value end expect!(RBrace) result end fn keyValue() -> Option<(String, Any)> let key = match lexer.nextToken() Some(JsonToken::String(s)) => s, _ => return None end let value = value() Some((key, value)) end fn value() -> Any match lexer.nextToken() Some(token) => match token JsonToken::String(s) => s, JsonToken::Number(n) => n, JsonToken::Boolean(b) => b, JsonToken::LBrace => object(), JsonToken::LSquare => array() end, None => panic! "Expected LBrace, LSquare, String, Number, or Boolean" end end fn array() -> Array todo!() end end