aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-25 07:38:25 +0000
committerAkshay <[email protected]>2021-03-25 07:38:25 +0000
commit8171b30adbc4cddd2c51f043c3379d78428666b8 (patch)
tree85e34bef77d330a5df52eef3bb2f249453329934 /src/lisp
parent5a232822a25604e669740a803eea8d9889772d74 (diff)
use new error kinds; track Environment nesting with stack
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/lex.rs64
-rw-r--r--src/lisp/mod.rs3
-rw-r--r--src/lisp/number.rs6
-rw-r--r--src/lisp/parse.rs55
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 @@
1use std::{fmt, str::CharIndices}; 1use std::{fmt, str::CharIndices};
2 2
3use super::error::LispError; 3use crate::lisp::error::{LispError, ParseError, ParseErrorKind};
4 4
5#[derive(Copy, Clone, Debug, Eq, PartialEq)] 5#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6pub enum Token<'a> { 6pub enum Token<'a> {
@@ -19,6 +19,26 @@ pub enum Token<'a> {
19 End, 19 End,
20} 20}
21 21
22impl<'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
22impl<'a> fmt::Display for Token<'a> { 42impl<'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)]
78pub struct SpanDisplay<'src> {
79 pub source: &'src str,
80 pub line: usize,
81 pub col: usize,
82}
83
84impl<'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
57pub struct Lexer<'input> { 96pub 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
116fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), LispError> { 164fn 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
159fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), LispError> { 207fn 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
200fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), LispError> { 248fn 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;
4pub mod lex; 4pub mod lex;
5pub mod number; 5pub mod number;
6pub mod parse; 6pub mod parse;
7mod primitives; 7pub mod prelude;
8 8
9use std::collections::HashMap; 9use std::collections::HashMap;
10 10
11use expr::LispExpr; 11use expr::LispExpr;
12 12
13pub type Environment = HashMap<String, LispExpr>; 13pub type Environment = HashMap<String, LispExpr>;
14pub 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 @@
1use std::{ 1use std::{
2 fmt, 2 fmt,
3 ops::{Add, Div, Mul, Sub}, 3 ops::{Add, Mul, Sub},
4}; 4};
5 5
6use crate::lisp::error::LispError; 6use crate::lisp::error::{EvalError, LispError};
7 7
8#[derive(Debug, Copy, Clone)] 8#[derive(Debug, Copy, Clone)]
9pub enum LispNumber { 9pub 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 @@
1use crate::lisp::{ 1use 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
33enum Group { 13enum 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