1use std::fmt::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct Located<A> {
5 pub value: A,
6 pub from: Location,
7 pub to: Location,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct Location {
12 pub row: usize,
13 pub col: usize,
14}
15
16#[derive(Debug, PartialEq, Eq)]
17pub enum ParseResult<'a, Output, State> {
18 ParseOk {
19 input: &'a str,
20 location: Location,
21 output: Output,
22 state: State,
23 },
24 ParseError {
25 message: String,
26 from: Location,
27 to: Location,
28 state: State,
29 },
30}
31
32impl<'a, T, S: Clone> ParseResult<'a, T, S> {
33 pub fn map<U, F: FnOnce(T) -> U>(self, func: F) -> ParseResult<'a, U, S> {
34 match self {
35 ParseResult::ParseOk { input, location, output, state } =>
36 ParseResult::ParseOk {
37 input,
38 location,
39 output: func(output),
40 state,
41 },
42 ParseResult::ParseError { message, from, to, state } =>
43 ParseResult::ParseError { message, from, to, state },
44 }
45 }
46 pub fn map_with_state<U, F: FnOnce(T, S) -> U>(self, func: F) -> ParseResult<'a, U, S> {
47 match self {
48 ParseResult::ParseOk { input, location, output, state } =>
49 ParseResult::ParseOk {
50 input,
51 location,
52 output: func(output, state.clone()),
53 state: state,
54 },
55 ParseResult::ParseError { message, from, to, state } =>
56 ParseResult::ParseError { message, from, to, state },
57 }
58 }
59 pub fn map_err<F: FnOnce(String) -> String>(self, func: F) -> ParseResult<'a, T, S> {
60 match self {
61 ParseResult::ParseOk { input, location, output, state } =>
62 ParseResult::ParseOk {
63 input,
64 location,
65 output,
66 state,
67 },
68 ParseResult::ParseError { message, from, to, state } =>
69 ParseResult::ParseError {
70 message: func(message),
71 from,
72 to,
73 state,
74 }
75 }
76 }
77 pub fn and_then<U, F: FnOnce(&'a str, T, Location, S) -> ParseResult<'a, U, S>>(self, func: F) -> ParseResult<'a, U, S> {
78 match self {
79 ParseResult::ParseOk { input, output, location, state } =>
80 func(input, output, location, state),
81 ParseResult::ParseError { message, from, to, state } =>
82 ParseResult::ParseError { message, from, to, state },
83 }
84 }
85}
86
87pub trait Parser<'a, Output, State: Clone> {
88 fn parse(&self, input: &'a str, location: Location, state: State) -> ParseResult<'a, Output, State>;
89 fn map<F, NewOutput>(self, map_fn: F) -> BoxedParser<'a, NewOutput, State>
90 where
91 Self: Sized + 'a,
92 Output: 'a,
93 NewOutput: 'a,
94 State: 'a,
95 F: Fn(Output) -> NewOutput + 'a,
96 {
97 BoxedParser::new(map(self, map_fn))
98 }
99 fn map_with_state<F, NewOutput>(self, map_fn: F) -> BoxedParser<'a, NewOutput, State>
100 where
101 Self: Sized + 'a,
102 Output: 'a,
103 NewOutput: 'a,
104 State: 'a,
105 F: Fn(Output, State) -> NewOutput + 'a,
106 {
107 BoxedParser::new(map_with_state(self, map_fn))
108 }
109 fn map_err<F>(self, map_fn: F) -> BoxedParser<'a, Output, State>
110 where
111 Self: Sized + 'a,
112 Output: 'a,
113 State: 'a,
114 F: Fn(String) -> String + 'a,
115 {
116 BoxedParser::new(map_err(self, map_fn))
117 }
118 fn and_then<F, NextParser, NewOutput>(self, f: F) -> BoxedParser<'a, NewOutput, State>
119 where
120 Self: Sized + 'a,
121 Output: 'a,
122 NewOutput: 'a,
123 State: 'a,
124 NextParser: Parser<'a, NewOutput, State> + 'a,
125 F: Fn(Output) -> NextParser + 'a,
126 {
127 BoxedParser::new(and_then(self, f))
128 }
129 fn pred<F>(self, predicate: F, expecting: &'a str) -> BoxedParser<'a, Output, State>
130 where
131 Self: Sized + 'a,
132 Output: std::fmt::Display + 'a,
133 State: 'a,
134 F: Fn(&Output) -> bool + 'a,
135 {
136 BoxedParser::new(pred(self, predicate, expecting))
137 }
138 fn ignore(self) -> BoxedParser<'a, (), State>
139 where
140 Self: Sized + 'a,
141 Output: 'a,
142 State: 'a,
143 {
144 BoxedParser::new(map(self, |_| ()))
145 }
146 fn update_state<F>(self, f: F) -> BoxedParser<'a, Output, State>
147 where
148 Self: Sized + 'a,
149 State: 'a,
150 Output: Clone + 'a,
151 F: Fn(Output, State) -> State + 'a,
152 {
153 BoxedParser::new(update_state(self, f))
154 }
155}
156
157impl<'a, F, Output, State: 'a> Parser<'a, Output, State> for F
158where
159 F: Fn(&'a str, Location, State) -> ParseResult<'a, Output,State>,
160 State: Clone,
161{
162 fn parse(&self, input: &'a str, location: Location, state: State) -> ParseResult<'a, Output, State> {
163 self(input, location, state)
164 }
165}
166
167pub struct BoxedParser<'a, Output, State> {
168 parser: Box<dyn Parser<'a, Output, State> + 'a>,
169}
170
171impl<'a, Output,State> BoxedParser<'a, Output, State> {
172 pub fn new<P>(parser: P) -> Self
173 where
174 P: Parser<'a, Output, State> + 'a,
175 State: Clone,
176 {
177 BoxedParser {
178 parser: Box::new(parser),
179 }
180 }
181}
182
183impl<'a, Output, State> Parser<'a, Output, State> for BoxedParser<'a, Output, State>
184 where
185 State: Clone,
186 {
187 fn parse(&self, input: &'a str, location: Location, state: State) -> ParseResult<'a, Output, State> {
188 self.parser.parse(input, location, state)
189 }
190}
191
192fn and_then<'a, P, F, A, B, S: Clone + 'a, NextP>(parser: P, f: F) -> impl Parser<'a, B, S>
193 where
194 P: Parser<'a, A, S>,
195 NextP: Parser<'a, B, S>,
196 F: Fn(A) -> NextP,
197 S: Clone,
198{
199 move |input, location, state| parser.parse(input, location, state)
200 .and_then(| next_input, next_output, next_location, next_state: S |
201 f(next_output).parse(next_input, next_location, next_state)
202 )
203}
204
205pub fn token<'a, S: Clone + 'a>(expected: &'static str) -> BoxedParser<'a, &str, S> {
206 BoxedParser::new(
207 move |input: &'a str, location: Location, state: S| {
208 let found = input.get(0..expected.len());
209 match found {
210 Some(next) if next == expected => ParseResult::ParseOk {
211 input: &input[expected.len()..],
212 output: expected,
213 location: increment_col(expected.len(), location),
214 state,
215 },
216 _ => ParseResult::ParseError {
217 message: format!(
218 "I'm expecting a `{}` but found {}.",
219 expected,
220 display_token(found)
221 ),
222 from: location,
223 to: match found {
224 Some(found_str) => Location {
225 row: location.row + found_str.len(),
226 col: location.col,
227 },
228 None => location,
229 },
230 state,
231 },
232 }
233 })
234}
235
236pub fn increment_col(additional_col: usize, location: Location) -> Location {
237 Location {
238 col: location.col + additional_col,
239 ..location
240 }
241}
242
243pub fn increment_row(additional_row: usize, location: Location) -> Location {
244 Location {
245 row: location.row + additional_row,
246 col: 1,
247 }
248}
249
250pub fn display_token<T: Display>(token: Option<T>) -> String {
251 match token {
252 Some(token_content) => format!("`{}`", token_content).replace("\n", "\\n"),
253 None => "nothing".to_string(),
254 }
255}
256
257pub fn pair<'a, P1, P2, R1, R2, S: Clone + 'a>(parser1: P1, parser2: P2) -> impl Parser<'a, (R1, R2), S>
258where
259 P1: Parser<'a, R1, S>,
260 P2: Parser<'a, R2, S>,
261{
262 move |input, location, state|
263 parser1.parse(input, location, state)
264 .and_then(| next_input, first_output, next_location, next_state: S |
265 parser2.parse(next_input, next_location, next_state).map(| second_output |
266 (first_output, second_output)
267 )
268 )
269}
270
271pub fn quadruple<'a, P1: 'a, P2: 'a, P3: 'a, P4: 'a, R1: 'a, R2: 'a, R3: 'a, R4: 'a, S: Clone + 'a>
272 (parser1: P1, parser2: P2, parser3: P3, parser4: P4)
273 -> BoxedParser<'a, (R1, R2, R3, R4), S>
274 where
275 P1: Parser<'a, R1, S>,
276 P2: Parser<'a, R2, S>,
277 P3: Parser<'a, R3, S>,
278 P4: Parser<'a, R4, S>,
279{
280 pair(
281 pair(parser1, parser2),
282 pair(parser3, parser4),
283 )
284 .map(|((result1, result2), (result3, result4))|
285 (result1, result2, result3, result4)
286 )
287}
288
289pub fn map<'a, P: 'a, F: 'a, A, B, S: Clone + 'a>(parser: P, map_fn: F) -> BoxedParser<'a, B, S>
290where
291 P: Parser<'a, A, S>,
292 F: Fn(A) -> B,
293{
294 BoxedParser::new(
295 move |input, location, state| parser.parse(input, location, state).map(
296 |output| map_fn(output)
297 ))
298}
299
300pub fn map_with_state<'a, P: 'a, F: 'a, A, B, S: Clone + 'a>(parser: P, map_fn: F) -> BoxedParser<'a, B, S>
301where
302 P: Parser<'a, A, S>,
303 F: Fn(A, S) -> B,
304{
305 BoxedParser::new(
306 move |input, location, state: S| match parser.parse(input, location, state.clone()) {
307 ParseResult::ParseOk {
308 input: next_input,
309 output,
310 location: next_location,
311 state: next_state,
312 } => ParseResult::ParseOk {
313 input: next_input,
314 location: next_location,
315 output: map_fn(output, next_state.clone()),
316 state: next_state,
317 },
318 ParseResult::ParseError {
319 message,
320 from,
321 to,
322 state: error_state,
323 } => ParseResult::ParseError {
324 message,
325 from,
326 to,
327 state: error_state,
328 }
329 }
330 )
331}
332
333pub fn map_err<'a, P, F, A, S: Clone + 'a>(parser: P, map_fn: F) -> impl Parser<'a, A, S>
334where
335 P: Parser<'a, A, S>,
336 F: Fn(String) -> String,
337{
338 move |input, location, state| parser.parse(input, location, state).map_err(
339 |error_message| map_fn(error_message)
340 )
341}
342
343fn map2<'a, P1, P2, F, A, B, C, S: Clone + 'a>(parser1: P1, parser2: P2, map_fn: F) -> impl Parser<'a, C, S>
344where
345 P1: Parser<'a, A, S>,
346 P2: Parser<'a, B, S>,
347 F: Fn(A, B) -> C,
348{
349 move |input, location, state| parser1.parse(input, location, state).and_then(
350 |input1, output1, location1, state1 | parser2.parse(input1, location1, state1).map(
351 |output2| map_fn(output1, output2)
352 )
353 )
354}
355
356pub fn left<'a, P1: 'a, P2: 'a, R1: 'a, R2: 'a, S: Clone + 'a>(parser1: P1, parser2: P2) -> BoxedParser<'a, R1, S>
357where
358 P1: Parser<'a, R1, S>,
359 P2: Parser<'a, R2, S>,
360{
361 map(pair(parser1, parser2), |(left, _right)| left)
362}
363
364pub fn right<'a, P1: 'a, P2: 'a, R1: 'a, R2: 'a, S: Clone + 'a>(parser1: P1, parser2: P2) -> BoxedParser<'a, R2, S>
365where
366 P1: Parser<'a, R1, S>,
367 P2: Parser<'a, R2, S>,
368{
369 map(pair(parser1, parser2), |(_left, right)| right)
370}
371
372pub fn one_or_more<'a, P, A, S: Clone + 'a>(parser: P) -> impl Parser<'a, Vec<A>, S>
373where
374 P: Parser<'a, A, S>,
375{
376 one_or_more_with_ending(false, parser)
377}
378
379pub fn one_or_more_till_end<'a, P, A, S: Clone + 'a>(parser: P) -> impl Parser<'a, Vec<A>, S>
380where
381 P: Parser<'a, A, S>,
382{
383 one_or_more_with_ending(true, parser)
384}
385
386pub fn one_or_more_with_ending<'a, P, A, S: Clone + 'a>(till_end: bool, parser: P) -> impl Parser<'a, Vec<A>, S>
387where
388 P: Parser<'a, A, S>,
389{
390 move |mut input, mut location, mut state: S| {
391 let mut result = Vec::new();
392
393 match parser.parse(input, location, state.clone()) {
394 ParseResult::ParseOk {
395 input: next_input,
396 output: first_item,
397 location: next_location,
398 state: next_state,
399 } => {
400 input = next_input;
401 location = next_location;
402 state = next_state;
403 result.push(first_item);
404 }
405 ParseResult::ParseError {
406 message: error_message,
407 from,
408 to,
409 state
410 } => {
411 return ParseResult::ParseError {
412 message: error_message,
413 from,
414 to,
415 state,
416 };
417 }
418 }
419
420 loop {
421 match parser.parse(input, location, state.clone()) {
422 ParseResult::ParseOk {
423 input: next_input,
424 output: next_item,
425 location: next_location,
426 state: next_state,
427 } => {
428 input = next_input;
429 location = next_location;
430 state = next_state;
431 result.push(next_item);
432 },
433 ParseResult::ParseError {
434 message: error_message,
435 from,
436 to,
437 state,
438 } => if till_end && input != "" {
439 return ParseResult::ParseError {
440 message: error_message,
441 from,
442 to,
443 state,
444 };
445 } else {
446 break;
447 }
448 }
449 }
450
451 ParseResult::ParseOk {
452 input: input,
453 output: result,
454 location: location,
455 state: state,
456 }
457 }
458}
459
460pub fn zero_or_more<'a, P: 'a, A, S: Clone + 'a>(parser: P) -> BoxedParser<'a, Vec<A>, S>
461where
462 P: Parser<'a, A, S>,
463{
464 BoxedParser::new(
465 move |mut input, mut location, mut state: S| {
466 let mut result = Vec::new();
467
468 while let ParseResult::ParseOk {
469 input: next_input,
470 output: next_item,
471 location: next_location,
472 state: next_state,
473 } = parser.parse(input, location, state.clone())
474 {
475 input = next_input;
476 location = next_location;
477 state = next_state;
478 result.push(next_item);
479 }
480
481 ParseResult::ParseOk {
482 input: input,
483 output: result,
484 location: location,
485 state: state,
486 }
487 })
488}
489
490pub fn any_char<'a, S: Clone + 'a>() -> impl Parser<'a, char, S> {
491 |input: &'a str, location: Location, state| match input.chars().next() {
492 Some(character) => ParseResult::ParseOk {
493 input: &input[character.len_utf8()..],
494 output: character,
495 location: increment_col(character.len_utf8(), location),
496 state,
497 },
498 _ => ParseResult::ParseError {
499 message: "I'm expecting any character but reached the end of input.".to_string(),
500 from: location,
501 to: location,
502 state,
503 },
504 }
505}
506
507fn pred<'a, P, F, A: std::fmt::Display, S: Clone + 'a>(parser: P, predicate: F, expecting: &'a str) -> impl Parser<'a, A, S>
508where
509 P: Parser<'a, A, S>,
510 F: Fn(&A) -> bool,
511{
512 move |input, location, state: S| match parser.parse(input, location, state.clone()) {
513 ParseResult::ParseOk {
514 input: next_input,
515 output: content,
516 location: next_location,
517 state: next_state,
518 } => if predicate(&content) {
519 ParseResult::ParseOk {
520 input: next_input,
521 output: content,
522 location: next_location,
523 state: next_state,
524 }
525 } else {
526 ParseResult::ParseError {
527 message: format!(
528 "I'm expecting {} but found {}.",
529 expecting,
530 display_token(Some(content)),
531 )
532 .to_string(),
533 from: location,
534 to: next_location,
535 state: next_state,
536 }
537 },
538 _ => ParseResult::ParseError {
539 message: format!(
540 "I'm expecting {} but found {}.",
541 expecting,
542 display_token(input.chars().next())
543 )
544 .to_string(),
545 from: location,
546 to: location,
547 state,
548 },
549 }
550}
551
552pub fn space_char<'a, S: Clone + 'a>() -> BoxedParser<'a, (), S> {
553 any_char().pred(
554 |character| *character == ' ',
555 "a whitespace",
556 ).ignore()
557}
558
559pub fn newline_char<'a, S: Clone + 'a>() -> BoxedParser<'a, (), S> {
560 BoxedParser::new(
561 (move |input, location, state: S| {
562 let mut next_input: &str = input;
563 let mut next_location: Location = location;
564 let mut next_state: S = state.clone();
565 let result1 = any_char().pred(
566 |character| *character == '\r',
567 "a carriage return",
568 ).parse(input, location, state);
569 match result1 {
570 ParseResult::ParseOk {
571 input,
572 location,
573 state,
574 ..
575 } => {
576 next_input = input;
577 next_location = location;
578 next_state = state;
579 }
580 _ => {}
581 }
582 let result = any_char().pred(
583 |character| *character == '\n',
584 "a newline",
585 ).parse(next_input, next_location, next_state);
586 match result {
587 ParseResult::ParseOk {
588 input: next_input,
589 output,
590 location: next_location,
591 state: next_state,
592 } => ParseResult::ParseOk {
593 input: next_input,
594 output: output,
595 location: increment_row(1, next_location),
596 state: next_state,
597 },
598 ParseResult::ParseError {
599 message: error_message,
600 from,
601 to,
602 state,
603 } => ParseResult::ParseError {
604 message: error_message,
605 from,
606 to,
607 state,
608 }
609 }
610 }).ignore()
611 )
612}
613
614fn newline0<'a, S: Clone + 'a>(indentations: usize) -> BoxedParser<'a, (), S> {
615 zero_or_more(
616 ignore_chain(vec![
617 indents(indentations),
618 newline_char(),
619 ])
620 ).ignore()
621}
622
623pub fn newline1<'a, S: Clone + 'a>(indentations: usize) -> BoxedParser<'a, (), S> {
624 ignore_chain(vec![
625 newline_char(),
626 newline0(indentations),
627 ])
628}
629
630pub fn space0<'a, S: Clone + 'a>() -> BoxedParser<'a, (), S> {
631 zero_or_more(space_char()).ignore()
632}
633
634pub fn space1<'a, S: Clone + 'a>() -> BoxedParser<'a, (), S> {
635 one_or_more(space_char()).ignore()
636}
637
638pub fn indent<'a, S: Clone + 'a>() -> BoxedParser<'a, (), S> {
639 ignore_chain(vec![
640 space_char(),
641 space_char(),
642 ]).map_err(|_| "I'm expecting an indentation.\nAll indentations should be two spaces.".to_string())
643}
644
645pub fn indents<'a, S: Clone + 'a>(indentations: usize) -> BoxedParser<'a, (), S> {
646 repeat(
647 indentations,
648 indent(),
649 ).map_err(|_| "I'm expecting an indentation.\nAll indentations should be two spaces.".to_string())
650 .ignore()
651}
652
653fn repeat<'a, A, P, S: Clone + 'a>(times: usize, parser: P)
654 -> impl Parser<'a, Vec<A>, S>
655 where
656 P: Parser<'a, A, S>
657{
658 move |mut input, mut location, mut state: S| {
659 let mut result = Vec::new();
660
661 if times == 0 {
662 return ParseResult::ParseOk {
663 input,
664 location,
665 output: result,
666 state,
667 }
668 }
669
670 let mut counter = 0;
671
672 while let ParseResult::ParseOk {
673 input: next_input,
674 output: next_item,
675 location: next_location,
676 state: next_state,
677 ..
678 } = parser.parse(input, location, state.clone())
679 {
680 if counter >= times {
681 break;
682 }
683 input = next_input;
684 location = next_location;
685 state = next_state;
686 result.push(next_item);
687 counter = counter + 1;
688 }
689
690 ParseResult::ParseOk {
691 input: input,
692 output: result,
693 location: location,
694 state: state,
695 }
696 }
697}
698
699pub fn choose3<'a, A: 'a, P: 'a, S: Clone + 'a>(parser1: P, parser2: P, parser3: P)
700 -> BoxedParser<'a, A, S>
701 where
702 P: Parser<'a, A, S>
703{
704 either(
705 BoxedParser::new(parser1),
706 either(
707 parser2,
708 parser3,
709 )
710 )
711}
712
713pub fn either<'a, A, P: 'a, S: Clone + 'a>(parser1: P, parser2: P)
714 -> BoxedParser<'a, A, S>
715 where
716 P: Parser<'a, A, S>
717{
718 BoxedParser::new(
719 move |input, location, state: S| {
720 let result = match parser1.parse(input, location, state.clone()) {
721 ok @ ParseResult::ParseOk {..} => ok,
722 ParseResult::ParseError {..} =>
723 parser2.parse(input, location, state)
724 };
725 result
730 }
731 )
732}
733
734pub fn optional<'a, A: Clone + 'a, P: 'a, S: Clone + 'a>(default: A, parser: P)
735 -> BoxedParser<'a, A, S>
736 where
737 P: Parser<'a, A, S>
738{
739 either(
740 BoxedParser::new(
741 parser
742 ),
743 BoxedParser::new(
744 move |input, location, state|
745 ParseResult::ParseOk {
746 input,
747 location,
748 output: default.clone(),
749 state,
750 }
751 )
752 )
753}
754
755pub fn newline_with_comment<'a, S: Clone + 'a>(comment_symbol: &'static str) -> impl Parser<'a, (), S> {
756 either(
757 ignore_chain(vec![
758 space0(),
759 line_comment(comment_symbol),
760 ]),
761 ignore_chain(vec![
762 space0(),
763 newline_char()
764 ]),
765 )
766}
767
768pub fn line_comment<'a, S: Clone + 'a>(comment_symbol: &'static str) -> BoxedParser<'a, (), S> {
769 ignore_chain(vec![
770 token(comment_symbol).ignore(),
771 zero_or_more(any_char().pred(
772 |character| *character != '\n' && *character != '\r',
773 "any character",
774 )).ignore(),
775 newline_char(),
776 ])
777}
778
779pub fn line_comments<'a, S: Clone + 'a>(indentations: usize) -> BoxedParser<'a, (), S> {
780 either(
781 one_or_more(
782 ignore_chain(vec![
783 newline0(indentations),
784 indents(indentations),
785 token("--").ignore(),
786 zero_or_more(any_char().pred(
787 |character| *character != '\n' && *character != '\r',
788 "any character",
789 )).ignore(),
790 newline1(indentations),
791 ])
792 ).ignore(),
793 newline0(indentations),
794 )
795}
796
797pub fn ignore_chain<'a, S: Clone + 'a>(parsers: Vec<BoxedParser<'a, (), S>>) -> BoxedParser<'a, (), S>
798{
799 BoxedParser::new(
800 move | mut input, mut location, mut state | {
801 for parser in &parsers {
802 match parser.parse(input, location, state) {
803 ParseResult::ParseOk {
804 input: next_input,
805 location: next_location,
806 state: next_state,
807 ..
808 } => {
809 input = next_input;
810 location = next_location;
811 state = next_state;
812 },
813 error @ ParseResult::ParseError {..} => {
814 return error;
815 }
816 }
817 }
818 ParseResult::ParseOk {
819 input,
820 location,
821 output: (),
822 state,
823 }
824 })
825}
826
827pub fn whole_decimal<'a, S: Clone + 'a>() -> impl Parser<'a, usize, S> {
828 one_or_more(
829 any_char().pred(
830 | character |
831 character.is_digit(10)
832 , "a whole decimal number"
833 )
834 ).map(| digits | digits.iter().collect::<String>().parse().unwrap())
835}
836
837pub fn located<'a, P: 'a, A, S: Clone + 'a>(parser: P) -> impl Parser<'a, Located<A>, S>
838 where
839 P: Parser<'a, A, S>
840{
841 move |input, location, state|
842 match parser.parse(input, location, state) {
843 ParseResult::ParseOk {
844 input: next_input,
845 output,
846 location: next_location,
847 state: next_state,
848 } => ParseResult::ParseOk {
849 input: next_input,
850 output: Located {
851 value: output,
852 from: Location {
853 row: location.row,
854 col: location.col,
855 },
856 to: Location {
857 row: next_location.row,
858 col: next_location.col,
859 },
860 },
861 location: next_location,
862 state: next_state,
863 },
864 ParseResult::ParseError {
865 message: error_message,
866 from,
867 to,
868 state,
869 } =>
870 ParseResult::ParseError {
871 message: error_message,
872 from,
873 to,
874 state,
875 }
876 }
877}
878
879pub fn display_error(source: &str, error_message: String, from: Location, to: Location) -> String {
880 let row = from.row;
881 let col = from.col;
882 let error_length = if to.col == from.col {
883 1
884 } else {
885 to.col - from.col
886 };
887 let error_line = row.to_string() + "| " + source.split("\n").collect::<Vec<&str>>()[row - 1];
888 let error_pointer = " ".repeat(col - 1 + row.to_string().len() + 2) + &"^".repeat(error_length);
889 let error_report =
890 error_line + "\n" + &error_pointer + "\n" + "⚠️" + &error_message;
891 error_report
892}
893
894pub fn update_state<'a, P, A: Clone, S: Clone + 'a, F>(parser: P, f: F) -> impl Parser<'a, A, S>
895 where
896 P: Parser<'a, A, S>,
897 F: Fn(A, S) -> S
898{
899 move |input, location, state| {
900 match parser.parse(input, location, state) {
901 ParseResult::ParseOk {
902 input: next_input,
903 location: next_location,
904 state: next_state,
905 output,
906 } =>
907 ParseResult::ParseOk {
908 input: next_input,
909 output: output.clone(),
910 location: next_location,
911 state: f(output, next_state),
912 },
913 ParseResult::ParseError {
914 message,
915 from,
916 to,
917 state,
918 } =>
919 ParseResult::ParseError {
920 message,
921 from,
922 to,
923 state,
924 }
925 }
926 }
927}