1use indexmap::IndexMap;
6use serde::Deserialize;
7
8use super::types::{Grammar, Precedence, PrecedenceEntry, Rule};
9
10#[derive(Debug)]
12pub enum GrammarError {
13 Json(serde_json::Error),
14 Binary(postcard::Error),
15}
16
17impl std::fmt::Display for GrammarError {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 match self {
20 Self::Json(e) => write!(f, "JSON parse error: {e}"),
21 Self::Binary(e) => write!(f, "binary decode error: {e}"),
22 }
23 }
24}
25
26impl std::error::Error for GrammarError {
27 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
28 match self {
29 Self::Json(e) => Some(e),
30 Self::Binary(e) => Some(e),
31 }
32 }
33}
34
35impl Grammar {
36 pub fn from_json(json: &str) -> Result<Self, GrammarError> {
38 let raw: RawGrammar = serde_json::from_str(json).map_err(GrammarError::Json)?;
39 Ok(raw.into())
40 }
41}
42
43#[derive(Debug, Deserialize)]
45struct RawGrammar {
46 name: String,
47 rules: IndexMap<String, RawRule>,
48 #[serde(default)]
49 extras: Vec<RawRule>,
50 #[serde(default)]
51 precedences: Vec<Vec<RawPrecedenceEntry>>,
52 #[serde(default)]
53 conflicts: Vec<Vec<String>>,
54 #[serde(default)]
55 externals: Vec<RawRule>,
56 #[serde(default, rename = "inline")]
57 inline_rules: Vec<String>,
58 #[serde(default)]
59 supertypes: Vec<String>,
60 #[serde(default)]
61 word: Option<String>,
62 #[serde(default)]
63 reserved: IndexMap<String, Vec<RawRule>>,
64 #[serde(default)]
65 inherits: Option<String>,
66}
67
68impl From<RawGrammar> for Grammar {
69 fn from(raw: RawGrammar) -> Self {
70 Self {
73 name: raw.name,
74 rules: raw.rules.into_iter().map(|(k, v)| (k, v.into())).collect(),
75 extras: raw.extras.into_iter().map(Into::into).collect(),
76 precedences: raw
77 .precedences
78 .into_iter()
79 .map(|v| v.into_iter().map(Into::into).collect())
80 .collect(),
81 conflicts: raw.conflicts,
82 externals: raw.externals.into_iter().map(Into::into).collect(),
83 inline: raw.inline_rules,
84 supertypes: raw.supertypes,
85 word: raw.word,
86 reserved: raw
87 .reserved
88 .into_iter()
89 .map(|(k, v)| (k, v.into_iter().map(Into::into).collect()))
90 .collect(),
91 inherits: raw.inherits,
92 }
93 }
94}
95
96#[derive(Debug, Deserialize)]
98#[serde(tag = "type")]
99#[allow(clippy::upper_case_acronyms, non_camel_case_types)]
100enum RawRule {
101 BLANK,
102 STRING {
103 value: String,
104 },
105 PATTERN {
106 value: String,
107 #[serde(default)]
108 flags: Option<String>,
109 },
110 SYMBOL {
111 name: String,
112 },
113 SEQ {
114 members: Vec<RawRule>,
115 },
116 CHOICE {
117 members: Vec<RawRule>,
118 },
119 REPEAT {
120 content: Box<RawRule>,
121 },
122 REPEAT1 {
123 content: Box<RawRule>,
124 },
125 FIELD {
126 name: String,
127 content: Box<RawRule>,
128 },
129 ALIAS {
130 content: Box<RawRule>,
131 value: String,
132 named: bool,
133 },
134 TOKEN {
135 content: Box<RawRule>,
136 },
137 IMMEDIATE_TOKEN {
138 content: Box<RawRule>,
139 },
140 PREC {
141 value: RawPrecedence,
142 content: Box<RawRule>,
143 },
144 PREC_LEFT {
145 value: RawPrecedence,
146 content: Box<RawRule>,
147 },
148 PREC_RIGHT {
149 value: RawPrecedence,
150 content: Box<RawRule>,
151 },
152 PREC_DYNAMIC {
153 value: i32,
154 content: Box<RawRule>,
155 },
156 RESERVED {
157 context_name: String,
158 content: Box<RawRule>,
159 },
160}
161
162impl From<RawRule> for Rule {
163 fn from(raw: RawRule) -> Self {
164 #[allow(clippy::boxed_local)] fn conv(content: Box<RawRule>) -> Box<Rule> {
166 Box::new(Rule::from(*content))
167 }
168
169 match raw {
170 RawRule::BLANK => Rule::Blank,
171 RawRule::STRING { value } => Rule::String(value),
172 RawRule::PATTERN { value, flags } => Rule::Pattern { value, flags },
173 RawRule::SYMBOL { name } => Rule::Symbol(name),
174 RawRule::SEQ { members } => Rule::Seq(members.into_iter().map(Into::into).collect()),
175 RawRule::CHOICE { members } => {
176 Rule::Choice(members.into_iter().map(Into::into).collect())
177 }
178 RawRule::REPEAT { content } => Rule::Repeat(conv(content)),
179 RawRule::REPEAT1 { content } => Rule::Repeat1(conv(content)),
180 RawRule::FIELD { name, content } => Rule::Field {
181 name,
182 content: conv(content),
183 },
184 RawRule::ALIAS {
185 content,
186 value,
187 named,
188 } => Rule::Alias {
189 content: conv(content),
190 value,
191 named,
192 },
193 RawRule::TOKEN { content } => Rule::Token(conv(content)),
194 RawRule::IMMEDIATE_TOKEN { content } => Rule::ImmediateToken(conv(content)),
195 RawRule::PREC { value, content } => Rule::Prec {
196 value: value.into(),
197 content: conv(content),
198 },
199 RawRule::PREC_LEFT { value, content } => Rule::PrecLeft {
200 value: value.into(),
201 content: conv(content),
202 },
203 RawRule::PREC_RIGHT { value, content } => Rule::PrecRight {
204 value: value.into(),
205 content: conv(content),
206 },
207 RawRule::PREC_DYNAMIC { value, content } => Rule::PrecDynamic {
208 value,
209 content: conv(content),
210 },
211 RawRule::RESERVED {
212 context_name,
213 content,
214 } => Rule::Reserved {
215 context_name,
216 content: conv(content),
217 },
218 }
219 }
220}
221
222#[derive(Debug, Deserialize)]
224#[serde(untagged)]
225enum RawPrecedence {
226 Integer(i32),
227 Name(String),
228}
229
230impl From<RawPrecedence> for Precedence {
231 fn from(raw: RawPrecedence) -> Self {
232 match raw {
233 RawPrecedence::Integer(n) => Precedence::Integer(n),
234 RawPrecedence::Name(s) => Precedence::Name(s),
235 }
236 }
237}
238
239#[derive(Debug, Deserialize)]
241#[serde(tag = "type")]
242#[allow(clippy::upper_case_acronyms)]
243enum RawPrecedenceEntry {
244 STRING { value: String },
245 SYMBOL { name: String },
246}
247
248impl From<RawPrecedenceEntry> for PrecedenceEntry {
249 fn from(raw: RawPrecedenceEntry) -> Self {
250 match raw {
251 RawPrecedenceEntry::STRING { value } => PrecedenceEntry::Name(value),
252 RawPrecedenceEntry::SYMBOL { name } => PrecedenceEntry::Symbol(name),
253 }
254 }
255}