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