feat(parser): add expression parser

This commit is contained in:
Jonas Röger 2024-11-05 20:20:46 +01:00
parent 33250c0272
commit 53e6ac8132
Signed by: jonas
GPG Key ID: 4000EB35E1AE0F07
5 changed files with 187 additions and 49 deletions

View File

@ -1,2 +1,8 @@
pub mod environment;
pub mod expression;
pub use environment::Environment;
pub use environment::EnvironmentLayer;
pub use expression::eval_prelude;
pub use expression::EvalError;
pub use expression::Expression;

View File

@ -1,56 +1,21 @@
mod lisp;
mod parser;
use lisp::expression::{eval_prelude, Expression};
use lisp::eval_prelude;
use parser::ExpressionStream;
fn main() {
let mut test = "(add 10 (sub 1.1 200.5)) (concat-if true \"true\" 'nil (a . b))".chars();
let program = "((lambda (x y) (add (if (lt x 10) (add x 10) x) y)) 2 20)";
let mut tkns = parser::tokenizer::tokenize(&mut test);
while let Some(tk) = tkns.next() {
println!("{:?}", tk);
for r in ExpressionStream::from_char_stream(program.chars()) {
match r {
Err(err) => println!("ParserError: {:?}", err),
Ok(expr) => println!(
"{:?} \n vvvvvvvvvvv \n {:?}\n",
expr.clone(),
eval_prelude(expr)
),
}
}
let expr: Expression = vec![
vec![
Expression::Symbol("lambda".to_string()),
vec![
Expression::Symbol("x".to_string()),
Expression::Symbol("y".to_string()),
]
.into(),
vec![
Expression::Symbol("if".to_string()),
vec![
Expression::Symbol("==".to_string()),
Expression::Symbol("x".to_string()),
Expression::Integer(5),
]
.into(),
vec![
Expression::Symbol("add".to_string()),
Expression::Symbol("x".to_string()),
Expression::Symbol("y".to_string()),
]
.into(),
Expression::String("x is not 5".to_string()),
]
.into(),
]
.into(),
Expression::Integer(5),
vec![
Expression::Symbol("let".to_string()),
vec![Expression::Cell(
Box::new(Expression::Symbol("y".to_string())),
Box::new(Expression::Integer(7)),
)]
.into(),
Expression::Symbol("y".to_string()),
]
.into(),
]
.into();
println!("{:?} evaluates to {:?}", expr.clone(), eval_prelude(expr));
println!("Interpreter Done!");
}

View File

@ -1,2 +1,6 @@
pub mod parser;
pub mod token;
pub mod tokenizer;
pub use parser::ExpressionStream;
pub use parser::ParserError;

163
src/parser/parser.rs Normal file
View File

@ -0,0 +1,163 @@
use super::token::Token;
use super::tokenizer::tokenize;
use super::tokenizer::TokenStream;
use super::tokenizer::TokenizerError;
use crate::lisp::Expression;
use std::iter::Peekable;
#[derive(Debug, Clone, PartialEq)]
pub enum ParserError {
UnexpectedToken(Token),
TokenizerError(TokenizerError),
UnexpectedEndOfInput,
}
impl From<TokenizerError> for ParserError {
fn from(value: TokenizerError) -> Self {
ParserError::TokenizerError(value)
}
}
fn parse_list<I>(stream: &mut Peekable<TokenStream<I>>) -> Result<Expression, ParserError>
where
I: Iterator<Item = char>,
{
let mut list = Vec::new();
loop {
match stream.peek() {
// Return current list or nil
Some(Ok(Token::ParClose)) => {
stream.next();
if list.len() == 0 {
return Ok(Expression::Nil);
} else {
return Ok(list.into());
}
}
// Switch to cons-pair parsing
Some(Ok(Token::Dot)) => {
stream.next();
if list.len() > 1 || list.len() == 0 {
return Err(ParserError::UnexpectedToken(Token::Dot));
} else {
let second_expr = parse_expression(stream)?;
match stream.next() {
Some(Ok(Token::ParClose)) => {
return Ok(Expression::Cell(
Box::new(list[0].to_owned()),
Box::new(second_expr),
));
}
Some(Ok(t)) => {
return Err(ParserError::UnexpectedToken(t));
}
Some(Err(e)) => {
return Err(e.into());
}
None => {
return Err(ParserError::UnexpectedEndOfInput);
}
}
}
}
_ => {}
}
list.push(parse_expression(stream)?);
}
}
fn parse_expression<I>(stream: &mut Peekable<TokenStream<I>>) -> Result<Expression, ParserError>
where
I: Iterator<Item = char>,
{
match stream.next() {
Some(Ok(Token::ParOpen)) => parse_list(stream),
Some(Ok(Token::Nil)) => Ok(Expression::Nil),
Some(Ok(Token::IntLiteral(n))) => Ok(Expression::Integer(n)),
Some(Ok(Token::FloatLiteral(f))) => Ok(Expression::Float(f)),
Some(Ok(Token::StringLiteral(s))) => Ok(Expression::String(s)),
Some(Ok(Token::True)) => Ok(Expression::True),
Some(Ok(Token::Symbol(s))) => Ok(Expression::Symbol(s)),
Some(Ok(Token::Quote)) => Ok(Expression::Quote(Box::new(parse_expression(stream)?))),
Some(Err(e)) => Err(ParserError::TokenizerError(e)),
Some(Ok(x)) => Err(ParserError::UnexpectedToken(x)),
None => Err(ParserError::UnexpectedEndOfInput),
}
}
pub struct ExpressionStream<I: Iterator<Item = char>> {
token_stream: Peekable<TokenStream<I>>,
}
impl<I: Iterator<Item = char>> ExpressionStream<I> {
pub fn from_token_stream(token_stream: TokenStream<I>) -> Self {
ExpressionStream {
token_stream: token_stream.peekable(),
}
}
pub fn from_char_stream(char_stream: I) -> Self {
ExpressionStream {
token_stream: tokenize(char_stream).peekable(),
}
}
}
impl<I: Iterator<Item = char>> Iterator for ExpressionStream<I> {
type Item = Result<Expression, ParserError>;
fn next(&mut self) -> Option<Self::Item> {
if self.token_stream.peek() == None {
return None;
}
Some(parse_expression(&mut self.token_stream))
}
}
#[test]
fn test_parser() {
let input = "(1 2 3) (4 5 6) (1 . 2) (1 . (2 . (3))) \"test\" '(a b c true nil)";
let ts = tokenize(input.chars());
let es = ExpressionStream::from_token_stream(ts);
let exprs = es.collect::<Result<Vec<Expression>, ParserError>>();
assert_eq!(
exprs,
Ok(vec![
vec![
Expression::Integer(1),
Expression::Integer(2),
Expression::Integer(3),
]
.into(),
vec![
Expression::Integer(4),
Expression::Integer(5),
Expression::Integer(6),
]
.into(),
Expression::Cell(
Box::new(Expression::Integer(1)),
Box::new(Expression::Integer(2)),
),
vec![
Expression::Integer(1),
Expression::Integer(2),
Expression::Integer(3),
]
.into(),
Expression::String("test".to_string()),
Expression::Quote(Box::new(
vec![
Expression::Symbol("a".to_string()),
Expression::Symbol("b".to_string()),
Expression::Symbol("c".to_string()),
Expression::True,
Expression::Nil,
]
.into()
)),
])
);
}

View File

@ -1,6 +1,6 @@
use super::token::Token;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
/// Errors the tokenizer can yield.
pub enum TokenizerError {
/// The tokenizer could not read the associated sequence.