diff options
author | Akshay <[email protected]> | 2021-03-25 07:38:25 +0000 |
---|---|---|
committer | Akshay <[email protected]> | 2021-03-25 07:38:25 +0000 |
commit | 8171b30adbc4cddd2c51f043c3379d78428666b8 (patch) | |
tree | 85e34bef77d330a5df52eef3bb2f249453329934 /src/lisp | |
parent | 5a232822a25604e669740a803eea8d9889772d74 (diff) |
use new error kinds; track Environment nesting with stack
Diffstat (limited to 'src/lisp')
-rw-r--r-- | src/lisp/lex.rs | 64 | ||||
-rw-r--r-- | src/lisp/mod.rs | 3 | ||||
-rw-r--r-- | src/lisp/number.rs | 6 | ||||
-rw-r--r-- | src/lisp/parse.rs | 55 |
4 files changed, 85 insertions, 43 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]))); |
diff --git a/src/lisp/mod.rs b/src/lisp/mod.rs index a52baa0..87a2720 100644 --- a/src/lisp/mod.rs +++ b/src/lisp/mod.rs | |||
@@ -4,10 +4,11 @@ pub mod expr; | |||
4 | pub mod lex; | 4 | pub mod lex; |
5 | pub mod number; | 5 | pub mod number; |
6 | pub mod parse; | 6 | pub mod parse; |
7 | mod primitives; | 7 | pub mod prelude; |
8 | 8 | ||
9 | use std::collections::HashMap; | 9 | use std::collections::HashMap; |
10 | 10 | ||
11 | use expr::LispExpr; | 11 | use expr::LispExpr; |
12 | 12 | ||
13 | pub type Environment = HashMap<String, LispExpr>; | 13 | pub type Environment = HashMap<String, LispExpr>; |
14 | pub type EnvList = Vec<Environment>; | ||
diff --git a/src/lisp/number.rs b/src/lisp/number.rs index 18a41f7..23d7997 100644 --- a/src/lisp/number.rs +++ b/src/lisp/number.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | fmt, | 2 | fmt, |
3 | ops::{Add, Div, Mul, Sub}, | 3 | ops::{Add, Mul, Sub}, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::lisp::error::LispError; | 6 | use crate::lisp::error::{EvalError, LispError}; |
7 | 7 | ||
8 | #[derive(Debug, Copy, Clone)] | 8 | #[derive(Debug, Copy, Clone)] |
9 | pub enum LispNumber { | 9 | pub enum LispNumber { |
@@ -15,7 +15,7 @@ impl LispNumber { | |||
15 | pub fn div(self, rhs: Self) -> Result<LispNumber, LispError> { | 15 | pub fn div(self, rhs: Self) -> Result<LispNumber, LispError> { |
16 | use LispNumber::*; | 16 | use LispNumber::*; |
17 | if rhs == Integer(0) || rhs == Float(0.) { | 17 | if rhs == Integer(0) || rhs == Float(0.) { |
18 | return Err(LispError::EvalError); | 18 | return Err(EvalError::DivByZero.into()); |
19 | } else { | 19 | } else { |
20 | return Ok(match (self, rhs) { | 20 | return Ok(match (self, rhs) { |
21 | (Integer(a), Integer(b)) => Float(a as f64 / b as f64), | 21 | (Integer(a), Integer(b)) => Float(a as f64 / b as f64), |
diff --git a/src/lisp/parse.rs b/src/lisp/parse.rs index 89a272a..4e0f427 100644 --- a/src/lisp/parse.rs +++ b/src/lisp/parse.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use crate::lisp::{ | 1 | use crate::lisp::{ |
2 | error::LispError, | 2 | error::{LispError, ParseError, ParseErrorKind}, |
3 | lex::{Lexer, Span, Token}, | 3 | lex::{Lexer, Span, Token}, |
4 | number::LispNumber, | 4 | number::LispNumber, |
5 | LispExpr, | 5 | LispExpr, |
@@ -10,26 +10,6 @@ pub struct Parser<'lex> { | |||
10 | cur_token: Option<(Span, Token<'lex>)>, | 10 | cur_token: Option<(Span, Token<'lex>)>, |
11 | } | 11 | } |
12 | 12 | ||
13 | // pub struct ParseError { | ||
14 | // pub span: Span, | ||
15 | // pub kind: ParseErrorKind, | ||
16 | // } | ||
17 | // | ||
18 | // pub enum ParseErrorKind { | ||
19 | // InvalidLiteral, | ||
20 | // InvalidToken, | ||
21 | // LiteralParseError, | ||
22 | // MissingCloseParen, | ||
23 | // UnbalancedComma, | ||
24 | // UnexpectedEof, | ||
25 | // UnexpectedToken { | ||
26 | // expected: &'static str, | ||
27 | // found: &'static str, | ||
28 | // }, | ||
29 | // UnmatchedParen, | ||
30 | // UnterminatedString, | ||
31 | // } | ||
32 | |||
33 | enum Group { | 13 | enum Group { |
34 | Backticks(i32), | 14 | Backticks(i32), |
35 | CommaAt, | 15 | CommaAt, |
@@ -49,7 +29,7 @@ impl<'lex> Parser<'lex> { | |||
49 | let mut stack = Vec::new(); | 29 | let mut stack = Vec::new(); |
50 | let mut total_backticks = 0; | 30 | let mut total_backticks = 0; |
51 | loop { | 31 | loop { |
52 | let (_, token) = self.next()?; | 32 | let (span, token) = self.next()?; |
53 | let r: Result<LispExpr, LispError> = match token { | 33 | let r: Result<LispExpr, LispError> = match token { |
54 | Token::LeftParen => { | 34 | Token::LeftParen => { |
55 | stack.push(Group::Parens(Vec::new())); | 35 | stack.push(Group::Parens(Vec::new())); |
@@ -57,21 +37,27 @@ impl<'lex> Parser<'lex> { | |||
57 | } | 37 | } |
58 | Token::RightParen => { | 38 | Token::RightParen => { |
59 | let group = stack.pop().ok_or_else( | 39 | let group = stack.pop().ok_or_else( |
60 | || LispError::ParseError, // unmatched paren here | 40 | || (ParseError::new(span, ParseErrorKind::UnmatchedParen)), // unmatched paren here |
61 | )?; | 41 | )?; |
62 | match group { | 42 | match group { |
63 | Group::Parens(v) => Ok(LispExpr::List(v)), | 43 | Group::Parens(v) => Ok(LispExpr::List(v)), |
64 | _ => Err(LispError::ParseError), | 44 | _ => Err(From::from(ParseError::new( |
45 | span, | ||
46 | ParseErrorKind::UnexpectedToken { | ||
47 | expected: "expression", | ||
48 | found: "(", | ||
49 | }, | ||
50 | ))), | ||
65 | } | 51 | } |
66 | } | 52 | } |
67 | Token::Float(f) => f | 53 | Token::Float(f) => f |
68 | .parse::<f64>() | 54 | .parse::<f64>() |
69 | .map(|n| LispExpr::Number(LispNumber::Float(n))) | 55 | .map(|n| LispExpr::Number(LispNumber::Float(n))) |
70 | .map_err(|_| LispError::ParseError), | 56 | .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError).into()), |
71 | Token::Integer(i) => i | 57 | Token::Integer(i) => i |
72 | .parse::<i64>() | 58 | .parse::<i64>() |
73 | .map(|n| LispExpr::Number(LispNumber::Integer(n))) | 59 | .map(|n| LispExpr::Number(LispNumber::Integer(n))) |
74 | .map_err(|_| LispError::ParseError), | 60 | .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError).into()), |
75 | Token::String(s) => Ok(LispExpr::StringLit(s.into())), | 61 | Token::String(s) => Ok(LispExpr::StringLit(s.into())), |
76 | Token::Name(n) => Ok(name_expr(n)), | 62 | Token::Name(n) => Ok(name_expr(n)), |
77 | Token::BackQuote => { | 63 | Token::BackQuote => { |
@@ -85,7 +71,7 @@ impl<'lex> Parser<'lex> { | |||
85 | } | 71 | } |
86 | Token::Comma => { | 72 | Token::Comma => { |
87 | if total_backticks <= 0 { | 73 | if total_backticks <= 0 { |
88 | return Err(LispError::ParseError); // unbalanced comma | 74 | return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma).into()); |
89 | } | 75 | } |
90 | total_backticks -= 1; | 76 | total_backticks -= 1; |
91 | if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() { | 77 | if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() { |
@@ -97,7 +83,7 @@ impl<'lex> Parser<'lex> { | |||
97 | } | 83 | } |
98 | Token::CommaAt => { | 84 | Token::CommaAt => { |
99 | if total_backticks <= 0 { | 85 | if total_backticks <= 0 { |
100 | return Err(LispError::ParseError); // unbalanced comma | 86 | return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma).into()); |
101 | } | 87 | } |
102 | total_backticks -= 1; | 88 | total_backticks -= 1; |
103 | stack.push(Group::CommaAt); | 89 | stack.push(Group::CommaAt); |
@@ -118,9 +104,9 @@ impl<'lex> Parser<'lex> { | |||
118 | }); | 104 | }); |
119 | 105 | ||
120 | if any_paren { | 106 | if any_paren { |
121 | Err(LispError::ParseError) // unbalanced paren | 107 | Err(ParseError::new(span, ParseErrorKind::MissingCloseParen).into()) |
122 | } else { | 108 | } else { |
123 | Err(LispError::ParseError) // unexpected eof | 109 | Err(ParseError::new(span, ParseErrorKind::UnexpectedEof).into()) |
124 | } | 110 | } |
125 | } | 111 | } |
126 | }; | 112 | }; |
@@ -178,7 +164,14 @@ impl<'lex> Parser<'lex> { | |||
178 | 164 | ||
179 | match self.next()? { | 165 | match self.next()? { |
180 | (_, Token::End) => Ok(expr), | 166 | (_, Token::End) => Ok(expr), |
181 | _ => Err(LispError::ParseError), // too many tokens | 167 | (span, token) => Err(ParseError::new( |
168 | span, | ||
169 | ParseErrorKind::UnexpectedToken { | ||
170 | expected: "EOF", | ||
171 | found: token.name(), | ||
172 | }, | ||
173 | ) | ||
174 | .into()), | ||
182 | } | 175 | } |
183 | } | 176 | } |
184 | 177 | ||