Refactored parser back to using traits rather than enum, Added gitignore, Added return statement
This commit is contained in:
parent
98023fe219
commit
68330a8156
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
||||||
target/
|
target/
|
||||||
|
.vscode/settings.json
|
||||||
|
.vscode/launch.json
|
||||||
|
|
|
@ -89,7 +89,7 @@ impl<'a> Lexer<'a> {
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_is_ascii_digit(&mut self) -> bool {
|
fn peek_is_ascii_digit(&mut self) -> bool {
|
||||||
match self.input.peek() {
|
match self.input.peek() {
|
||||||
Some(v) => v.is_ascii_digit(),
|
Some(v) => v.is_ascii_digit(),
|
||||||
|
|
|
@ -1,52 +1,68 @@
|
||||||
use crate::lexer::Token;
|
use crate::{
|
||||||
use crate::parser::{ParseError, Parser};
|
lexer::Token,
|
||||||
|
parser::{ParseError, Parser},
|
||||||
|
};
|
||||||
|
use std::any::Any;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
pub enum Node {
|
pub trait Node {
|
||||||
Statement(StatementType),
|
fn string(&self) -> String
|
||||||
Expression,
|
where
|
||||||
|
Self: Sized + Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
pub trait Statement: Node {
|
||||||
pub enum StatementType {
|
fn parse(&mut Parser) -> Result<Self, ParseError>
|
||||||
Let(LetStatement),
|
where
|
||||||
Ident(Identifier),
|
Self: Sized + Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Expression: Node {
|
||||||
|
fn parse(&mut Parser) -> Result<Self, Box<dyn Error>>
|
||||||
|
where
|
||||||
|
Self: Sized + Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct LetStatement {
|
pub struct Let {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
// value: dyn Expression,
|
// value: dyn Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LetStatement {
|
impl Let {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new(identifier: Identifier) -> StatementType {
|
pub fn new(identifier: Identifier) -> Let {
|
||||||
StatementType::Let(LetStatement { name: identifier })
|
Let { name: identifier }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse(parser: &mut Parser) -> Result<LetStatement, Box<dyn Error>> {
|
impl Node for Let {
|
||||||
|
fn string(&self) -> String {
|
||||||
|
String::new() // TODO: Complete how I want to format strings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement for Let {
|
||||||
|
fn parse(parser: &mut Parser) -> Result<Let, ParseError> {
|
||||||
let name;
|
let name;
|
||||||
|
|
||||||
//TODO: Add expression parser
|
//TODO: Add expression parser
|
||||||
match parser.lexer.next() {
|
match parser.lexer.next() {
|
||||||
Some(v) => match v {
|
Some(v) => match v {
|
||||||
Token::Ident(q) => name = Identifier { name: q },
|
Token::Ident(q) => name = Identifier { name: q },
|
||||||
n @ _ => {
|
n @ _ => {
|
||||||
return Err(Box::new(ParseError::new(&format!(
|
return Err(ParseError::new(&format!("expected IDENT, Found {:?}", n)));
|
||||||
"expected IDENT, Found {:?}",
|
|
||||||
n
|
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
return Err(Box::new(ParseError::new(
|
return Err(ParseError::new(
|
||||||
"expected IDENT after let, Could not find it",
|
"expected IDENT after let, Could not find it",
|
||||||
)))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !parser.expect_peek(Token::Assign) {
|
if !parser.expect_peek(Token::Assign) {
|
||||||
return Err(Box::new(ParseError::new("expected =, Could not find it")));
|
return Err(ParseError::new("expected =, Could not find it"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace this with code to parse expressions correctly
|
// TODO: Replace this with code to parse expressions correctly
|
||||||
|
@ -54,7 +70,37 @@ impl LetStatement {
|
||||||
parser.current_token = parser.lexer.next();
|
parser.current_token = parser.lexer.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(LetStatement { name })
|
Ok(Let { name })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct Return {
|
||||||
|
return_value: Expr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Return {
|
||||||
|
pub fn new() -> Return {
|
||||||
|
Return { return_value: Expr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct Expr; // TODO: Replace with actual expressions parser
|
||||||
|
|
||||||
|
impl Node for Return {
|
||||||
|
fn string(&self) -> String {
|
||||||
|
String::new() // TODO: Complete how I want to format return statements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement for Return {
|
||||||
|
fn parse(parser: &mut Parser) -> Result<Return, ParseError> {
|
||||||
|
while !parser.current_token_is(Token::Semicolon) {
|
||||||
|
parser.current_token = parser.lexer.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Return { return_value: Expr })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ mod program;
|
||||||
|
|
||||||
pub use self::program::Program;
|
pub use self::program::Program;
|
||||||
|
|
||||||
use self::ast::{LetStatement, StatementType};
|
use self::ast::{Let, Return, Statement};
|
||||||
use crate::lexer::{Lexer, Token};
|
use crate::lexer::{Lexer, Token};
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
|
@ -19,28 +19,31 @@ impl<'a> Parser<'a> {
|
||||||
current_token: None,
|
current_token: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn parse_statement(&mut self, token: Token) -> Option<ast::StatementType> {
|
fn parse_statement(&mut self, token: Token) -> Result<Box<dyn ast::Statement>, ParseError> {
|
||||||
match token {
|
match token {
|
||||||
Token::Let => {
|
Token::Let => match Let::parse(self) {
|
||||||
match LetStatement::parse(self) {
|
Ok(v) => Ok(Box::new(v)),
|
||||||
Ok(v) => Some(StatementType::Let(v)),
|
Err(e) => Err(e), //TODO: Return appropriate error
|
||||||
Err(_) => None, //TODO: Return appropriate error
|
},
|
||||||
}
|
Token::Return => match Return::parse(self) {
|
||||||
|
Ok(v) => Ok(Box::new(v)),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
},
|
||||||
|
n @ _ => {
|
||||||
|
println!("{:?}", n);
|
||||||
|
unimplemented!();
|
||||||
}
|
}
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_peek(&mut self, token: Token) -> bool {
|
fn expect_peek(&mut self, token: Token) -> bool {
|
||||||
if let Some(v) = self.lexer.peek() {
|
match self.lexer.peek() {
|
||||||
if v == &token {
|
Some(v) if v == &token => {
|
||||||
self.current_token = self.lexer.next();
|
self.current_token = self.lexer.next();
|
||||||
true
|
true
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
} else {
|
Some(v) => false,
|
||||||
false
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
use crate::lexer::{Lexer, Token};
|
use crate::lexer::{Lexer, Token};
|
||||||
use crate::parser::ast::StatementType;
|
use crate::parser::{ast::Statement, Parser};
|
||||||
use crate::parser::Parser;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
statements: Vec<StatementType>,
|
statements: Vec<Box<dyn Statement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
|
@ -13,20 +11,22 @@ impl Program {
|
||||||
let mut parser = Parser::new(lexer);
|
let mut parser = Parser::new(lexer);
|
||||||
loop {
|
loop {
|
||||||
if let Some(token) = parser.lexer.next() {
|
if let Some(token) = parser.lexer.next() {
|
||||||
|
parser.current_token = Some(token.clone());
|
||||||
if parser.current_token_is(Token::EOF) {
|
if parser.current_token_is(Token::EOF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(stmt) = parser.parse_statement(token) {
|
match parser.parse_statement(token) {
|
||||||
statements.push(stmt);
|
Ok(v) => statements.push(v),
|
||||||
} else {
|
Err(e) => {
|
||||||
continue;
|
println!("{:?}", e);
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("statements={:?}", statements);
|
|
||||||
Program { statements }
|
Program { statements }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,9 @@ impl Program {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::lexer::Lexer;
|
use crate::lexer::Lexer;
|
||||||
use crate::parser::ast::{Identifier, LetStatement};
|
use crate::parser::ast::{Identifier, Let, Statement};
|
||||||
use crate::parser::Program;
|
use crate::parser::Program;
|
||||||
|
use std::any::Any;
|
||||||
#[test]
|
#[test]
|
||||||
fn let_statements() {
|
fn let_statements() {
|
||||||
let ip = "
|
let ip = "
|
||||||
|
@ -43,22 +44,39 @@ mod tests {
|
||||||
let qq = 10;
|
let qq = 10;
|
||||||
let foobar = 8388383;
|
let foobar = 8388383;
|
||||||
";
|
";
|
||||||
let out = Program {
|
|
||||||
statements: vec![
|
let expected_out = vec![
|
||||||
LetStatement::new(Identifier::new("yr")),
|
Box::new(Let::new(Identifier::new("yr"))),
|
||||||
LetStatement::new(Identifier::new("qq")),
|
Box::new(Let::new(Identifier::new("qq"))),
|
||||||
LetStatement::new(Identifier::new("foobar")),
|
Box::new(Let::new(Identifier::new("foobar"))),
|
||||||
],
|
];
|
||||||
};
|
|
||||||
let lexer = Lexer::new(ip);
|
let lexer = Lexer::new(ip);
|
||||||
let ast_tree = Program::parse(lexer);
|
let as_tree = Program::parse(lexer);
|
||||||
|
|
||||||
if ast_tree.statements.len() != 3 {
|
assert_eq!(as_tree.statements.len(), 3);
|
||||||
assert_eq!(ast_tree.statements.len(), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (out, expected_out) in ast_tree.statements.iter().zip(out.statements.iter()) {
|
for (out, expected_out) in as_tree.statements.into_iter().zip(expected_out.into_iter()) {
|
||||||
assert_eq!(out, expected_out);
|
let out: Option<Let> =
|
||||||
|
if std::any::TypeId::of::<Let>() == std::any::TypeId::of::<dyn Statement>() {
|
||||||
|
Some(unsafe { std::mem::transmute::<Box<dyn Statement>, Let>(out) })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if Box::new(out.unwrap()) == expected_out {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_statements() {
|
||||||
|
let ip = "
|
||||||
|
return 5;
|
||||||
|
return 10;
|
||||||
|
return 80932;
|
||||||
|
";
|
||||||
|
|
||||||
|
let lexer = Lexer::new(ip);
|
||||||
|
let as_tree = Program::parse(lexer);
|
||||||
|
assert_eq!(as_tree.statements.len(), 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user