1use 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
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 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 mech_code(input: ParseString) -> ParseResult<(MechCode,Option<Comment>)> {
324 let (input, code) = mech_code_alt(input)?;
325 if input.is_empty() {
326 return Ok((input, (code, None)));
327 }
328 let (input, _) = many0(space_tab)(input)?;
329 let (input, cmmnt) = opt(tuple((opt(semicolon),many0(space_tab),comment)))(input)?;
330 let (input, _) = alt((null(new_line), null(semicolon)))(input)?;
331 let (input, _) = whitespace0(input)?;
332 let cmmt = match cmmnt {
333 Some((_, _, cmnt)) => Some(cmnt),
334 None => None,
335 };
336 Ok((input,(code,cmmt)))
337}
338
339
340pub fn program(input: ParseString) -> ParseResult<Program> {
342 let msg = "Expects program body";
343 let (input, _) = whitespace0(input)?;
344 let (input, title) = opt(title)(input)?;
345 let (input, body) = body(input)?;
347 let (input, _) = whitespace0(input)?;
348 Ok((input, Program{title, body}))
349}
350
351pub fn parse_mech(input: ParseString) -> ParseResult<Program> {
353 let (input, mech) = program(input)?;
356 Ok((input, mech))
357}
358
359pub fn print_err_report(text: &str, report: &ParserErrorReport) {
364 let msg = TextFormatter::new(text).format_error(report);
365 println!("{}", msg);
366}
367
368pub fn parse_grammar(text: &str) -> MResult<Grammar> {
369 let text_no_Ws = &text.replace(" ", "").replace("\n", "").replace("\r", "").replace("\t", "");
371 let graphemes = graphemes::init_source(text_no_Ws);
372 let mut result_node = None;
373 let mut error_log: Vec<(SourceRange, ParseErrorDetail)> = vec![];
374
375 let remaining: ParseString = match grammar(ParseString::new(&graphemes)) {
377 Ok((mut remaining_input, parse_tree)) => {
379 error_log.append(&mut remaining_input.error_log);
380 result_node = Some(parse_tree);
381 remaining_input
382 },
383 Err(err) => {
385 match err {
386 Err::Error(mut e) | Err::Failure(mut e) => {
387 error_log.append(&mut e.remaining_input.error_log);
388 error_log.push((e.cause_range, e.error_detail));
389 e.remaining_input
390 },
391 Err::Incomplete(_) => panic!("nom::Err::Incomplete is not supported!"),
392 }
393 },
394 };
395 if remaining.len() != 0 {
397 let e = ParseError::new(remaining, "Inputs since here are not parsed");
398 error_log.push((e.cause_range, e.error_detail));
399 }
400
401 if error_log.is_empty() {
403 Ok(result_node.unwrap())
404 } else {
405 let report: ParserErrorReport = error_log.into_iter().map(|e| ParserErrorContext {
406 cause_rng: e.0,
407 err_message: String::from(e.1.message),
408 annotation_rngs: e.1.annotation_rngs,
409 }).collect();
410 let msg = TextFormatter::new(text).format_error(&report);
411 Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: 3202, kind: MechErrorKind::ParserError(report, msg)})
412 }
413}
414
415
416pub fn parse(text: &str) -> MResult<Program> {
417 let graphemes = graphemes::init_source(text);
418 let mut result_node = None;
419 let mut error_log: Vec<(SourceRange, ParseErrorDetail)> = vec![];
420
421 let remaining: ParseString = match parse_mech(ParseString::new(&graphemes)) {
423 Ok((mut remaining_input, parse_tree)) => {
425 error_log.append(&mut remaining_input.error_log);
426 result_node = Some(parse_tree);
427 remaining_input
428 },
429 Err(err) => {
431 match err {
432 Err::Error(mut e) | Err::Failure(mut e) => {
433 error_log.append(&mut e.remaining_input.error_log);
434 error_log.push((e.cause_range, e.error_detail));
435 e.remaining_input
436 },
437 Err::Incomplete(_) => panic!("nom::Err::Incomplete is not supported!"),
438 }
439 },
440 };
441
442 if remaining.len() != 0 {
444 let e = ParseError::new(remaining, "Inputs since here are not parsed");
445 error_log.push((e.cause_range, e.error_detail));
446 }
447
448 if error_log.is_empty() {
450 Ok(result_node.unwrap())
451 } else {
452 let report: ParserErrorReport = error_log.into_iter().map(|e| ParserErrorContext {
453 cause_rng: e.0,
454 err_message: String::from(e.1.message),
455 annotation_rngs: e.1.annotation_rngs,
456 }).collect();
457 let msg = TextFormatter::new(text).format_error(&report);
458 Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: 3202, kind: MechErrorKind::ParserError(report, msg)})
459 }
460}