mech_syntax/
parser.rs

1// Parser
2// ========
3
4/// Sections:
5///   1. Prelude
6///   2. Parser combinators
7///   3. Recovery functions
8///   4. Public interface
9///   5. Error reporting
10
11// 1. Prelude
12// ------------
13
14use crate::*;
15use crate::functions::function_define;
16
17use mech_core::{MechError, MechErrorKind, ParserErrorContext, ParserErrorReport};
18use mech_core::nodes::*;
19use mech_core::nodes::{SectionElement, MechString, Table};
20
21#[cfg(not(feature = "no-std"))] use core::fmt;
22#[cfg(feature = "no-std")] use alloc::fmt;
23#[cfg(feature = "no-std")] use alloc::string::String;
24#[cfg(feature = "no-std")] use alloc::vec::Vec;
25use nom::{
26  IResult,
27  branch::alt,
28  sequence::tuple as nom_tuple,
29  combinator::{opt, eof},
30  multi::{many1, many_till, many0, separated_list1, separated_list0},
31  Err,
32  Err::Failure
33};
34
35use std::collections::HashMap;
36use colored::*;
37
38//use crate::*;
39use crate::{
40  TextFormatter,
41  ParseError,
42  ParseString,
43  ParseErrorDetail,
44  graphemes,
45  ParseResult,
46};
47
48// 2. Parser combinators
49// -----------------------
50
51/// Convert output of any parser into ParserNode::Null.
52/// Useful for working with `alt` combinator and error recovery functions.
53pub fn null<'a, F, O>(mut parser: F) ->
54  impl FnMut(ParseString<'a>) -> ParseResult<()>
55where
56  F: FnMut(ParseString<'a>) -> ParseResult<O>
57{
58  move |input: ParseString| match parser(input) {
59    Ok((remaining, _)) => Ok((remaining, ())),
60    Err(Err::Error(e)) => Err(Err::Error(e)),
61    Err(Err::Failure(e)) => Err(Err::Failure(e)),
62    x => panic!("Err::Incomplete is not supported"),
63  }
64}
65
66/// For parser p, run p and also output the range that p has matched
67/// upon success.
68pub fn range<'a, F, O>(mut parser: F) ->
69  impl FnMut(ParseString<'a>) -> ParseResult<(O, SourceRange)>
70where
71  F: FnMut(ParseString<'a>) -> ParseResult<O>
72{
73  move |input: ParseString| {
74    let start = input.loc();
75    match parser(input) {
76      Ok((remaining, o)) => {
77        let rng = SourceRange { start, end: remaining.loc(), };
78        Ok((remaining, (o, rng)))
79      },
80      Err(e) => Err(e),
81    }
82  }
83}
84
85#[macro_export]
86macro_rules! label {
87  ($parser:expr, $msg:expr) => {
88    (label_without_recovery($parser, ParseErrorDetail {
89      message: $msg, annotation_rngs: vec![]
90    }))
91  };
92
93  ($parser:expr, $msg:expr, $($rngs:expr),+) => {
94    (label_without_recovery($parser, ParseErrorDetail {
95      message: $msg, annotation_rngs: vec![$($rngs),+]
96    }))
97  };
98}
99
100#[macro_export]
101macro_rules! labelr {
102  ($parser:expr, $recovery_fn:expr, $msg:expr) => {
103    (label_with_recovery($parser, $recovery_fn, ParseErrorDetail {
104      message: $msg, annotation_rngs: vec![]
105    }))
106  };
107
108  ($parser:expr, $recovery_fn:expr, $msg:expr, $($rngs:expr),+) => {
109    (label_with_recovery($parser, $recovery_fn, ParseErrorDetail {
110      message: $msg, annotation_rngs: vec![$($rngs),+]
111    }))
112  };
113}
114
115/// Label without recovery function. Upgrade Err::Error to Err:Failure
116/// and override its context information.
117pub fn label_without_recovery<'a, F, O>(
118  mut parser: F,
119  error_detail: ParseErrorDetail,
120) ->
121  impl FnMut(ParseString<'a>) -> ParseResult<O>
122where
123  F: FnMut(ParseString<'a>) -> ParseResult<O>
124{
125  move |mut input: ParseString| {
126    let start = input.loc();
127    match parser(input) {
128      Err(Err::Error(mut e)) => {
129        e.cause_range = SourceRange { start, end: e.cause_range.end };
130        e.error_detail = error_detail.clone();
131        Err(Err::Failure(e))
132      }
133      x => x,
134    }
135  }
136}
137
138/// Label with recovery function. In addition to upgrading errors, the
139/// error is logged and recovery function will be run as an attempt to
140/// synchronize parser state.
141pub fn label_with_recovery<'a, F, O>(
142  mut parser: F,
143  mut recovery_fn: fn(ParseString<'a>) -> ParseResult<O>,
144  error_detail: ParseErrorDetail,
145) ->
146  impl FnMut(ParseString<'a>) -> ParseResult<O>
147where
148  F: FnMut(ParseString<'a>) -> ParseResult<O>
149{
150  move |mut input: ParseString| {
151    let start = input.loc();
152    match parser(input) {
153      Err(Err::Error(mut e)) => {
154        e.cause_range = SourceRange { start, end: e.cause_range.end };
155        e.error_detail = error_detail.clone();
156        e.log();
157        recovery_fn(e.remaining_input)
158      }
159      Err(Err::Failure(mut e)) => {
160        e.log();
161        recovery_fn(e.remaining_input)
162      },
163      x => x,
164    }
165  }
166}
167
168/// For parser p, return the `!!p` peek parsing expression.
169pub fn is<'a, F, O>(mut parser: F) ->
170  impl FnMut(ParseString<'a>) -> ParseResult<O>
171where
172  F: FnMut(ParseString<'a>) -> ParseResult<O>
173{
174  move |input: ParseString| {
175    let input_clone = input.clone();
176    match parser(input_clone) {
177      Ok((_, o)) => Ok((input, o)),
178      _ => Err(Err::Error(ParseError::new(input, "Unexpected character"))),
179    }
180  }
181}
182
183/// For parser p, return the `!p` peek parsing expression.
184pub fn is_not<'a, F, E>(mut parser: F) ->
185  impl FnMut(ParseString<'a>) -> ParseResult<()>
186where
187  F: FnMut(ParseString<'a>) -> ParseResult<E>
188{
189  move |input: ParseString| {
190    let input_clone = input.clone();
191    match parser(input_clone) {
192      Err(Err::Failure(_)) |
193      Err(Err::Error(_)) => Ok((input, ())),
194      _ => Err(Err::Error(ParseError::new(input, "Unexpected character")))
195    }
196  }
197}
198
199/// Return a terminal parsing expression that consumes `tag` from input.
200pub fn tag(tag: &'static str) -> impl Fn(ParseString) -> ParseResult<String> {
201  move |mut input: ParseString| {
202    if input.is_empty() {
203      return Err(nom::Err::Error(ParseError::new(input, "Unexpected eof")));
204    }
205    if let Some(matched) = input.consume_tag(tag) {
206      Ok((input, matched))
207    } else {
208      Err(nom::Err::Error(ParseError::new(input, "Unexpected char")))
209    }
210  }
211}
212
213// 3. Recovery functions
214// -----------------------
215
216// skip_till_eol := (!new_line, any)* ;
217pub fn skip_till_eol(input: ParseString) -> ParseResult<()> {
218  let (input, _) = many0(nom_tuple((
219    is_not(new_line),
220    any,
221  )))(input)?;
222  Ok((input, ()))
223}
224
225// skip_past_eol := skip_till_eol, new_line ;
226fn skip_past_eol(input: ParseString) -> ParseResult<()> {
227  let (input, _) = skip_till_eol(input)?;
228  let (input, _) = new_line(input)?;
229  Ok((input, ()))
230}
231
232// skip_till_section_element := skip_past_eol, (!section_element, skip_past_eol)* ;
233fn skip_till_section_element(input: ParseString) -> ParseResult<()> {
234  if input.is_empty() {
235    return Ok((input, ()));
236  }
237  let (input, _) = skip_past_eol(input)?;
238  let (input, _) = many0(nom_tuple((
239    is_not(section_element),
240    skip_past_eol,
241  )))(input)?;
242  Ok((input, ()))
243}
244
245/*
246fn skip_till_section_element2(input: ParseString) -> ParseResult<ParserNode> {
247  if input.len() == 0 {
248    return Ok((input, ParserNode::Error));
249  }
250  let (input, _) = skip_past_eol(input)?;
251  let (input, _) = many0(nom_tuple((
252    is_not(section_element2),
253    skip_past_eol,
254  )))(input)?;
255  Ok((input, ParserNode::Error))
256}
257
258fn skip_till_section_element3(input: ParseString) -> ParseResult<ParserNode> {
259  if input.len() == 0 {
260    return Ok((input, ParserNode::Error));
261  }
262  let (input, _) = skip_past_eol(input)?;
263  let (input, _) = many0(nom_tuple((
264    is_not(section_element3),
265    skip_past_eol,
266  )))(input)?;
267  Ok((input, ParserNode::Error))
268}*/
269
270// skip_spaces := space* ;
271pub fn skip_spaces(input: ParseString) -> ParseResult<()> {
272  let (input, _) = many0(space)(input)?;
273  Ok((input, ()))
274}
275
276// skip_nil := ;
277pub fn skip_nil(input: ParseString) -> ParseResult<()> {
278  Ok((input, ()))
279}
280
281// skip_empty_mech_directive := ;
282pub fn skip_empty_mech_directive(input: ParseString) -> ParseResult<String> {
283  Ok((input, String::from("mech:")))
284}
285
286// 4. Public interface
287// ---------------------
288
289// mech_code_alt := fsm_specification | fsm_implementation | function_define | statement | expression | comment ;
290pub fn mech_code_alt(input: ParseString) -> ParseResult<MechCode> {
291  let (input, _) = whitespace0(input)?;
292  match fsm_specification(input.clone()) {
293    Ok((input, fsm_spec)) => {return Ok((input, MechCode::FsmSpecification(fsm_spec)));},
294    //Err(Failure(err)) => { return Err(Failure(err)); }
295    _ => () 
296  }
297  match fsm_implementation(input.clone()) {
298    Ok((input, fsm_impl)) => {return Ok((input, MechCode::FsmImplementation(fsm_impl)));},
299    //Err(Failure(err)) => { return Err(Failure(err)); }
300    _ => ()
301  }
302  match function_define(input.clone()) {
303    Ok((input, fxn_def)) => {return Ok((input, MechCode::FunctionDefine(fxn_def)));},
304    //Err(Failure(err)) => { return Err(Failure(err)); }
305    _ => () 
306  }
307  match statement(input.clone()) {
308    Ok((input, stmt)) => { return Ok((input, MechCode::Statement(stmt)));},
309    //Err(Failure(err)) => { return Err(Failure(err)); }
310    _ => ()
311  }
312  match expression(input.clone()) {
313    Ok((input, expr)) => {return Ok((input, MechCode::Expression(expr)));},
314    _ => ()
315  }
316  match comment(input.clone()) {
317    Ok((input, cmnt)) => {return Ok((input, MechCode::Comment(cmnt)));},
318    Err(err) => {return Err(err);}
319  }
320}
321
322// mech_code := mech_code_alt, ("\n" | ";" | comment) ;
323pub fn mech_code(input: ParseString) -> ParseResult<(MechCode,Option<Comment>)> {
324  let (input, code) = mech_code_alt(input)?;
325  let (input, _) = many0(space_tab)(input)?;
326  let (input, cmmnt) = opt(tuple((opt(semicolon),many0(space_tab),comment)))(input)?;
327  let (input, _) = alt((null(new_line), null(semicolon)))(input)?;
328  let (input, _) = whitespace0(input)?;
329  let cmmt = match cmmnt {
330    Some((_, _, cmnt)) => Some(cmnt),
331    None => None,
332  };
333  Ok((input,(code,cmmt)))
334}
335
336
337// program := title?, body ;
338pub fn program(input: ParseString) -> ParseResult<Program> {
339  let msg = "Expects program body";
340  let (input, _) = whitespace0(input)?;
341  let (input, title) = opt(title)(input)?;
342  //let (input, body) = labelr!(body, skip_nil, msg)(input)?;
343  let (input, body) = body(input)?;
344  let (input, _) = whitespace0(input)?;
345  Ok((input, Program{title, body}))
346}
347
348// parse_mech := program | statement ;
349pub fn parse_mech(input: ParseString) -> ParseResult<Program> {
350  //let (input, mech) = alt((program, statement))(input)?;
351  //Ok((input, ParserNode::Root { children: vec![mech] }))
352  let (input, mech) = program(input)?;
353  Ok((input, mech))
354}
355
356// 5. Error Reporting
357// --------------------
358
359/// Print formatted error message.
360pub fn print_err_report(text: &str, report: &ParserErrorReport) {
361  let msg = TextFormatter::new(text).format_error(report);
362  println!("{}", msg);
363}
364
365pub fn parse_grammar(text: &str) -> MResult<Grammar> {
366  // remove all whitespace from the input string
367  let text_no_Ws = &text.replace(" ", "").replace("\n", "").replace("\r", "").replace("\t", "");
368  let graphemes = graphemes::init_source(text_no_Ws);
369  let mut result_node = None;
370  let mut error_log: Vec<(SourceRange, ParseErrorDetail)> = vec![];
371
372  // Do parse
373  let remaining: ParseString = match grammar(ParseString::new(&graphemes)) {
374    // Got a parse tree, however there may be errors
375    Ok((mut remaining_input, parse_tree)) => {
376      error_log.append(&mut remaining_input.error_log);
377      result_node = Some(parse_tree);
378      remaining_input
379    },
380    // Parsing failed and could not be recovered. No parse tree was created in this case
381    Err(err) => {
382      match err {
383        Err::Error(mut e) | Err::Failure(mut e) => {
384          error_log.append(&mut e.remaining_input.error_log);
385          error_log.push((e.cause_range, e.error_detail));
386          e.remaining_input
387        },
388        Err::Incomplete(_) => panic!("nom::Err::Incomplete is not supported!"),
389      }
390    },
391  };
392  // Check if all inputs were parsed
393  if remaining.len() != 0 {
394    let e = ParseError::new(remaining, "Inputs since here are not parsed");
395    error_log.push((e.cause_range, e.error_detail));
396  }
397
398  // Construct result
399  if error_log.is_empty() {
400    Ok(result_node.unwrap())
401  } else {
402    let report: ParserErrorReport = error_log.into_iter().map(|e| ParserErrorContext {
403      cause_rng: e.0,
404      err_message: String::from(e.1.message),
405      annotation_rngs: e.1.annotation_rngs,
406    }).collect();
407    let msg = TextFormatter::new(text).format_error(&report);
408    Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: 3202, kind: MechErrorKind::ParserError(report, msg)})
409  }
410}
411
412
413pub fn parse(text: &str) -> MResult<Program> {
414  let graphemes = graphemes::init_source(text);
415  let mut result_node = None;
416  let mut error_log: Vec<(SourceRange, ParseErrorDetail)> = vec![];
417
418  // Do parse
419  let remaining: ParseString = match parse_mech(ParseString::new(&graphemes)) {
420    // Got a parse tree, however there may be errors
421    Ok((mut remaining_input, parse_tree)) => {
422      error_log.append(&mut remaining_input.error_log);
423      result_node = Some(parse_tree);
424      remaining_input
425    },
426    // Parsing failed and could not be recovered. No parse tree was created in this case
427    Err(err) => {
428      match err {
429        Err::Error(mut e) | Err::Failure(mut e) => {
430          error_log.append(&mut e.remaining_input.error_log);
431          error_log.push((e.cause_range, e.error_detail));
432          e.remaining_input
433        },
434        Err::Incomplete(_) => panic!("nom::Err::Incomplete is not supported!"),
435      }
436    },
437  };
438
439  // Check if all inputs were parsed
440  if remaining.len() != 0 {
441    let e = ParseError::new(remaining, "Inputs since here are not parsed");
442    error_log.push((e.cause_range, e.error_detail));
443  }
444
445  // Construct result
446  if error_log.is_empty() {
447    Ok(result_node.unwrap())
448  } else {
449    let report: ParserErrorReport = error_log.into_iter().map(|e| ParserErrorContext {
450      cause_rng: e.0,
451      err_message: String::from(e.1.message),
452      annotation_rngs: e.1.annotation_rngs,
453    }).collect();
454    let msg = TextFormatter::new(text).format_error(&report);
455    Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: 3202, kind: MechErrorKind::ParserError(report, msg)})
456  }
457}