sim_codec/implementation/
domain_form.rs1use sim_kernel::{Expr, Symbol};
19
20#[derive(Clone, Debug, PartialEq)]
22pub enum DomainValue {
23 Form(DomainForm),
25 List(Vec<DomainValue>),
27 String(String),
29 Atom(String),
31}
32
33#[derive(Clone, Debug, PartialEq)]
35pub struct DomainForm {
36 pub name: String,
38 pub fields: Vec<(String, DomainValue)>,
40 pub positional: Vec<DomainValue>,
42}
43
44impl DomainForm {
45 pub fn field(&self, key: &str) -> Option<&DomainValue> {
47 self.fields
48 .iter()
49 .find_map(|(name, value)| (name == key).then_some(value))
50 }
51
52 pub fn atom(&self, key: &str) -> Result<&str, DomainFormError> {
54 match self.field(key) {
55 Some(DomainValue::Atom(value)) => Ok(value),
56 Some(_) => Err(DomainFormError::WrongFieldKind(key.to_owned())),
57 None => Err(DomainFormError::MissingField(key.to_owned())),
58 }
59 }
60
61 pub fn string(&self, key: &str) -> Result<&str, DomainFormError> {
63 match self.field(key) {
64 Some(DomainValue::String(value)) => Ok(value),
65 Some(_) => Err(DomainFormError::WrongFieldKind(key.to_owned())),
66 None => Err(DomainFormError::MissingField(key.to_owned())),
67 }
68 }
69
70 pub fn list(&self, key: &str) -> Result<&[DomainValue], DomainFormError> {
72 match self.field(key) {
73 Some(DomainValue::List(items)) => Ok(items),
74 Some(_) => Err(DomainFormError::WrongFieldKind(key.to_owned())),
75 None => Err(DomainFormError::MissingField(key.to_owned())),
76 }
77 }
78
79 pub fn form(&self, key: &str) -> Result<&DomainForm, DomainFormError> {
81 match self.field(key) {
82 Some(DomainValue::Form(value)) => Ok(value),
83 Some(_) => Err(DomainFormError::WrongFieldKind(key.to_owned())),
84 None => Err(DomainFormError::MissingField(key.to_owned())),
85 }
86 }
87
88 pub fn field_atom_or_string(&self, name: &str) -> Result<&str, DomainFormError> {
94 match self.field(name) {
95 Some(DomainValue::Atom(value) | DomainValue::String(value)) => Ok(value),
96 Some(_) => Err(DomainFormError::WrongFieldKind(name.to_owned())),
97 None => Err(DomainFormError::MissingField(name.to_owned())),
98 }
99 }
100
101 pub fn field_text(&self, name: &str) -> Result<String, DomainFormError> {
109 match self.field(name) {
110 Some(value) => Ok(value.render_text()),
111 None => Err(DomainFormError::MissingField(name.to_owned())),
112 }
113 }
114
115 pub fn to_expr_map(&self) -> Expr {
121 let mut entries = vec![(
122 Expr::Symbol(Symbol::new("form")),
123 Expr::String(self.name.clone()),
124 )];
125
126 if !self.positional.is_empty() {
127 entries.push((
128 Expr::Symbol(Symbol::new("args")),
129 Expr::List(self.positional.iter().map(DomainValue::to_expr).collect()),
130 ));
131 }
132
133 entries.extend(
134 self.fields
135 .iter()
136 .map(|(key, value)| (Expr::Symbol(Symbol::new(key.clone())), value.to_expr())),
137 );
138
139 Expr::Map(entries)
140 }
141}
142
143impl DomainValue {
144 pub fn as_form(&self) -> Result<&DomainForm, DomainFormError> {
149 match self {
150 DomainValue::Form(form) => Ok(form),
151 _ => Err(DomainFormError::WrongValueKind),
152 }
153 }
154
155 pub fn atom_or_string(&self) -> Result<&str, DomainFormError> {
160 match self {
161 DomainValue::Atom(value) | DomainValue::String(value) => Ok(value),
162 _ => Err(DomainFormError::WrongValueKind),
163 }
164 }
165
166 pub fn render_text(&self) -> String {
172 match self {
173 DomainValue::Form(form) => format_domain_form(form),
174 DomainValue::List(items) => format!(
175 "[{}]",
176 items
177 .iter()
178 .map(DomainValue::render_text)
179 .collect::<Vec<_>>()
180 .join(",")
181 ),
182 DomainValue::String(value) => {
183 format!("\"{}\"", value.replace('\\', "\\\\").replace('"', "\\\""))
184 }
185 DomainValue::Atom(value) => value.clone(),
186 }
187 }
188
189 pub fn to_expr(&self) -> Expr {
194 match self {
195 DomainValue::Form(form) => form.to_expr_map(),
196 DomainValue::List(items) => {
197 Expr::List(items.iter().map(DomainValue::to_expr).collect())
198 }
199 DomainValue::String(value) | DomainValue::Atom(value) => Expr::String(value.clone()),
200 }
201 }
202}
203
204#[derive(Clone, Debug, PartialEq, Eq)]
206pub enum DomainFormError {
207 ExpectedForm,
209 UnexpectedEof,
211 InvalidToken,
213 DuplicateField(String),
215 TrailingInput,
217 MissingField(String),
219 WrongFieldKind(String),
221 WrongValueKind,
224}
225
226pub fn parse_domain_form(input: &str) -> Result<DomainForm, DomainFormError> {
242 let mut parser = Parser { input, index: 0 };
243 parser.skip_ws();
244 if !parser.consume_str("#(") {
245 return Err(DomainFormError::ExpectedForm);
246 }
247 let form = parser.parse_form_body()?;
248 parser.skip_ws();
249 if parser.index != parser.input.len() {
250 return Err(DomainFormError::TrailingInput);
251 }
252 Ok(form)
253}
254
255pub fn format_domain_form(form: &DomainForm) -> String {
269 let mut out = String::from("#(");
270 out.push_str(&form.name);
271 for value in &form.positional {
272 out.push(' ');
273 format_value(value, &mut out);
274 }
275 for (key, value) in &form.fields {
276 out.push(' ');
277 out.push_str(key);
278 out.push('=');
279 format_value(value, &mut out);
280 }
281 out.push(')');
282 out
283}
284
285fn format_value(value: &DomainValue, out: &mut String) {
286 match value {
287 DomainValue::Form(form) => out.push_str(&format_domain_form(form)),
288 DomainValue::List(items) => {
289 out.push('[');
290 for (index, item) in items.iter().enumerate() {
291 if index > 0 {
292 out.push(',');
293 }
294 format_value(item, out);
295 }
296 out.push(']');
297 }
298 DomainValue::String(text) => {
299 out.push('"');
300 for ch in text.chars() {
301 if ch == '\\' || ch == '"' {
302 out.push('\\');
303 }
304 out.push(ch);
305 }
306 out.push('"');
307 }
308 DomainValue::Atom(text) => out.push_str(text),
309 }
310}
311
312struct Parser<'a> {
313 input: &'a str,
314 index: usize,
315}
316
317impl Parser<'_> {
318 fn parse_form_body(&mut self) -> Result<DomainForm, DomainFormError> {
319 let name = self.parse_ident()?;
320 let mut fields: Vec<(String, DomainValue)> = Vec::new();
321 let mut positional = Vec::new();
322 loop {
323 self.skip_ws();
324 if self.consume_char(')') {
325 break;
326 }
327 match self.peek_char() {
328 Some('#') | Some('[') | Some('"') => positional.push(self.parse_value()?),
329 _ => {
330 let atom = self.parse_atom()?;
331 if self.consume_char('=') {
332 if fields.iter().any(|(key, _)| key == &atom) {
333 return Err(DomainFormError::DuplicateField(atom));
334 }
335 fields.push((atom, self.parse_value()?));
336 } else {
337 positional.push(DomainValue::Atom(atom));
338 }
339 }
340 }
341 }
342 Ok(DomainForm {
343 name,
344 fields,
345 positional,
346 })
347 }
348
349 fn parse_value(&mut self) -> Result<DomainValue, DomainFormError> {
350 self.skip_ws();
351 if self.consume_str("#(") {
352 return self.parse_form_body().map(DomainValue::Form);
353 }
354 if self.consume_char('[') {
355 return self.parse_list();
356 }
357 if self.peek_char() == Some('"') {
358 return self.parse_string().map(DomainValue::String);
359 }
360 self.parse_atom().map(DomainValue::Atom)
361 }
362
363 fn parse_list(&mut self) -> Result<DomainValue, DomainFormError> {
364 let mut items = Vec::new();
365 loop {
366 self.skip_ws();
367 if self.consume_char(']') {
368 break;
369 }
370 items.push(self.parse_value()?);
371 self.skip_ws();
372 if self.consume_char(',') {
373 continue;
374 }
375 self.expect_char(']')?;
376 break;
377 }
378 Ok(DomainValue::List(items))
379 }
380
381 fn parse_string(&mut self) -> Result<String, DomainFormError> {
382 self.expect_char('"')?;
383 let mut out = String::new();
384 while let Some(ch) = self.next_char() {
385 match ch {
386 '"' => return Ok(out),
387 '\\' => out.push(self.next_char().ok_or(DomainFormError::UnexpectedEof)?),
388 other => out.push(other),
389 }
390 }
391 Err(DomainFormError::UnexpectedEof)
392 }
393
394 fn parse_atom(&mut self) -> Result<String, DomainFormError> {
395 let start = self.index;
396 while let Some(ch) = self.peek_char() {
397 if ch.is_whitespace() || [',', ')', ']', '='].contains(&ch) {
398 break;
399 }
400 self.index += ch.len_utf8();
401 }
402 if self.index == start {
403 return Err(DomainFormError::UnexpectedEof);
404 }
405 Ok(self.input[start..self.index].to_owned())
406 }
407
408 fn parse_ident(&mut self) -> Result<String, DomainFormError> {
409 let atom = self.parse_atom()?;
410 if atom
411 .chars()
412 .all(|ch| ch.is_ascii_alphanumeric() || ch == '_' || ch == '-')
413 {
414 Ok(atom)
415 } else {
416 Err(DomainFormError::InvalidToken)
417 }
418 }
419
420 fn expect_char(&mut self, expected: char) -> Result<(), DomainFormError> {
421 match self.next_char() {
422 Some(ch) if ch == expected => Ok(()),
423 Some(_) => Err(DomainFormError::InvalidToken),
424 None => Err(DomainFormError::UnexpectedEof),
425 }
426 }
427
428 fn consume_char(&mut self, expected: char) -> bool {
429 if self.peek_char() == Some(expected) {
430 self.index += expected.len_utf8();
431 true
432 } else {
433 false
434 }
435 }
436
437 fn consume_str(&mut self, expected: &str) -> bool {
438 if self.input[self.index..].starts_with(expected) {
439 self.index += expected.len();
440 true
441 } else {
442 false
443 }
444 }
445
446 fn skip_ws(&mut self) {
447 while let Some(ch) = self.peek_char() {
448 if ch.is_whitespace() {
449 self.index += ch.len_utf8();
450 } else {
451 break;
452 }
453 }
454 }
455
456 fn peek_char(&self) -> Option<char> {
457 self.input[self.index..].chars().next()
458 }
459
460 fn next_char(&mut self) -> Option<char> {
461 let ch = self.peek_char()?;
462 self.index += ch.len_utf8();
463 Some(ch)
464 }
465}