use std::collections::HashMap;
#[derive(Debug)]
pub enum JSON {
Object(HashMap<String, JSON>),
Array(Vec<JSON>),
String(String),
Number(f64),
Boolean(bool),
Null,
}
pub fn parse_value_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
match parser.peek() {
'{' => parse_object_ws(parser),
'[' => parse_array_ws(parser),
'"' => Ok(JSON::String(parser.parse_string_match_delimiter_ws()?)),
ch if ch == '-' || ch.is_ascii_digit() => Ok(JSON::Number(parser.parse_f64_decimal_ws()?)),
't' if parser.peek_and_consume_str_ws("true") => Ok(JSON::Boolean(true)),
'f' if parser.peek_and_consume_str_ws("false") => Ok(JSON::Boolean(false)),
'n' if parser.peek_and_consume_str_ws("null") => Ok(JSON::Null),
ch => Err(trivet::errors::unexpected_text_error(
parser.loc(),
"the start of a JSON value",
&ch.to_string(),
)),
}
}
fn parse_object_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
parser.consume(); parser.consume_ws();
let mut first = true;
let mut map = HashMap::new();
while !parser.peek_and_consume_ws('}') {
if first {
first = false;
} else if !parser.peek_and_consume_ws(',') {
return Err(trivet::errors::syntax_error(
parser.loc(),
"There must be a comma (,) between members of an object.",
));
}
if parser.peek() != '"' {
return Err(trivet::errors::syntax_error(
parser.loc(),
"Names in a JSON object must be quoted strings.",
));
}
let name = parser.parse_string_match_delimiter_ws()?;
if !parser.peek_and_consume_ws(':') {
return Err(trivet::errors::syntax_error(
parser.loc(),
"Names in a JSON object must be followed by a colon (:).",
));
}
let value = parse_value_ws(parser)?;
map.insert(name, value);
}
Ok(JSON::Object(map))
}
fn parse_array_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
parser.consume(); parser.consume_ws_only();
let mut first = true;
let mut array = vec![];
while !parser.peek_and_consume_ws(']') {
if first {
first = false;
} else if !parser.peek_and_consume_ws(',') {
return Err(trivet::errors::syntax_error(
parser.loc(),
"There must be a comma (,) between members of an array.",
));
}
let value = parse_value_ws(parser)?;
array.push(value);
}
Ok(JSON::Array(array))
}
pub fn main() {
let mut parser = trivet::parse_from_stdin();
parser.parse_comments = false;
let numpar = parser.borrow_number_parser();
numpar.settings.permit_binary = false;
numpar.settings.permit_hexadecimal = false;
numpar.settings.permit_octal = false;
numpar.settings.permit_underscores = false;
numpar.settings.decimal_only_floats = true;
numpar.settings.permit_plus = false;
numpar.settings.permit_leading_zero = false;
numpar.settings.permit_empty_whole = false;
numpar.settings.permit_empty_fraction = false;
let strpar = parser.borrow_string_parser();
strpar.set(trivet::strings::StringStandard::JSON);
let _ = parser
.borrow_core()
.replace_whitespace_test(Box::new(|ch| [' ', '\n', '\r', '\t'].contains(&ch)));
parser.consume_ws();
let result = parse_value_ws(&mut parser);
match result {
Err(error) => {
println!("ERROR: {}", error);
std::process::exit(1);
}
Ok(json) => {
if parser.is_at_eof() {
println!("{:?}", json);
std::process::exit(0)
} else {
println!("Found unexpected trailing characters after JSON value.");
std::process::exit(1);
}
}
}
}