diff options
Diffstat (limited to 'src/lisp/lex.rs')
-rw-r--r-- | src/lisp/lex.rs | 64 |
1 files changed, 56 insertions, 8 deletions
diff --git a/src/lisp/lex.rs b/src/lisp/lex.rs index a7b9586..b307e80 100644 --- a/src/lisp/lex.rs +++ b/src/lisp/lex.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::{fmt, str::CharIndices}; | 1 | use std::{fmt, str::CharIndices}; |
2 | 2 | ||
3 | use super::error::LispError; | 3 | use crate::lisp::error::{LispError, ParseError, ParseErrorKind}; |
4 | 4 | ||
5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | 5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
6 | pub enum Token<'a> { | 6 | pub enum Token<'a> { |
@@ -19,6 +19,26 @@ pub enum Token<'a> { | |||
19 | End, | 19 | End, |
20 | } | 20 | } |
21 | 21 | ||
22 | impl<'a> Token<'a> { | ||
23 | pub fn name(&self) -> &'static str { | ||
24 | match self { | ||
25 | Token::LeftParen => "(", | ||
26 | Token::RightParen => ")", | ||
27 | Token::Float(_) => "float", | ||
28 | Token::Integer(_) => "integer", | ||
29 | // Token::Char(_) => "char", | ||
30 | Token::String(_) => "string", | ||
31 | Token::Name(_) => "name", | ||
32 | // Token::Keyword(_) => "keyword", | ||
33 | Token::BackQuote => "`", | ||
34 | Token::Comma => ",", | ||
35 | Token::CommaAt => ",@", | ||
36 | Token::Quote => "'", | ||
37 | Token::End => "EOF", | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
22 | impl<'a> fmt::Display for Token<'a> { | 42 | impl<'a> fmt::Display for Token<'a> { |
23 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 43 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
24 | match self { | 44 | match self { |
@@ -54,6 +74,25 @@ impl Span { | |||
54 | } | 74 | } |
55 | } | 75 | } |
56 | 76 | ||
77 | #[derive(Debug, Clone)] | ||
78 | pub struct SpanDisplay<'src> { | ||
79 | pub source: &'src str, | ||
80 | pub line: usize, | ||
81 | pub col: usize, | ||
82 | } | ||
83 | |||
84 | impl<'src> SpanDisplay<'src> { | ||
85 | pub fn highlight_span(span: Span, source: &'src str) -> Self { | ||
86 | let line_start = match source[..span.low as usize].rfind('\n') { | ||
87 | Some(pos) => pos + 1, | ||
88 | None => 0, | ||
89 | }; | ||
90 | let line = source[..line_start].chars().filter(|&c| c == '\n').count() + 1; | ||
91 | let col = source[line_start..span.low as usize].chars().count(); | ||
92 | Self { source, line, col } | ||
93 | } | ||
94 | } | ||
95 | |||
57 | pub struct Lexer<'input> { | 96 | pub struct Lexer<'input> { |
58 | input: &'input str, | 97 | input: &'input str, |
59 | cur_pos: u32, | 98 | cur_pos: u32, |
@@ -68,6 +107,7 @@ impl<'a> Lexer<'a> { | |||
68 | offset, | 107 | offset, |
69 | } | 108 | } |
70 | } | 109 | } |
110 | |||
71 | pub fn next_token(&mut self) -> Result<(Span, Token<'a>), LispError> { | 111 | pub fn next_token(&mut self) -> Result<(Span, Token<'a>), LispError> { |
72 | let mut chars = self.input.char_indices(); | 112 | let mut chars = self.input.char_indices(); |
73 | 113 | ||
@@ -94,11 +134,19 @@ impl<'a> Lexer<'a> { | |||
94 | self.cur_pos += ch.len_utf8() as u32; | 134 | self.cur_pos += ch.len_utf8() as u32; |
95 | continue; | 135 | continue; |
96 | } | 136 | } |
97 | _ => Err(LispError::ParseError), | 137 | ch => Err(ParseErrorKind::InvalidChar(ch)), |
98 | }; | 138 | }; |
99 | let (size, token) = match res { | 139 | let (size, token) = match res { |
100 | Ok(v) => v, | 140 | Ok(v) => v, |
101 | Err(_) => return Err(LispError::ParseError), | 141 | Err(kind) => { |
142 | return Err(LispError::Parse(ParseError { | ||
143 | span: Span { | ||
144 | low, | ||
145 | high: low + chr.len_utf8() as u32, | ||
146 | }, | ||
147 | kind, | ||
148 | })) | ||
149 | } | ||
102 | }; | 150 | }; |
103 | self.cur_pos += size as u32; | 151 | self.cur_pos += size as u32; |
104 | self.input = &self.input[ind + size..]; | 152 | self.input = &self.input[ind + size..]; |
@@ -113,7 +161,7 @@ impl<'a> Lexer<'a> { | |||
113 | } | 161 | } |
114 | } | 162 | } |
115 | 163 | ||
116 | fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), LispError> { | 164 | fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { |
117 | let mut dot = false; | 165 | let mut dot = false; |
118 | let mut minus = false; | 166 | let mut minus = false; |
119 | let mut size = 0; | 167 | let mut size = 0; |
@@ -137,12 +185,12 @@ fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), LispError> | |||
137 | dot = true; | 185 | dot = true; |
138 | size += 1; | 186 | size += 1; |
139 | } else { | 187 | } else { |
140 | return Err(LispError::ParseError); | 188 | return Err(ParseErrorKind::InvalidChar(chr)); |
141 | } | 189 | } |
142 | } else if !is_ident(chr) { | 190 | } else if !is_ident(chr) { |
143 | break; | 191 | break; |
144 | } else { | 192 | } else { |
145 | return Err(LispError::ParseError); | 193 | return Err(ParseErrorKind::InvalidChar(chr)); |
146 | } | 194 | } |
147 | } | 195 | } |
148 | 196 | ||
@@ -156,7 +204,7 @@ fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), LispError> | |||
156 | return Ok((size, tok)); | 204 | return Ok((size, tok)); |
157 | } | 205 | } |
158 | 206 | ||
159 | fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), LispError> { | 207 | fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { |
160 | // count opening quote | 208 | // count opening quote |
161 | let mut size = 1; | 209 | let mut size = 1; |
162 | let mut chars = input.char_indices().skip(1); | 210 | let mut chars = input.char_indices().skip(1); |
@@ -197,7 +245,7 @@ fn consume_comment(start: usize, chars: &mut CharIndices) -> usize { | |||
197 | last - start + 1 | 245 | last - start + 1 |
198 | } | 246 | } |
199 | 247 | ||
200 | fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), LispError> { | 248 | fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { |
201 | for (ind, chr) in input.char_indices() { | 249 | for (ind, chr) in input.char_indices() { |
202 | if !is_ident(chr) { | 250 | if !is_ident(chr) { |
203 | return Ok((ind, Token::Name(&input[..ind]))); | 251 | return Ok((ind, Token::Name(&input[..ind]))); |