1use pest::Parser;
2use pest::iterators::Pair;
3use pest_derive::Parser;
4use std::collections::HashMap;
5use crate::ast::*;
6
7#[derive(Parser)]
8#[grammar = "src/grammar.pest"]
9pub struct CadlParser;
11
12pub fn parse_file(input: &str) -> Result<CadlDocument, String> {
13 let mut pairs = CadlParser::parse(Rule::file, input)
14 .map_err(|e| format!("{}", e))?;
15
16 let mut doc = CadlDocument {
17 interfaces: Vec::new(),
18 implementations: Vec::new(),
19 constraints: Vec::new(),
20 top_level_annotations: Vec::new(),
21 };
22
23 for pair in pairs.next().unwrap().into_inner() {
24 match pair.as_rule() {
25 Rule::interface_def => {
26 doc.interfaces.push(parse_interface(pair));
27 }
28 Rule::impl_def => {
29 doc.implementations.push(parse_impl(pair));
30 }
31 Rule::annotation => {
32 let ann = parse_annotation(pair);
33 if let Annotation::Unknown(name, map) = &ann {
37 if name == "constraints" {
38 doc.constraints.push(ConstraintDef {
39 name: None,
40 rules: Vec::new(), other: map.clone(),
42 });
43 continue;
44 }
45 }
46 doc.top_level_annotations.push(ann);
47 }
48 Rule::EOI => (),
49 _ => (),
50 }
51 }
52
53 Ok(doc)
54}
55
56fn parse_interface(pair: Pair<Rule>) -> InterfaceDef {
57 let mut inner = pair.into_inner();
58 let name = inner.next().unwrap().as_str().to_string();
63 let content = inner.next().unwrap();
64
65 let mut methods = Vec::new();
66 let mut annotations = Vec::new();
67
68 for item in content.into_inner() {
69 match item.as_rule() {
70 Rule::method_def => {
71 methods.push(parse_method(item));
72 }
73 Rule::annotation => {
74 annotations.push(parse_annotation(item));
75 }
76 _ => {}
77 }
78 }
79
80 InterfaceDef {
81 name,
82 methods,
83 annotations,
84 }
85}
86
87fn parse_method(pair: Pair<Rule>) -> MethodDef {
88 let mut inner = pair.into_inner();
89 let name = inner.next().unwrap().as_str().to_string();
90
91 let next = inner.next().unwrap();
93 let (params, return_type) = if next.as_rule() == Rule::params {
94 let params = parse_params(next);
95 (params, inner.next().unwrap().as_str().trim().to_string())
96 } else {
97 (Vec::new(), next.as_str().trim().to_string())
98 };
99
100 MethodDef {
101 name,
102 params,
103 return_type,
104 }
105}
106
107fn parse_params(pair: Pair<Rule>) -> Vec<ParamDef> {
108 let mut params = Vec::new();
109 for p in pair.into_inner() {
110 let mut inner = p.into_inner();
111 let name = inner.next().unwrap().as_str().to_string();
112 let type_name = inner.next().unwrap().as_str().to_string();
113 params.push(ParamDef { name, type_name });
114 }
115 params
116}
117
118fn parse_annotation(pair: Pair<Rule>) -> Annotation {
119 let mut inner = pair.into_inner();
120 let name = inner.next().unwrap().as_str().to_string();
121 let content = inner.next().unwrap(); let map = parse_object_like(content);
124
125 match name.as_str() {
126 "contract" => Annotation::Contract(from_map_contract(map)),
127 "effects" => Annotation::Effects(from_map_effects(map)),
128 "abi" => Annotation::Abi(from_map_abi(map)),
129 "data_format" => Annotation::DataFormat(from_map_data_format(map)),
130 "resources" => Annotation::Resources(from_map_resources(map)),
131 "protocol" => Annotation::Protocol(from_map_protocol(map)),
132 "numerical" => Annotation::Numerical(from_map_numerical(map)),
133 "observability" => Annotation::Observability(from_map_observability(map)),
134 "permissions" => Annotation::Permissions(from_map_permissions(map)),
135 _ => Annotation::Unknown(name, map),
136 }
137}
138
139fn parse_object_like(pair: Pair<Rule>) -> HashMap<String, Value> {
140 let mut map = HashMap::new();
141 for item in pair.into_inner() {
142 match item.as_rule() {
143 Rule::pair => {
144 let mut inner = item.into_inner();
145 let key = inner.next().unwrap().as_str().to_string();
146 let val = parse_value(inner.next().unwrap());
147 map.insert(key, val);
148 }
149 Rule::named_block => {
150 let mut inner = item.into_inner();
151 let key = inner.next().unwrap().as_str().to_string();
152 let content = inner.next().unwrap();
153 let val = Value::Object(parse_object_like(content));
154 map.insert(key, val);
155 }
156 _ => {}
158 }
159 }
160 map
161}
162
163fn parse_value(pair: Pair<Rule>) -> Value {
164 let inner = pair.into_inner().next().unwrap();
165 match inner.as_rule() {
166 Rule::string => {
167 let s = inner.as_str();
169 Value::String(s[1..s.len()-1].to_string())
170 },
171 Rule::number => {
172 let n = inner.as_str().parse::<f64>().unwrap_or(0.0);
173 Value::Number(n)
174 },
175 Rule::boolean => {
176 let b = inner.as_str() == "true";
177 Value::Bool(b)
178 },
179 Rule::identifier => Value::String(inner.as_str().to_string()),
180 Rule::array => {
181 let vals = inner.into_inner().map(parse_value).collect();
182 Value::Array(vals)
183 },
184 Rule::object => {
185 Value::Object(parse_object_like(inner))
186 },
187 Rule::null_val => Value::String("null".to_string()),
188 _ => Value::String(inner.as_str().to_string()),
189 }
190}
191
192fn parse_impl(pair: Pair<Rule>) -> ImplDef {
193 let mut inner = pair.into_inner();
194 let name = inner.next().unwrap().as_str().to_string();
195 let content = inner.next().unwrap();
196
197 let mut attributes = HashMap::new();
198 let mut annotations = Vec::new();
199
200 for item in content.into_inner() {
201 match item.as_rule() {
202 Rule::pair => {
203 let mut p_inner = item.into_inner();
204 let key = p_inner.next().unwrap().as_str().to_string();
205 let val = parse_value(p_inner.next().unwrap());
206 attributes.insert(key, val);
207 }
208 Rule::annotation => {
209 annotations.push(parse_annotation(item));
210 }
211 _ => {}
212 }
213 }
214
215 ImplDef {
216 name,
217 attributes,
218 annotations,
219 }
220}
221
222fn from_map_contract(mut map: HashMap<String, Value>) -> ContractDef {
224 ContractDef {
225 codec: extract_string(&mut map, "codec"),
226 profile: extract_string(&mut map, "profile"),
227 container: extract_string(&mut map, "container"),
228 ensures: extract_string_list(&mut map, "ensures"),
229 complexity: extract_string_map(&mut map, "complexity"),
230 other: map,
231 }
232}
233
234fn from_map_effects(mut map: HashMap<String, Value>) -> EffectsDef {
235 EffectsDef {
236 concurrency: extract_string(&mut map, "concurrency"),
237 io: extract_string_list(&mut map, "io"),
238 memory: extract_string(&mut map, "memory"),
239 mutates: extract_string_list(&mut map, "mutates"),
240 reads: extract_string_list(&mut map, "reads"),
241 blocking: extract_string(&mut map, "blocking"),
242 async_exec: extract_string(&mut map, "async"),
243 other: map,
244 }
245}
246
247fn from_map_abi(mut map: HashMap<String, Value>) -> AbiDef {
249 AbiDef {
250 string_encoding: extract_string(&mut map, "string_encoding"),
251 memory_ownership: extract_string_map(&mut map, "memory_ownership"),
252 error_model: extract_string(&mut map, "error_model"),
253 other: map,
254 }
255}
256
257fn from_map_data_format(mut map: HashMap<String, Value>) -> DataFormatDef {
258 DataFormatDef {
259 input: extract_data_format_spec_map(&mut map, "input"),
260 output: extract_data_format_spec_map(&mut map, "output"),
261 }
262}
263
264fn extract_data_format_spec_map(map: &mut HashMap<String, Value>, key: &str) -> HashMap<String, DataFormatSpec> {
265 match map.remove(key) {
266 Some(Value::Object(obj)) => obj.into_iter().map(|(k, v)| {
267 let spec = match v {
268 Value::Object(mut inner_map) => DataFormatSpec {
269 format: extract_string(&mut inner_map, "format"),
270 schema: extract_string(&mut inner_map, "schema"),
271 value_range: extract_number_list(&mut inner_map, "value_range"),
272 other: inner_map,
273 },
274 _ => DataFormatSpec {
275 format: None,
276 schema: None,
277 value_range: None,
278 other: HashMap::new(),
279 }
280 };
281 (k, spec)
282 }).collect(),
283 _ => HashMap::new(),
284 }
285}
286
287fn from_map_resources(mut map: HashMap<String, Value>) -> ResourcesDef {
288 ResourcesDef {
289 requires: extract_string_list(&mut map, "requires"),
290 memory: extract_string_map(&mut map, "memory"),
291 cpu_time: extract_string(&mut map, "cpu_time"),
292 gpu: extract_string_map(&mut map, "gpu"),
293 other: map,
294 }
295}
296
297fn from_map_protocol(mut map: HashMap<String, Value>) -> ProtocolDef {
298 ProtocolDef {
299 states: extract_string_list(&mut map, "states"),
300 initial: extract_string(&mut map, "initial"),
301 transitions: extract_string_list(&mut map, "transitions"),
302 other: map,
303 }
304}
305
306fn from_map_numerical(mut map: HashMap<String, Value>) -> NumericalDef {
307 NumericalDef {
308 precision: extract_string(&mut map, "precision"),
309 error_bounds: extract_string_map(&mut map, "error_bounds"),
310 other: map,
311 }
312}
313
314fn from_map_observability(mut map: HashMap<String, Value>) -> ObservabilityDef {
315 ObservabilityDef {
317 logging: extract_map(&mut map, "logging"),
318 metrics: extract_map(&mut map, "metrics"),
319 tracing: extract_map(&mut map, "tracing"),
320 }
321}
322
323fn from_map_permissions(mut map: HashMap<String, Value>) -> PermissionsDef {
324 PermissionsDef {
325 allow: extract_string_list(&mut map, "allow"),
326 deny: extract_string_list(&mut map, "deny"),
327 sandbox: extract_string_map(&mut map, "sandbox"),
328 }
329}
330
331fn extract_string(map: &mut HashMap<String, Value>, key: &str) -> Option<String> {
333 match map.remove(key) {
334 Some(Value::String(s)) => Some(s),
335 Some(v) => Some(format!("{:?}", v)), None => None,
337 }
338}
339
340fn extract_string_list(map: &mut HashMap<String, Value>, key: &str) -> Vec<String> {
341 match map.remove(key) {
342 Some(Value::Array(arr)) => arr.into_iter().filter_map(|v| match v {
343 Value::String(s) => Some(s),
344 _ => None,
345 }).collect(),
346 _ => Vec::new(),
347 }
348}
349
350fn extract_string_map(map: &mut HashMap<String, Value>, key: &str) -> HashMap<String, String> {
351 match map.remove(key) {
352 Some(Value::Object(obj)) => obj.into_iter().map(|(k, v)| (k, match v {
353 Value::String(s) => s,
354 _ => format!("{:?}", v),
355 })).collect(),
356 _ => HashMap::new(),
357 }
358}
359
360fn extract_map(map: &mut HashMap<String, Value>, key: &str) -> HashMap<String, Value> {
361 match map.remove(key) {
362 Some(Value::Object(obj)) => obj,
363 _ => HashMap::new(),
364 }
365}
366
367fn extract_number_list(map: &mut HashMap<String, Value>, key: &str) -> Option<Vec<f64>> {
368 match map.remove(key) {
369 Some(Value::Array(arr)) => Some(arr.into_iter().filter_map(|v| match v {
370 Value::Number(n) => Some(n),
371 _ => None,
372 }).collect()),
373 _ => None,
374 }
375}