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