1use std::collections::VecDeque;
2use std::{env, fmt};
3
4use crate::build::{SymbolGraph, UUId};
5
6pub struct TrailError(pub String);
7
8impl fmt::Debug for TrailError {
9 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10 write!(f, "\n{}", self.0)
11 }
12}
13
14impl fmt::Display for TrailError {
15 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16 write!(f, "{}", self.0)
17 }
18}
19
20impl std::error::Error for TrailError {}
21
22pub fn consume_lexeme(lexemes: &mut Vec<String>, accumulate: &mut Vec<char>) {
23 if accumulate.len() > 0 {
24 lexemes.push(accumulate.iter().collect());
25 accumulate.clear();
26 }
27}
28
29pub fn is_escaped(unicodes: &Vec<char>, index: usize) -> bool {
30 let mut count: i32 = 0;
31 let mut index: i32 = index as i32 - 1;
32
33 while index >= 0 && unicodes[index as usize] == '\\' {
34 count += 1;
35 index -= 1;
36 }
37
38 return count % 2 == 1;
39}
40
41pub fn peek(unicodes: &Vec<char>, index: usize, offset: i32) -> char {
42 let result = index as i32 + offset;
43 if 0 <= result && (result as usize) < unicodes.len() {
44 return unicodes[result as usize];
45 } else {
46 return '\0';
47 }
48}
49
50pub fn get_env(key: &str, default: bool) -> bool {
51 return env::var(key)
52 .ok()
53 .and_then(|s| s.parse::<i32>().ok())
54 .map(|n| n != 0)
55 .unwrap_or(default);
56}
57
58pub fn contains_special_characters(head: &str) -> bool {
59 return head.chars().any(|c| "[@!#$%^&*()<>?/\\|}~:".contains(c));
60}
61
62pub fn bfs<'a>(graph: &'a SymbolGraph, start: Vec<UUId>) -> Vec<UUId> {
63 let mut visited: Vec<UUId> = Vec::new();
64 let mut queue: VecDeque<UUId> = start.into_iter().collect();
65
66 while !queue.is_empty() {
67 let vertex = queue.pop_front().unwrap();
68
69 if !visited.contains(&vertex) {
70 visited.push(vertex);
71
72 let successors = graph.edges.get(&vertex).cloned().unwrap_or_default();
73 queue.extend(successors);
74 }
75 }
76
77 return visited;
78}
79
80pub fn format_error(header: &str, context: &str, source: &str) -> String {
81 const RED: &str = "\x1b[31m";
82 const BLUE: &str = "\x1b[34m";
83 const YELLOW: &str = "\x1b[33m";
84 const BOLD: &str = "\x1b[1m";
85 const RESET: &str = "\x1b[0m";
86
87 let markers = (".".repeat(context.len()), "^".repeat(source.len()));
88
89 format!(
90 "{BOLD}{RED}error{RESET}: {header}\n\
91 {BOLD}{BLUE} |{RESET}\n\
92 {BOLD}{BLUE} |{RESET} {context}{source}\n\
93 {BOLD}{BLUE} |{RESET} {BOLD}{YELLOW}{}{BOLD}{RED}{}{RESET}",
94 markers.0, markers.1,
95 )
96}