114 lines
3.1 KiB
Plaintext
114 lines
3.1 KiB
Plaintext
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 <R> matchAt(startIndex: Int, matchers: Map<Regex, R | fn (match: String) -> R), opts: obj {
|
|
ignoreWhitespace: boolean,
|
|
endIndex: Int
|
|
}) -> Option<R>
|
|
todo!()
|
|
end
|
|
end
|
|
|
|
class JsonLexer(val source: String)
|
|
var index: Int
|
|
|
|
pub fn nextToken() -> Option<JsonToken>
|
|
let token: Option<JsonToken> = 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<Any>
|
|
todo!()
|
|
end
|
|
|
|
end |