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