feat(parser): add expression parser
This commit is contained in:
parent
33250c0272
commit
53e6ac8132
@ -1,2 +1,8 @@
|
|||||||
pub mod environment;
|
pub mod environment;
|
||||||
pub mod expression;
|
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 lisp;
|
||||||
mod parser;
|
mod parser;
|
||||||
use lisp::expression::{eval_prelude, Expression};
|
use lisp::eval_prelude;
|
||||||
|
use parser::ExpressionStream;
|
||||||
|
|
||||||
fn main() {
|
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);
|
for r in ExpressionStream::from_char_stream(program.chars()) {
|
||||||
|
match r {
|
||||||
while let Some(tk) = tkns.next() {
|
Err(err) => println!("ParserError: {:?}", err),
|
||||||
println!("{:?}", tk);
|
Ok(expr) => println!(
|
||||||
|
"{:?} \n vvvvvvvvvvv \n {:?}\n",
|
||||||
|
expr.clone(),
|
||||||
|
eval_prelude(expr)
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let expr: Expression = vec![
|
println!("Interpreter Done!");
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,6 @@
|
|||||||
|
pub mod parser;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod tokenizer;
|
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;
|
use super::token::Token;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
/// Errors the tokenizer can yield.
|
/// Errors the tokenizer can yield.
|
||||||
pub enum TokenizerError {
|
pub enum TokenizerError {
|
||||||
/// The tokenizer could not read the associated sequence.
|
/// The tokenizer could not read the associated sequence.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user