1use crate::*;
15use crate::expressions::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
38use crate::{
40 TextFormatter,
41 ParseError,
42 ParseString,
43 ParseErrorDetail,
44 graphemes,
45 ParseResult,
46};
47
48pub 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
66pub 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
115pub 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
138pub 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
168pub 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
183pub 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
199pub 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
213pub 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
225fn skip_past_eol(input: ParseString) -> ParseResult<()> {
227 let (input, _) = skip_till_eol(input)?;
228 let (input, _) = new_line(input)?;
229 Ok((input, ()))
230}
231
232fn 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
245pub fn skip_spaces(input: ParseString) -> ParseResult<()> {
272 let (input, _) = many0(space)(input)?;
273 Ok((input, ()))
274}
275
276pub fn skip_nil(input: ParseString) -> ParseResult<()> {
278 Ok((input, ()))
279}
280
281pub fn skip_empty_mech_directive(input: ParseString) -> ParseResult<String> {
283 Ok((input, String::from("mech:")))
284}
285
286pub 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 _ => ()
296 }
297 match fsm_implementation(input.clone()) {
298 Ok((input, fsm_impl)) => {return Ok((input, MechCode::FsmImplementation(fsm_impl)));},
299 _ => ()
301 }
302 match function_define(input.clone()) {
303 Ok((input, fxn_def)) => {return Ok((input, MechCode::FunctionDefine(fxn_def)));},
304 _ => ()
306 }
307 match statement(input.clone()) {
308 Ok((input, stmt)) => { return Ok((input, MechCode::Statement(stmt)));},
309 _ => ()
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
322pub fn comment_token(input: ParseString) -> ParseResult<Token> {
324 let (input, c) = comment(input)?;
325 Ok((input, c.text))
326}
327
328pub fn mech_code(input: ParseString) -> ParseResult<MechCode> {
330 let (input, code) = mech_code_alt(input)?;
331 let (input, _) = many0(space_tab)(input)?;
332 let (input, _) = alt((new_line, semicolon, comment_token))(input)?;
333 let (input, _) = whitespace0(input)?;
334 Ok((input, code))
335}
336
337
338pub fn program(input: ParseString) -> ParseResult<Program> {
340 let msg = "Expects program body";
341 let (input, _) = whitespace0(input)?;
342 let (input, title) = opt(title)(input)?;
343 let (input, body) = body(input)?;
345 let (input, _) = whitespace0(input)?;
346 Ok((input, Program{title, body}))
347}
348
349pub fn parse_mech(input: ParseString) -> ParseResult<Program> {
351 let (input, mech) = program(input)?;
354 Ok((input, mech))
355}
356
357pub fn print_err_report(text: &str, report: &ParserErrorReport) {
362 let msg = TextFormatter::new(text).format_error(report);
363 println!("{}", msg);
364}
365
366pub fn parse_grammar(text: &str) -> MResult<Grammar> {
367 let text_no_Ws = &text.replace(" ", "").replace("\n", "").replace("\r","").replace("\t", "");
369 let graphemes = graphemes::init_source(text_no_Ws);
370 let mut result_node = None;
371 let mut error_log: Vec<(SourceRange, ParseErrorDetail)> = vec![];
372
373 let remaining: ParseString = match grammar(ParseString::new(&graphemes)) {
375 Ok((mut remaining_input, parse_tree)) => {
377 error_log.append(&mut remaining_input.error_log);
378 result_node = Some(parse_tree);
379 remaining_input
380 },
381 Err(err) => {
383 match err {
384 Err::Error(mut e) | Err::Failure(mut e) => {
385 error_log.append(&mut e.remaining_input.error_log);
386 error_log.push((e.cause_range, e.error_detail));
387 e.remaining_input
388 },
389 Err::Incomplete(_) => panic!("nom::Err::Incomplete is not supported!"),
390 }
391 },
392 };
393
394 if remaining.len() != 0 {
396 let e = ParseError::new(remaining, "Inputs since here are not parsed");
397 error_log.push((e.cause_range, e.error_detail));
398 }
399
400 if error_log.is_empty() {
402 Ok(result_node.unwrap())
403 } else {
404 let report: ParserErrorReport = error_log.into_iter().map(|e| ParserErrorContext {
405 cause_rng: e.0,
406 err_message: String::from(e.1.message),
407 annotation_rngs: e.1.annotation_rngs,
408 }).collect();
409 let msg = TextFormatter::new(text).format_error(&report);
410 Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: 3202, kind: MechErrorKind::ParserError(report, msg)})
411 }
412}
413
414
415pub fn parse(text: &str) -> MResult<Program> {
416 let graphemes = graphemes::init_source(text);
417 let mut result_node = None;
418 let mut error_log: Vec<(SourceRange, ParseErrorDetail)> = vec![];
419
420 let remaining: ParseString = match parse_mech(ParseString::new(&graphemes)) {
422 Ok((mut remaining_input, parse_tree)) => {
424 error_log.append(&mut remaining_input.error_log);
425 result_node = Some(parse_tree);
426 remaining_input
427 },
428 Err(err) => {
430 match err {
431 Err::Error(mut e) | Err::Failure(mut e) => {
432 error_log.append(&mut e.remaining_input.error_log);
433 error_log.push((e.cause_range, e.error_detail));
434 e.remaining_input
435 },
436 Err::Incomplete(_) => panic!("nom::Err::Incomplete is not supported!"),
437 }
438 },
439 };
440
441 if remaining.len() != 0 {
443 let e = ParseError::new(remaining, "Inputs since here are not parsed");
444 error_log.push((e.cause_range, e.error_detail));
445 }
446
447 if error_log.is_empty() {
449 Ok(result_node.unwrap())
450 } else {
451 let report: ParserErrorReport = error_log.into_iter().map(|e| ParserErrorContext {
452 cause_rng: e.0,
453 err_message: String::from(e.1.message),
454 annotation_rngs: e.1.annotation_rngs,
455 }).collect();
456 let msg = TextFormatter::new(text).format_error(&report);
457 Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: 3202, kind: MechErrorKind::ParserError(report, msg)})
458 }
459}