1pub use nargo_types::{Cursor, Error, ErrorKind, Position, Span};
2use std::collections::HashMap;
3
4pub struct ParseState<'a> {
5 pub cursor: Cursor<'a>,
6}
7
8impl<'a> ParseState<'a> {
9 pub fn new(source: &'a str) -> Self {
10 Self { cursor: Cursor::new(source) }
11 }
12
13 pub fn new_with_pos(source: &'a str, pos: Position) -> Self {
14 Self { cursor: Cursor::with_position(source, pos) }
15 }
16
17 pub fn with_cursor(cursor: Cursor<'a>) -> Self {
18 Self { cursor }
19 }
20
21 pub fn get_context(&self, radius: usize) -> String {
23 let start = if self.cursor.pos > radius { self.cursor.pos - radius } else { 0 };
24 let end = if self.cursor.pos + radius < self.cursor.source.len() { self.cursor.pos + radius } else { self.cursor.source.len() };
25 self.cursor.source[start..end].to_string()
26 }
27
28 pub fn format_error_message(&self, message: &str) -> String {
30 let line = self.cursor.line;
31 let column = self.cursor.column;
32 let context = self.get_context(20);
33 let pointer = " ".repeat(20 - (self.cursor.pos % 20)) + "^";
34
35 format!("Error at line {}, column {}:\n{}\n{}\n{}", line, column, message, context, pointer)
36 }
37
38 pub fn unexpected_char(&self) -> Error {
39 let message = format!("Unexpected character '{}'", self.cursor.peek());
40 let formatted_message = self.format_error_message(&message);
41 Error::new(ErrorKind::UnexpectedChar { character: self.cursor.peek(), span: self.cursor.span_at_current() })
42 }
43
44 pub fn expected_char(&self, expected: char) -> Error {
45 let message = format!("Expected '{}', found '{}'", expected, self.cursor.peek());
46 let formatted_message = self.format_error_message(&message);
47 Error::new(ErrorKind::ExpectedChar { expected, found: self.cursor.peek(), span: self.cursor.span_at_current() })
48 }
49
50 pub fn expected_string(&self, expected: &str) -> Error {
51 let message = format!("Expected '{}', found '{}'", expected, self.cursor.peek());
52 let formatted_message = self.format_error_message(&message);
53 Error::new(ErrorKind::ExpectedString { expected: expected.to_string(), found: self.cursor.peek().to_string(), span: self.cursor.span_at_current() })
54 }
55
56 pub fn error(&self, message: impl Into<String>) -> Error {
57 let message = message.into();
58 let formatted_message = self.format_error_message(&message);
59 Error::new(ErrorKind::Parse { message: formatted_message, span: self.cursor.span_at_current() })
60 }
61
62 pub fn expected_token(&self, expected: &str) -> Error {
64 let message = format!("Expected '{}' token", expected);
65 let formatted_message = self.format_error_message(&message);
66 Error::new(ErrorKind::Parse { message: formatted_message, span: self.cursor.span_at_current() })
67 }
68
69 pub fn syntax_error(&self, message: impl Into<String>) -> Error {
71 let message = format!("Syntax error: {}", message.into());
72 let formatted_message = self.format_error_message(&message);
73 Error::new(ErrorKind::Parse { message: formatted_message, span: self.cursor.span_at_current() })
74 }
75
76 pub fn type_error(&self, message: impl Into<String>) -> Error {
78 let message = format!("Type error: {}", message.into());
79 let formatted_message = self.format_error_message(&message);
80 Error::new(ErrorKind::Parse { message: formatted_message, span: self.cursor.span_at_current() })
81 }
82
83 pub fn parse_tag_attributes(&mut self) -> HashMap<String, String> {
84 let mut attrs = HashMap::new();
85 self.cursor.skip_whitespace();
86 while !self.cursor.is_eof() && self.cursor.peek() != '>' {
87 let start = self.cursor.pos;
88 while !self.cursor.is_eof() && !self.cursor.peek().is_whitespace() && self.cursor.peek() != '=' && self.cursor.peek() != '>' {
89 self.cursor.consume();
90 }
91 let key = self.cursor.current_str(start).to_string();
92 self.cursor.skip_whitespace();
93 if self.cursor.peek() == '=' {
94 self.cursor.consume();
95 self.cursor.skip_whitespace();
96 let quote = self.cursor.peek();
97 if quote == '"' || quote == '\'' {
98 self.cursor.consume();
99 let val_start = self.cursor.pos;
100 while !self.cursor.is_eof() && self.cursor.peek() != quote {
101 self.cursor.consume();
102 }
103 let val = self.cursor.current_str(val_start).to_string();
104 let _ = self.cursor.consume(); attrs.insert(key, val);
106 }
107 else {
108 let val_start = self.cursor.pos;
109 while !self.cursor.is_eof() && !self.cursor.peek().is_whitespace() && self.cursor.peek() != '>' {
110 self.cursor.consume();
111 }
112 let val = self.cursor.current_str(val_start).to_string();
113 attrs.insert(key, val);
114 }
115 }
116 else {
117 attrs.insert(key, "true".to_string());
118 }
119 self.cursor.skip_whitespace();
120 }
121 attrs
122 }
123}