1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
use std::vec::IntoIter; use pest::{Parser, error::Error}; #[grammar = "grammar.pest"] #[derive(Parser)] struct IONParser; #[derive(Debug)] pub(crate) enum IONValue<'a> { Object(Vec<(&'a str, IONValue<'a>)>), Array(Vec<IONValue<'a>>), String(&'a str), Number(f64), Boolean(bool), Null, } impl IONValue<'_> { fn to_json(&self) -> String { match self { IONValue::Object(o) => { let mut buf = "{".to_string(); for (key, val) in o { buf.push_str(&format!("\"{}\"", key)); buf.push(':'); buf.push_str(&val.to_json()); buf.push(','); } buf.remove(buf.len()-1); buf.push('}'); buf } IONValue::Array(a) => { let mut buf = "[".to_string(); for val in a { buf.push_str(&val.to_json()); buf.push(','); } buf.remove(buf.len()-1); buf.push(']'); buf } IONValue::String(a) => { let mut a = a.to_string(); if a.as_bytes()[0] as char == '"' { a } else if a.as_bytes()[0] as char == '\'' { a.remove(0); a.remove(a.len() - 1); format!("\"{}\"", a) } else { format!("\"{}\"", a) } }, IONValue::Number(a) => a.to_string(), IONValue::Boolean(a) => a.to_string(), IONValue::Null => "null".to_string(), } } } pub fn ion_to_json(file: &str) -> Result<String, anyhow::Error> { let p = match IONParser::parse(Rule::ion, file)?.next() { Some(s) => s, None => return Err(anyhow::anyhow!("not a valid file")) }; let p = parse_value(p); let json = p.to_json(); if json != "{" { Ok(json) } else { Ok("".to_string()) } } use pest::iterators::Pair; use crate::error; fn parse_value(pair: Pair<Rule>) -> IONValue { match pair.as_rule() { Rule::ion | Rule::object => { IONValue::Object( pair.into_inner().map(|s| { let mut inner = s.into_inner(); let name = inner.next().unwrap().as_span().as_str(); let value = inner.next().unwrap(); let value = parse_value(value); (name, value) }).collect() ) }, Rule::array => IONValue::Array(pair.into_inner().map(parse_value).collect()), Rule::version | Rule::string => IONValue::String(pair.as_str()), Rule::number => IONValue::Number(pair.as_str().parse().unwrap()), Rule::boolean => IONValue::Boolean(pair.as_str().parse().unwrap()), Rule::null => IONValue::Null, | Rule::key_val | Rule::value | Rule::qchar | Rule::sqchar | Rule::COMMENT | Rule::WHITESPACE => unreachable!(), } }