1#[derive(Clone, Debug, PartialEq)]
46pub enum Value {
47 Dict(Vec<Object>),
48 Str(String),
49 ZStr(String),
50 Int(i32),
51 Float(f64),
52 Bool(bool),
53}
54
55impl Value {
56 pub fn to_number<T>(&self) -> Option<T>
61 where
62 T: std::convert::From<i32> + std::convert::From<f64>,
63 {
64 match *self {
65 Self::Int(i) => Some(i.into()),
66 Self::Float(f) => Some(f.into()),
67 _ => None,
68 }
69 }
70}
71
72#[derive(Clone, Debug, PartialEq)]
74pub struct Pair {
75 pub key: String,
76 pub value: Value,
77}
78
79#[derive(Clone, Debug, PartialEq)]
81pub enum Object {
82 Dict(Vec<Object>),
83 Pair(Pair),
84 Str(String),
85 ZStr(String),
86 Int(i32),
87}
88
89type Result<T> = std::result::Result<T, peg::error::ParseError<peg::str::LineCol>>;
91
92impl Object {
93 pub fn from_string(s: &str) -> Result<Object> {
95 lron::root(s)
96 }
97}
98
99peg::parser! {grammar lron() for str {
104
105use std::str::FromStr;
106
107pub rule root() -> Object
108 = key:identifier() _() "=" _() value:array() _()
109 { Object::Pair(Pair{key, value: Value::Dict(value)}) }
110
111rule array() -> Vec<Object>
112 = "{" _() v:(object() ** (_() "," _())) _()(",")? _() "}" { v }
113
114rule object() -> Object
115 = a:array() { Object::Dict(a) } /
116 p:pair() { Object::Pair(p) } /
117 s:string_literal() { Object::Str(s) } /
118 z:zstr() { Object::ZStr(z) } /
119 n:int() { Object::Int(n) }
120
121rule pair() -> Pair
122 = key:identifier() _() "=" _() value:value() { Pair { key, value } } /
123 "[" key:string_literal() "]" _() "=" _() value:value()
124 { Pair { key, value } }
125
126rule value() -> Value
127 = i:int() { Value::Int(i) } /
128 b:bool() { Value::Bool(b) } /
129 f:float() { Value::Float(f) } /
130 s:string_literal() { Value::Str(s) } /
131 a:array() { Value::Dict(a) } /
132 z:zstr() { Value::ZStr(z) }
133
134rule int() -> i32
135 = n:$("-"? ['0'..='9']+) !"." { i32::from_str(n).unwrap() } / expected!("integer")
136
137rule bool() -> bool
138 = "true" { true } / "false" { false }
139
140rule float() -> f64
141 = f:$("-"? ['0'..='9']+ "." ['0'..='9']+) { f64::from_str(f).unwrap() } / expected!("floating point")
142
143rule identifier() -> String
144 = s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_']+) { s.to_owned() } / expected!("identifier")
145
146rule escape() -> &'static str
148 = "\\\"" { "\"" } / "\\\n" { "\n" }
149
150rule string_literal() -> String
152 = "\"" s:((escape() / $(!['"'][_]))*) "\"" { s.join("") }
153
154rule zstr() -> String
155 = "ZSTR" _() s:string_literal() { s }
156
157rule _() = quiet!{[' ' | '\r' | '\n' | '\t']*}
158
159}}
160
161#[test]
162fn test_parser() {
163 const DATA: &str = include_str!("../data/test_lron");
164 let r = Object::from_string(DATA);
165
166 assert!(r.is_ok());
167 let o = r.unwrap();
168
169 assert!(matches!(o, Object::Pair(_)));
170 if let Object::Pair(ref p) = o {
171 assert_eq!(p.key, "s");
172 assert!(matches!(p.value, Value::Dict(_)));
173
174 if let Value::Dict(ref d) = p.value {
175 assert_eq!(d.len(), 2);
176 assert!(matches!(d[0], Object::Dict(_)));
177 if let Object::Dict(ref d) = d[0] {
178 assert_eq!(d.len(), 5);
179 assert!(matches!(d[0], Object::Pair(_)));
180 assert!(matches!(d[1], Object::Pair(_)));
181 assert!(matches!(d[2], Object::Pair(_)));
182 assert!(matches!(d[3], Object::Pair(_)));
183 assert!(matches!(d[4], Object::Pair(_)));
184 if let Object::Pair(ref p) = d[4] {
185 assert_eq!(p.key, "someOther");
186 if let Value::Str(value) = &p.value {
187 let r2 = Object::from_string(value);
188 assert!(r2.is_ok());
189 }
190 assert_eq!(
191 p.value,
192 Value::Str(
193 "anObject = {\n\
194 key = \"lr\",\n\
195 }\n"
196 .to_owned()
197 )
198 );
199 }
200 }
201 assert!(matches!(d[1], Object::Pair(_)));
202 if let Object::Pair(ref p) = d[1] {
203 assert_eq!(p.key, "combine");
204 assert_eq!(p.value, Value::Str("intersect".to_owned()));
205 }
206 }
207 } else {
208 unreachable!();
209 }
210}