1#![cfg_attr(feature = "no-std", no_std)]
4#![cfg_attr(feature = "no-std", alloc)]
5#![allow(dead_code)]
6#![allow(warnings)]
7
8extern crate mech_core;
9#[cfg(feature="no-std")] #[macro_use] extern crate alloc;
10#[cfg(not(feature = "no-std"))] extern crate core;
11extern crate nom;
12extern crate nom_unicode;
13extern crate tabled;
14
15use mech_core::*;
16use mech_core::nodes::*;
17use std::cell::RefCell;
18use std::rc::Rc;
19use num_traits::*;
20
21#[cfg(feature = "serde")] use serde::{Serialize, Deserialize};
22
23#[cfg(not(feature = "no-std"))] use core::fmt;
24#[cfg(feature = "no-std")] use alloc::fmt;
25#[cfg(feature = "no-std")] use alloc::string::String;
26#[cfg(feature = "no-std")] use alloc::vec::Vec;
27use nom::{
28 IResult,
29 branch::alt,
30 sequence::tuple,
31 combinator::{opt, eof},
32 multi::{many1, many_till, many0, separated_list1},
33 Err,
34};
35use nom::Parser;
36
37use std::collections::HashMap;
38use colored::*;
39
40pub mod mechdown;
42pub mod expressions;
43pub mod statements;
44pub mod structures;
45pub mod base;
46pub mod parser;
47#[cfg(feature = "formatter")]
48pub mod formatter;
49#[cfg(feature = "mika")]
50pub mod mika;
51pub mod grammar;
52pub mod literals;
53pub mod state_machines;
54pub mod functions;
55pub mod repl;
56
57pub use crate::parser::*;
58pub use crate::mechdown::*;
60pub use crate::expressions::*;
61pub use crate::statements::*;
62pub use crate::structures::*;
63pub use crate::base::*;
64#[cfg(feature = "formatter")]
65pub use crate::formatter::*;
66#[cfg(feature = "mika")]
67pub use crate::mika::*;
68pub use crate::grammar::*;
69pub use crate::literals::*;
70pub use crate::state_machines::*;
71pub use crate::functions::*;
72pub use crate::repl::*;
73
74
75pub mod graphemes {
79 use unicode_segmentation::UnicodeSegmentation;
80
81 pub fn init_source(text: &str) -> Vec<&str> {
85 let mut graphemes = UnicodeSegmentation::graphemes(text, true).collect::<Vec<&str>>();
86 graphemes.push("\n");
87 graphemes
88 }
89
90 pub fn init_tag(tag: &str) -> Vec<&str> {
91 UnicodeSegmentation::graphemes(tag, true).collect::<Vec<&str>>()
92 }
93
94 pub fn is_new_line(grapheme: &str) -> bool {
95 match grapheme {
96 "\r" | "\n" | "\r\n" => true,
97 _ => false,
98 }
99 }
100
101 pub fn is_numeric(grapheme: &str) -> bool {
102 grapheme.chars().next().unwrap().is_numeric()
103 }
104
105 pub fn is_alpha(grapheme: &str) -> bool {
106 grapheme.chars().next().unwrap().is_alphabetic()
107 }
108
109 pub fn is_emoji(grapheme: &str) -> bool {
110 let ch = grapheme.chars().next().unwrap();
111 !(ch.is_alphanumeric() || ch.is_ascii())
112 }
113
114 pub fn width(grapheme: &str) -> usize {
115 let ch = grapheme.chars().next().unwrap();
117 if ch == '\t' {
118 1
119 } else if ch.is_control() {
120 0
121 } else {
122 1
123 }
124 }
125}
126
127pub type ParseResult<'a, O> = IResult<ParseString<'a>, O, ParseError<'a>>;
129
130#[derive(Clone, Debug)]
134pub struct ParseString<'a> {
135 pub graphemes: &'a Vec<&'a str>,
137 pub error_log: Vec<(SourceRange, ParseErrorDetail)>,
139 pub cursor: usize,
141 pub location: SourceLocation,
143}
144
145impl<'a> ParseString<'a> {
146 pub fn new(graphemes: &'a Vec<&'a str>) -> Self {
148 ParseString {
149 graphemes,
150 error_log: vec![],
151 cursor: 0,
152 location: SourceLocation { row: 1, col: 1 },
153 }
154 }
155
156 pub fn rest(&self) -> String {
157 let mut s = String::new();
159 for i in self.cursor..self.graphemes.len() {
160 s.push_str(self.graphemes[i]);
161 }
162 s
163 }
164
165 pub fn peek(&self, n: usize) -> Option<&str> {
166 self.graphemes.get(self.cursor + n).copied()
167 }
168
169 pub fn current(&self) -> Option<&str> {
170 self.graphemes.get(self.cursor).copied()
171 }
172
173 pub fn next(&self) -> Option<&str> {
174 self.graphemes.get(self.cursor + 1).copied()
175 }
176
177 fn consume_tag(&mut self, tag: &str) -> Option<String> {
179 if self.is_empty() {
180 return None;
181 }
182 let current = self.graphemes[self.cursor];
183
184 let gs = graphemes::init_tag(tag);
185 let gs_len = gs.len();
186
187 if self.len() < gs_len {
189 return None;
190 }
191
192 let mut tmp_location = self.location;
194 for i in 0..gs_len {
195 let c = self.cursor + i;
196 let g = self.graphemes[c];
197 if g != gs[i] {
198 return None;
199 }
200 if graphemes::is_new_line(g) {
201 if !self.is_last_grapheme(c) {
202 tmp_location.row += 1;
203 tmp_location.col = 1;
204 }
205 } else {
206 tmp_location.col += graphemes::width(g);
207 }
208 }
209 self.cursor += gs_len;
211 self.location = tmp_location;
212 Some(tag.to_string())
213 }
214
215 pub fn slice(&self, start_cursor: usize, end_cursor: usize) -> String {
217 let start = start_cursor.min(self.graphemes.len());
218 let end = end_cursor.min(self.graphemes.len());
219 self.graphemes[start..end].join("")
220 }
221
222 fn consume_one(&mut self) -> Option<String> {
224 if self.is_empty() {
225 return None;
226 }
227 let g = self.graphemes[self.cursor];
228 if graphemes::is_new_line(g) {
229 if !self.is_last_grapheme(self.cursor) {
230 self.location.row += 1;
231 self.location.col = 1;
232 }
233 } else {
234 self.location.col += graphemes::width(g);
235 }
236 self.cursor += 1;
237 Some(g.to_string())
238 }
239
240
241 fn consume_emoji(&mut self) -> Option<String> {
243 if self.is_empty() {
244 return None;
245 }
246 let g = self.graphemes[self.cursor];
247
248 if graphemes::is_emoji(g) {
249 self.cursor += 1;
250 self.location.col += graphemes::width(g);
251 Some(g.to_string())
252 } else {
253 None
254 }
255 }
256
257 fn consume_alpha(&mut self) -> Option<String> {
259 if self.is_empty() {
260 return None;
261 }
262 let g = self.graphemes[self.cursor];
263 if graphemes::is_alpha(g) {
264 self.cursor += 1;
265 self.location.col += graphemes::width(g);
266 Some(g.to_string())
267 } else {
268 None
269 }
270 }
271
272 fn consume_digit(&mut self) -> Option<String> {
274 if self.is_empty() {
275 return None;
276 }
277 let g = self.graphemes[self.cursor];
278 if graphemes::is_numeric(g) {
279 self.cursor += 1;
280 self.location.col += graphemes::width(g);
281 Some(g.to_string())
282 } else {
283 None
284 }
285 }
286
287 fn loc(&self) -> SourceLocation {
289 self.location
290 }
291
292 fn is_last_grapheme(&self, c: usize) -> bool {
294 (self.graphemes.len() - 1 - c) == 0
295 }
296
297 pub fn len(&self) -> usize {
299 self.graphemes.len() - self.cursor
300 }
301
302 pub fn is_empty(&self) -> bool {
303 self.len() == 0
304 }
305
306 fn output(&self) {
308
309 println!("───────────────────{}", self.len());
310 for i in self.cursor..self.graphemes.len() {
311 print!("{}", self.graphemes[i]);
312 }
313 println!();
314 println!("───────────────────");
315 }
316}
317
318impl<'a> nom::InputLength for ParseString<'a> {
320 fn input_len(&self) -> usize {
321 self.len()
322 }
323}
324
325#[derive(Clone, Debug)]
327pub struct ParseErrorDetail {
328 pub message: &'static str,
329 pub annotation_rngs: Vec<SourceRange>,
330}
331
332#[derive(Clone, Debug)]
337pub struct ParseError<'a> {
338 pub cause_range: SourceRange,
350 pub remaining_input: ParseString<'a>,
352 pub error_detail: ParseErrorDetail,
354}
355
356impl<'a> ParseError<'a> {
357 pub fn new(input: ParseString<'a>, msg: &'static str) -> Self {
361 let start = input.loc();
362 let mut end = start;
363 end.col += 1;
364 ParseError {
365 cause_range: SourceRange { start, end },
366 remaining_input: input,
367 error_detail: ParseErrorDetail {
368 message: msg,
369 annotation_rngs: vec![],
370 }
371 }
372 }
373
374 fn log(&mut self) {
376 self.remaining_input.error_log.push((self.cause_range.clone(), self.error_detail.clone()));
377 }
378}
379
380impl<'a> nom::error::ParseError<ParseString<'a>> for ParseError<'a> {
382 fn from_error_kind(input: ParseString<'a>,
384 _kind: nom::error::ErrorKind) -> Self {
385 ParseError::new(input, format!("NomErrorKind: {:?}", _kind).leak())
386 }
387
388 fn append(_input: ParseString<'a>,
390 _kind: nom::error::ErrorKind,
391 other: Self) -> Self {
392 other
393 }
394
395 fn or(self, other: Self) -> Self {
397 let self_start = self.cause_range.start;
398 let other_start = other.cause_range.start;
399 if self_start > other_start {
400 self
401 } else {
402 other
403 }
404 }
405}
406
407pub struct TextFormatter<'a> {
410 graphemes: Vec<&'a str>,
411 line_beginnings: Vec<usize>,
412 end_index: usize,
413}
414
415impl<'a> TextFormatter<'a> {
416 pub fn new(text: &'a str) -> Self {
417 let graphemes = graphemes::init_source(text);
418 let mut line_beginnings = vec![0];
419 for i in 0..graphemes.len() {
420 if graphemes::is_new_line(graphemes[i]) {
421 line_beginnings.push(i + 1);
422 }
423 }
424 line_beginnings.pop();
425 TextFormatter {
426 end_index: graphemes.len(),
427 graphemes,
428 line_beginnings,
429 }
430 }
431
432 fn get_line_range(&self, linenum: usize) -> Option<(usize, usize)> {
435 let line_index = linenum - 1;
436 if line_index >= self.line_beginnings.len() {
437 return None;
438 }
439 if linenum == self.line_beginnings.len() { return Some((self.line_beginnings[line_index], self.end_index));
441 }
442 Some((self.line_beginnings[line_index], self.line_beginnings[linenum]))
443 }
444
445 fn get_text_by_linenum(&self, linenum: usize) -> String {
446 let (start, end) = match self.get_line_range(linenum) {
447 Some(v) => v,
448 None => return "\n".to_string(),
449 };
450 let mut s = self.graphemes[start..end].iter().map(|s| *s).collect::<String>();
451 if !s.ends_with("\n") {
452 s.push('\n');
453 }
454 s
455 }
456
457 fn get_textlen_by_linenum(&self, linenum: usize) -> usize {
458 let (start, end) = match self.get_line_range(linenum) {
459 Some(v) => v,
460 None => return 1,
461 };
462 let mut len = 0;
463 for i in start..end {
464 len += graphemes::width(self.graphemes[i]);
465 }
466 len + 1
467 }
468
469 fn heading_color(s: &str) -> String {
472 s.truecolor(246, 192, 78).bold().to_string()
473 }
474
475 fn location_color(s: &str) -> String {
476 s.truecolor(0,187,204).bold().to_string()
477 }
478
479 fn linenum_color(s: &str) -> String {
480 s.truecolor(0,187,204).bold().to_string()
481 }
482
483 fn text_color(s: &str) -> String {
484 s.to_string()
485 }
486
487 fn annotation_color(s: &str) -> String {
488 s.truecolor(102,51,153).bold().to_string()
489 }
490
491 fn error_color(s: &str) -> String {
492 s.truecolor(170,51,85).bold().to_string()
493 }
494
495 fn ending_color(s: &str) -> String {
496 s.truecolor(246, 192, 78).bold().to_string()
497 }
498
499 fn err_heading(index: usize) -> String {
500 let n = index + 1;
501 let d = "────────────────────────";
502 let s = format!("{} syntax error #{} {}\n", d, n, d);
503 Self::heading_color(&s)
504 }
505
506 fn err_location(&self, ctx: &ParserErrorContext) -> String {
507 let err_end = ctx.cause_rng.end;
508 let (row, col) = (err_end.row, err_end.col - 1);
510 let s = format!("@location:{}:{}\n", row, col);
511 Self::location_color(&s)
512 }
513
514 fn err_context(&self, ctx: &ParserErrorContext) -> String {
515 let mut result = String::new();
516
517 let mut annotation_rngs = ctx.annotation_rngs.clone();
518 annotation_rngs.push(ctx.cause_rng.clone());
519
520 let mut lines_to_print: Vec<usize> = vec![];
522 for rng in &annotation_rngs {
523 let r1 = rng.start.row;
524 let r2 = if rng.end.col == 1 {
526 usize::max(rng.start.row, rng.end.row - 1)
527 } else {
528 rng.end.row
529 };
530 for i in r1..=r2 {
531 lines_to_print.push(i);
532 }
533 }
534 lines_to_print.sort();
535 lines_to_print.dedup();
536
537 let mut range_table: HashMap<usize, Vec<(usize, usize, bool, bool)>> = HashMap::new();
540 for linenum in &lines_to_print {
541 range_table.insert(*linenum, vec![]);
542 }
543 let n = annotation_rngs.len() - 1; for (i, rng) in annotation_rngs.iter().enumerate() {
545 let (r1, c1) = (rng.start.row, rng.start.col);
547 let (r2, c2) = (rng.end.row, rng.end.col - 1);
548 if r1 == r2 { if c2 >= c1 { range_table.get_mut(&r1).unwrap().push((c1, c2 - c1 + 1, true, i == n));
551 }
552 } else { range_table.get_mut(&r1).unwrap().push((c1, usize::MAX, i != n, i == n));
554 for r in r1+1..r2 {
555 range_table.get_mut(&r).unwrap().push((1, usize::MAX, false, i == n));
556 }
557 if c2 != 0 { range_table.get_mut(&r2).unwrap().push((1, c2, i == n, i == n));
559 }
560 }
561 }
562
563 let dots = "...";
565 let indentation = " ";
566 let vert_split1 = " │";
567 let vert_split2 = " ";
568 let arrow = "^";
569 let tilde = "~";
570 let lines_str: Vec<String> = lines_to_print.iter().map(|i| i.to_string()).collect();
571 let row_str_len = usize::max(lines_str.last().unwrap().len(), dots.len());
572
573 for i in 0..lines_to_print.len() {
575 if i != 0 && (lines_to_print[i] - lines_to_print[i-1] != 1) {
577 result.push_str(indentation);
578 for _ in 3..row_str_len { result.push(' '); }
579 result.push_str(&Self::linenum_color(dots));
580 result.push_str(&Self::linenum_color(vert_split1));
581 result.push('\n');
582 }
583
584 result.push_str(indentation);
586 for _ in 0..row_str_len { result.push(' '); }
587 result.push_str(&Self::linenum_color(vert_split1));
588 result.push('\n');
589
590 let text = self.get_text_by_linenum(lines_to_print[i]);
592 result.push_str(indentation);
593 for _ in 0..row_str_len-lines_str[i].len() { result.push(' '); }
594 result.push_str(&Self::linenum_color(&lines_str[i]));
595 result.push_str(&Self::linenum_color(vert_split1));
596 result.push_str(&Self::text_color(&text));
597
598 result.push_str(indentation);
600 for _ in 0..row_str_len { result.push(' '); }
601 result.push_str(&Self::linenum_color(vert_split1));
602 let mut curr_col = 1;
603 let line_len = self.get_textlen_by_linenum(lines_to_print[i]);
604 let rngs = range_table.get(&lines_to_print[i]).unwrap();
605 for (start, len, major, cause) in rngs {
606 let max_len = usize::max(1, usize::min(*len, line_len - curr_col + 1));
607 for _ in curr_col..*start { result.push(' '); }
608 if *cause {
609 for _ in 0..max_len-1 {
610 result.push_str(&Self::error_color(tilde));
611 }
612 if *major {
613 result.push_str(&Self::error_color(arrow));
614 } else {
615 result.push_str(&Self::error_color(tilde));
616 }
617 } else {
618 if *major {
619 result.push_str(&Self::annotation_color(arrow));
620 } else {
621 result.push_str(&Self::annotation_color(tilde));
622 }
623 for _ in 0..max_len-1 {
624 result.push_str(&Self::annotation_color(tilde));
625 }
626 }
627 curr_col = start + max_len;
628 }
629 result.push('\n');
630 }
631
632 let cause_col = ctx.cause_rng.end.col - 1;
635 result.push_str(indentation);
636 for _ in 0..row_str_len { result.push(' '); }
637 result.push_str(vert_split2);
638 for _ in 0..cause_col-1 { result.push(' '); }
639 result.push_str(&Self::error_color(&ctx.err_message));
640 result.push('\n');
641
642 result
643 }
644
645 fn err_ending(d: usize) -> String {
646 let s = format!("... and {} other error{} not shown\n", d, if d == 1 {""} else {"s"});
647 Self::heading_color(&s)
648 }
649
650 pub fn format_error(&self, errors: &ParserErrorReport) -> String {
652 let n = usize::min(errors.1.len(), 10);
653 let mut result = String::new();
654 result.push('\n');
655 for i in 0..n {
656 let ctx = &errors.1[i];
657 result.push_str(&Self::err_heading(i));
658 result.push_str(&self.err_location(ctx));
659 result.push_str(&self.err_context(ctx));
660 result.push_str("\n\n");
661 }
662 let d = errors.0.len() - n;
663 if d != 0 {
664 result.push_str(&Self::err_ending(d));
665 }
666 result
667 }
668}
669
670#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
671#[derive(Clone, Debug, Eq, PartialEq, Hash)]
672pub struct ParserErrorContext {
673 pub cause_rng: SourceRange,
674 pub err_message: String,
675 pub annotation_rngs: Vec<SourceRange>,
676}
677
678#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
679#[derive(Clone, Debug, PartialEq, Eq, Hash)]
680pub struct ParserErrorReport(pub String, pub Vec<ParserErrorContext>);
681
682impl MechErrorKind for ParserErrorReport {
683 fn name(&self) -> &str {
684 "ParserErrorContext"
685 }
686 fn message(&self) -> String {
687 let source = &self.0;
688 let lines: Vec<&str> = source.lines().collect();
689
690 self.1
691 .iter()
692 .map(|e| {
693 let cause_snippet = extract_snippet(&lines, &e.cause_rng);
694
695 let annotation_snippets = e.annotation_rngs
696 .iter()
697 .map(|rng| extract_snippet(&lines, rng))
698 .collect::<Vec<_>>()
699 .join("\n");
700
701 format!(
702 "{}: {} (Annotations: [{}])\n\nSource:\n{}\n\nAnnotations:\n{}",
703 format!(
704 "[{}:{}-{}:{}]",
705 e.cause_rng.start.row,
706 e.cause_rng.start.col,
707 e.cause_rng.end.row,
708 e.cause_rng.end.col
709 ),
710 e.err_message,
711 e.annotation_rngs.iter()
712 .map(|rng| format!(
713 "[{}:{}-{}:{}]",
714 rng.start.row, rng.start.col, rng.end.row, rng.end.col
715 ))
716 .collect::<Vec<_>>()
717 .join(", "),
718 indent(&cause_snippet),
719 indent(&annotation_snippets)
720 )
721 })
722 .collect::<Vec<_>>()
723 .join("\n\n---\n\n")
724 }
725}
726
727fn extract_snippet(lines: &[&str], range: &SourceRange) -> String {
728 let mut out = String::new();
729
730 for row in range.start.row..=range.end.row {
731 if let Some(line) = lines.get(row) {
732 let start = if row == range.start.row { range.start.col } else { 0 };
733 let end = if row == range.end.row { range.end.col } else { line.len() };
734
735 let end = end.min(line.len());
736
737 if start <= end {
738 out.push_str(&line[start..end]);
739 }
740 out.push('\n');
741 }
742 }
743
744 out
745}
746
747fn indent(s: &str) -> String {
748 s.lines()
749 .map(|line| format!(" {}", line))
750 .collect::<Vec<_>>()
751 .join("\n")
752}
753
754pub fn alt_best<'a, O>(
757 input: ParseString<'a>,
758 parsers: &[(&'static str, Box<dyn Fn(ParseString) -> ParseResult<O>>)],
759) -> ParseResult<'a, O> {
760 let start_cursor = input.cursor;
761
762 let mut best_success: Option<(ParseString, O, usize, &'static str)> = None;
763 let mut best_failure: Option<(nom::Err<ParseError>, usize, &'static str)> = None;
764 let mut best_error: Option<(nom::Err<ParseError>, usize, &'static str)> = None;
765
766 for (name, parser) in parsers {
767 match parser(input.clone()) {
768 Ok((next_input, val)) => {
769 if *name == "mech_code" {
770 return Ok((next_input, val));
771 }
772 let consumed = next_input.cursor;
773 if best_success.is_none() || consumed > best_success.as_ref().unwrap().2 {
774 best_success = Some((next_input, val, consumed, name));
775 }
776 }
777
778 Err(nom::Err::Failure(e)) => {
779 let reached = e.remaining_input.cursor;
780 if best_failure.is_none() || reached > best_failure.as_ref().unwrap().1 {
781 best_failure = Some((nom::Err::Failure(e), reached, name));
782 }
783 }
784
785 Err(nom::Err::Error(e)) => {
786 let reached = e.remaining_input.cursor;
787 if best_error.is_none() || reached > best_error.as_ref().unwrap().1 {
788 best_error = Some((nom::Err::Error(e), reached, name));
789 }
790 }
791
792 Err(e @ nom::Err::Incomplete(_)) => {
793 return Err(e);
794 }
795 }
796 }
797
798 if let Some((next_input, val, success_cursor, _)) = best_success {
800 if let Some((nom::Err::Failure(failure), failure_cursor, _)) = best_failure {
801 if success_cursor > failure_cursor {
802 Ok((next_input, val))
803 } else {
804 Err(nom::Err::Failure(failure))
805 }
806 } else {
807 Ok((next_input, val))
808 }
809 } else if let Some((nom::Err::Failure(failure), _, _)) = best_failure {
810 Err(nom::Err::Failure(failure))
811 } else if let Some((err, _, _)) = best_error {
812 Err(err)
813 } else {
814 Err(nom::Err::Error(ParseError::new(
815 input,
816 "No parser matched in alt_best",
817 )))
818 }
819}