-
Notifications
You must be signed in to change notification settings - Fork 14
/
parser.rs
94 lines (73 loc) · 2.42 KB
/
parser.rs
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
use std::{borrow::Cow, collections::HashMap, str::FromStr};
#[derive(Debug, PartialEq, Clone)]
pub enum JsonValue {
Null,
Boolean(bool),
Str(String),
Num(f64),
Array(Vec<JsonValue>),
Object(HashMap<String, JsonValue>),
}
peg::parser!(pub grammar parser() for str {
pub rule json() -> JsonValue
= _ value:value() _ { value }
rule _() = [' ' | '\t' | '\r' | '\n']*
rule value_separator() = _ "," _
rule value() -> JsonValue
= boolean() / null() / object() / array() / number() / string()
rule null() -> JsonValue
= "null" { JsonValue::Null }
rule boolean() -> JsonValue
= "true" { JsonValue::Boolean(true) }
/ "false" { JsonValue::Boolean(false) }
rule object() -> JsonValue
= "{" _ elements:(member() ** value_separator()) _ "}" {
JsonValue::Object(elements.into_iter().collect())
}
rule member() -> (String, JsonValue)
= key:raw_string() _ ":" _ value:value() { (key, value) }
rule array() -> JsonValue
= "[" _ elements:(value() ** value_separator()) _ "]" {
JsonValue::Array(elements)
}
rule string() -> JsonValue
= value:raw_string() { JsonValue::Str(value) }
rule raw_string() -> String
= "\"" slices:string_slice()* "\"" { slices.concat() }
/// A substring of same-kind (escaped or unescaped) characters
rule string_slice() -> Cow<'input, str>
= value:string_characters() { Cow::Borrowed(value) }
/ value:string_escapes() { Cow::Owned(value.into_iter().collect()) }
/// A substring of unescaped characters
rule string_characters() -> &'input str
= $([^ '\"' | '\\']+)
/// A substring of escaped characters
rule string_escapes() -> Vec<char>
= ("\\" value:string_escape_char() { value })+
/// Handles a single escape
rule string_escape_char() -> char
= "\"" { '"' }
/ "\\" { '\\' }
/ "/" { '/' }
/ "b" { '\x08' }
/ "f" { '\x0C' }
/ "n" { '\n' }
/ "r" { '\r' }
/ "t" { '\t' }
/ "u" digits:$(hex_digit()*<4>) { ?
let value = u16::from_str_radix(digits, 16).unwrap();
char::from_u32(value.into()).ok_or("invalid unicode escape")
}
rule hex_digit()
= ['0'..='9' | 'a'..='f' | 'A'..='F']
rule number() -> JsonValue
= "-"? value:$(int() frac()? exp()?) { ?
Ok(JsonValue::Num(f64::from_str(value).map_err(|_| "invalid number")?))
}
rule int()
= ['0'] / ['1'..='9']['0'..='9']*
rule exp()
= ("e" / "E") ("-" / "+")? ['0'..='9']*<1,>
rule frac()
= "." ['0'..='9']*<1,>
});