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 match fsm_specification(input.clone()) {
292 Ok((input, fsm_spec)) => {return Ok((input, MechCode::FsmSpecification(fsm_spec)));},
293 _ => ()
295 }
296 match fsm_implementation(input.clone()) {
297 Ok((input, fsm_impl)) => {return Ok((input, MechCode::FsmImplementation(fsm_impl)));},
298 _ => ()
300 }
301 match function_define(input.clone()) {
302 Ok((input, fxn_def)) => {return Ok((input, MechCode::FunctionDefine(fxn_def)));},
303 _ => ()
305 }
306 match statement(input.clone()) {
307 Ok((input, stmt)) => { return Ok((input, MechCode::Statement(stmt)));},
308 _ => ()
310 }
311 match expression(input.clone()) {
312 Ok((input, expr)) => {return Ok((input, MechCode::Expression(expr)));},
313 _ => ()
314 }
315 match comment(input.clone()) {
316 Ok((input, cmnt)) => {return Ok((input, MechCode::Comment(cmnt)));},
317 Err(err) => {return Err(err);}
318 }
319}
320
321pub fn comment_token(input: ParseString) -> ParseResult<Token> {
323 let (input, c) = comment(input)?;
324 Ok((input, c.text))
325}
326
327pub fn mech_code(input: ParseString) -> ParseResult<MechCode> {
329 let (input, code) = mech_code_alt(input)?;
330 let (input, _) = many0(space_tab)(input)?;
331 let (input, _) = alt((new_line, semicolon, comment_token))(input)?;
332 let (input, _) = whitespace0(input)?;
333 Ok((input, code))
334}
335
336
337pub 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) = body(input)?;
344 let (input, _) = whitespace0(input)?;
345 Ok((input, Program{title, body}))
346}
347
348pub fn parse_mech(input: ParseString) -> ParseResult<Program> {
350 let (input, mech) = program(input)?;
353 Ok((input, mech))
354}
355
356pub 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(text: &str) -> Result<Program, MechError> {
366 let graphemes = graphemes::init_source(text);
367 let mut result_node = None;
368 let mut error_log: Vec<(SourceRange, ParseErrorDetail)> = vec![];
369
370 let remaining: ParseString = match parse_mech(ParseString::new(&graphemes)) {
372 Ok((mut remaining_input, parse_tree)) => {
374 error_log.append(&mut remaining_input.error_log);
375 result_node = Some(parse_tree);
376 remaining_input
377 },
378 Err(err) => {
380 match err {
381 Err::Error(mut e) | Err::Failure(mut e) => {
382 error_log.append(&mut e.remaining_input.error_log);
383 error_log.push((e.cause_range, e.error_detail));
384 e.remaining_input
385 },
386 Err::Incomplete(_) => panic!("nom::Err::Incomplete is not supported!"),
387 }
388 },
389 };
390
391 if remaining.len() != 0 {
393 let e = ParseError::new(remaining, "Inputs since here are not parsed");
394 error_log.push((e.cause_range, e.error_detail));
395 }
396
397 if error_log.is_empty() {
399 Ok(result_node.unwrap())
400 } else {
401 let report: ParserErrorReport = error_log.into_iter().map(|e| ParserErrorContext {
402 cause_rng: e.0,
403 err_message: String::from(e.1.message),
404 annotation_rngs: e.1.annotation_rngs,
405 }).collect();
406 let msg = TextFormatter::new(text).format_error(&report);
407 Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: 3202, kind: MechErrorKind::ParserError(report, msg)})
408 }
409}