feat(parser): add expression parser
This commit is contained in:
parent
33250c0272
commit
53e6ac8132
@ -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;
|
||||
|
||||
61
src/main.rs
61
src/main.rs
@ -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!");
|
||||
}
|
||||
|
||||
@ -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
163
src/parser/parser.rs
Normal 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()
|
||||
)),
|
||||
])
|
||||
);
|
||||
}
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user