aboutsummaryrefslogtreecommitdiff
path: root/sloth/src/parser
diff options
context:
space:
mode:
Diffstat (limited to 'sloth/src/parser')
-rw-r--r--sloth/src/parser/ast.rs247
-rw-r--r--sloth/src/parser/expr.rs273
-rw-r--r--sloth/src/parser/graph.rs160
-rw-r--r--sloth/src/parser/mod.rs66
-rw-r--r--sloth/src/parser/stmt.rs851
5 files changed, 717 insertions, 880 deletions
diff --git a/sloth/src/parser/ast.rs b/sloth/src/parser/ast.rs
index 543ea3a..2385443 100644
--- a/sloth/src/parser/ast.rs
+++ b/sloth/src/parser/ast.rs
@@ -1,52 +1,49 @@
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum BinaryOp {
- Add,
- Con,
- Sub,
- Mul,
- Pow,
- Div,
- Mod,
+use crate::lexer::{self, TokenType};
+use crate::parser::ParsingError;
- BWSftRight,
- BWSftLeft,
- BWAnd,
- BWOr,
- BWXor,
+// #[derive(PartialEq, Clone, Debug)]
+// pub struct Node {
+// id: i32,
+// kind: NodeKind,
+// }
+//
+// impl Node {
+// pub fn new(id: i32, kind: NodeKind) -> Self {
+// Self { id, kind }
+// }
+// }
+//
+// #[derive(PartialEq, Clone, Debug)]
+// pub enum NodeKind {
+// Expr(Expr),
+// Stmt(Stmt),
+// }
+//
+// impl From<Expr> for NodeKind {
+// fn from(value: Expr) -> Self {
+// todo!()
+// }
+// }
+//
+// impl From<Stmt> for NodeKind {}
- Lt,
- Gt,
- LtEq,
- GtEq,
- EqEq,
- NotEq,
- LogAnd,
- LogOr,
- Range,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum UnaryOp {
- Not,
- Neg,
-
- BWComp,
+#[derive(PartialEq, Clone, Debug)]
+pub struct Expr {
+ pub id: i32,
+ pub kind: ExprKind,
}
-#[derive(Debug, Clone, PartialEq)]
-pub enum Literal {
- Integer(i128),
- Float(f64),
- Bool(bool),
- Char(char),
- String(String),
- Regex(String),
- List(Vec<Expr>),
+impl Expr {
+ pub fn new(id: i32, kind: ExprKind) -> Self {
+ Self { id, kind }
+ }
}
#[derive(Debug, Clone, PartialEq)]
-pub enum Expr {
+pub enum ExprKind {
Grouping(Box<Expr>),
+ Literal(Literal),
+ Identifier(String),
BinaryOp {
op: BinaryOp,
lhs: Box<Expr>,
@@ -57,59 +54,153 @@ pub enum Expr {
value: Box<Expr>,
},
Call {
- ident: Box<Expr>,
+ callee: Box<Expr>,
args: Vec<Expr>,
},
- Variable(String),
- Literal(Literal),
- Lambda, // TODO: Lambda
}
#[derive(PartialEq, Clone, Debug)]
-pub struct FuncArgs {
- pub name: String,
- pub typ: Option<String>,
+pub struct FunctionInput {
+ pub identifier: String,
+ pub typ: String,
}
+// TODO: For loops
+// TODO: Values & Constants
#[derive(PartialEq, Clone, Debug)]
pub enum Stmt {
+ Block(Vec<Stmt>),
ExprStmt(Expr),
- DefineFunction {
- ident: String,
- args: Vec<FuncArgs>,
- body: Vec<Stmt>,
- return_type: Option<String>,
+ IfStmt {
+ condition: Expr,
+ if_then: Box<Stmt>,
+ else_then: Option<Box<Stmt>>,
},
- DefineVariable {
- name: String,
- value: Expr,
- typ: Option<String>,
+ WhileStmt {
+ condition: Expr,
+ body: Box<Stmt>,
},
- DefineValue {
- name: String,
+ DefineVariable {
+ identifier: String,
value: Expr,
- typ: Option<String>,
+ typ: String,
},
AssignVariable {
- name: String,
+ identifier: String,
value: Expr,
},
- If {
- expr: Expr,
- body: Vec<Stmt>,
- else_if: Vec<(Expr, Stmt)>,
- els: Option<Box<Stmt>>,
- },
- For {
- name: String,
- iter: Expr,
- body: Vec<Stmt>,
- },
- While {
- condition: Expr,
- body: Vec<Stmt>,
- },
- Return {
- value: Expr,
+ /// A function definition. Output is None when the function returns nothing
+ /// meaning void, otherwise it is the name of the type the function
+ /// returns.
+ DefineFunction {
+ identifier: String,
+ inputs: Vec<FunctionInput>,
+ output: Option<String>,
+ body: Box<Stmt>,
},
+ Return(Expr),
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Literal {
+ Integer(i64),
+ Float(f64),
+ Boolean(bool),
+ Character(char),
+ String(String),
+ Array(Vec<ExprKind>),
+}
+
+impl From<lexer::Literal> for Literal {
+ fn from(value: lexer::Literal) -> Self {
+ use lexer::Literal;
+
+ match value {
+ Literal::Integer(value) => Self::Integer(value),
+ Literal::Float(value) => Self::Float(value),
+ Literal::Boolean(value) => Self::Boolean(value),
+ Literal::Character(value) => Self::Character(value),
+ Literal::String(value) => Self::String(value),
+ }
+ }
+}
+
+impl From<Literal> for ExprKind {
+ fn from(value: Literal) -> Self {
+ Self::Literal(value)
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum BinaryOp {
+ Add,
+ Con,
+ Sub,
+ Mul,
+ Div,
+ Mod,
+
+ Lt,
+ Gt,
+ LtEq,
+ GtEq,
+ EqEq,
+ NotEq,
+
+ LogicalAnd,
+ LogicalOr,
+
+ Range,
+}
+
+impl TryFrom<TokenType> for BinaryOp {
+ type Error = ParsingError;
+
+ fn try_from(value: TokenType) -> Result<Self, Self::Error> {
+ let operation = match value {
+ TokenType::Plus => Self::Add,
+ TokenType::PlusPlus => Self::Con,
+ TokenType::Minus => Self::Sub,
+ TokenType::Star => Self::Mul,
+ TokenType::Slash => Self::Div,
+ TokenType::Perc => Self::Mod,
+
+ TokenType::Lt => Self::Lt,
+ TokenType::Gt => Self::Gt,
+ TokenType::LtEq => Self::LtEq,
+ TokenType::GtEq => Self::GtEq,
+ TokenType::EqEq => Self::EqEq,
+ TokenType::BangEq => Self::NotEq,
+
+ TokenType::AmpAmp => Self::LogicalAnd,
+ TokenType::PipePipe => Self::LogicalOr,
+
+ TokenType::DotDot => Self::Range,
+
+ _ => return Err(ParsingError::InvalidOp),
+ };
+
+ Ok(operation)
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum UnaryOp {
+ Not,
+ Neg,
+}
+
+impl TryFrom<TokenType> for UnaryOp {
+ type Error = ParsingError;
+
+ fn try_from(value: TokenType) -> Result<Self, Self::Error> {
+ let operation = match value {
+ TokenType::Bang => Self::Not,
+ TokenType::Minus => Self::Neg,
+
+ _ => return Err(ParsingError::InvalidOp),
+ };
+
+ Ok(operation)
+ }
}
diff --git a/sloth/src/parser/expr.rs b/sloth/src/parser/expr.rs
index 9e81f7f..aaf76a9 100644
--- a/sloth/src/parser/expr.rs
+++ b/sloth/src/parser/expr.rs
@@ -1,98 +1,47 @@
-use super::ast::{BinaryOp, Expr, Literal, UnaryOp};
+use super::ast::{Expr, Literal, UnaryOp};
use super::AstParser;
use crate::lexer::TokenType;
+use crate::parser::ast::{BinaryOp, ExprKind};
+use crate::parser::ParsingError;
-/// Implementation containing parsers internal components related to expressions
impl<'a> AstParser<'a> {
- // FIXME: Should probably avoid cloning token types
-
- pub fn expression(&mut self) -> Expr {
+ pub(super) fn expression(&mut self) -> Result<Expr, ParsingError> {
self.logical_or()
}
- fn unary(&mut self) -> Expr {
- if !self.eof()
- && matches!(
- self.peek().tt,
- TokenType::Bang | TokenType::Plus | TokenType::Minus
- )
- {
- let operator = match self.advance().unwrap().tt.clone() {
- TokenType::Bang => UnaryOp::Not,
- TokenType::Tilde => UnaryOp::BWComp,
- TokenType::Minus => UnaryOp::Neg,
- _ => panic!(),
- };
-
- let rhs = self.unary();
- return Expr::UnaryOp {
- op: (operator),
- value: (Box::new(rhs)),
- };
- }
-
- self.call()
- }
-
- fn call(&mut self) -> Expr {
- let mut expr = self.primary();
-
- if self.advance_if_eq(&TokenType::OpeningParen) {
- let mut arguments = Vec::<Expr>::new();
-
- if self.peek().tt != TokenType::ClosingParen {
- loop {
- arguments.push(self.expression());
- if !self.advance_if_eq(&TokenType::Comma) {
- break;
- }
- }
- }
+ fn unary(&mut self) -> Result<Expr, ParsingError> {
+ if matches!(self.peek().tt, TokenType::Bang | TokenType::Minus) {
+ let oeprator_tt = self.advance().unwrap().tt.clone();
+ let operator = UnaryOp::try_from(oeprator_tt)?;
- self.consume(
- TokenType::ClosingParen,
- "Expected ')' to close off function call",
- );
+ let value = self.unary()?;
- // let Expr::Variable(_ident) = expr else { panic!("uh oh spaghettio"); };
+ let kind = ExprKind::UnaryOp {
+ op: operator,
+ value: Box::new(value),
+ };
- expr = Expr::Call {
- ident: (Box::new(expr)),
- args: (arguments),
- }
+ return Ok(Expr::new(self.reserve_id(), kind));
}
- expr
+ self.primary()
}
- fn primary(&mut self) -> Expr {
- match self.advance().unwrap().tt.clone() {
- TokenType::Integer(literal) => Expr::Literal(Literal::Integer(literal)),
- TokenType::Float(literal) => Expr::Literal(Literal::Float(literal)),
- TokenType::Boolean(literal) => Expr::Literal(Literal::Bool(literal)),
- TokenType::Character(literal) => Expr::Literal(Literal::Char(literal)),
- TokenType::String(literal) => Expr::Literal(Literal::String(literal)),
- TokenType::Regex(literal) => Expr::Literal(Literal::Regex(literal)),
- TokenType::Identifier(ident) => Expr::Variable(ident),
+ fn primary(&mut self) -> Result<Expr, ParsingError> {
+ let kind = match self.advance().unwrap().tt.clone() {
+ TokenType::Literal(literal) => ExprKind::Literal(literal.into()),
+ TokenType::Identifier(identifier) => ExprKind::Identifier(identifier),
+
TokenType::OpeningParen => {
- let expr = self.expression();
- self.consume(TokenType::ClosingParen, "Must end expression with ')'");
- Expr::Grouping(Box::new(expr))
+ let expr = self.expression()?;
+ self.consume(TokenType::ClosingParen, "Must end grouping with ')'")?;
+ ExprKind::Grouping(Box::new(expr))
}
- TokenType::OpeningBracket => {
- let mut expr: Vec<Expr> = Vec::new();
- while !self.eof() && self.peek().tt != TokenType::ClosingBracket {
- let exp = self.expression();
- expr.push(exp);
+ _ => return Err(ParsingError::UnexpectedToken),
+ };
- self.advance_if_eq(&TokenType::Comma);
- }
- self.consume(TokenType::ClosingBracket, "Expected ']' at end of list");
- Expr::Literal(Literal::List(expr))
- }
- _ => unimplemented!("{:?}", self.peek()),
- }
+ Ok(Expr::new(self.reserve_id(), kind))
}
}
@@ -100,162 +49,78 @@ impl<'a> AstParser<'a> {
// multiplication, exc.
macro_rules! binary_expr {
($name:ident, $parent:ident, $pattern:pat) => {
- fn $name(&mut self) -> Expr {
- let mut expr = self.$parent();
+ fn $name(&mut self) -> Result<Expr, ParsingError> {
+ let mut expr = self.$parent()?;
while !self.eof() && matches!(self.peek().tt, $pattern) {
- let operator = match self.advance().unwrap().tt.clone() {
- TokenType::Plus => BinaryOp::Add,
- TokenType::PlusPlus => BinaryOp::Con,
- TokenType::Minus => BinaryOp::Sub,
- TokenType::Star => BinaryOp::Mul,
- TokenType::StarStar => BinaryOp::Pow,
- TokenType::Slash => BinaryOp::Div,
- TokenType::Perc => BinaryOp::Mod,
- TokenType::DotDot => BinaryOp::Range,
-
- TokenType::LtLt => BinaryOp::BWSftRight,
- TokenType::GtGt => BinaryOp::BWSftLeft,
- TokenType::Amp => BinaryOp::BWAnd,
- TokenType::Pipe => BinaryOp::BWOr,
- TokenType::Caret => BinaryOp::BWXor,
-
- TokenType::Lt => BinaryOp::Lt,
- TokenType::Gt => BinaryOp::Gt,
- TokenType::LtEq => BinaryOp::LtEq,
- TokenType::GtEq => BinaryOp::GtEq,
- TokenType::EqEq => BinaryOp::EqEq,
- TokenType::BangEq => BinaryOp::NotEq,
- TokenType::AmpAmp => BinaryOp::LogAnd,
- TokenType::PipePipe => BinaryOp::LogOr,
- _ => panic!("uh oh spagghetio"),
+ let operator_tt = self.advance().unwrap().tt.clone();
+ let operator = BinaryOp::try_from(operator_tt)?;
+
+ let rhs = self.$parent()?;
+ let kind = ExprKind::BinaryOp {
+ op: operator,
+ lhs: Box::new(expr),
+ rhs: Box::new(rhs),
};
- let rhs = self.$parent();
- expr = Expr::BinaryOp {
- op: (operator),
- lhs: (Box::new(expr)),
- rhs: (Box::new(rhs)),
- }
+ expr = Expr::new(self.reserve_id(), kind);
}
- expr
+ Ok(expr)
}
};
}
#[rustfmt::skip]
#[allow(unused_parens)]
-impl<'a> AstParser<'a> {
+impl<'a> AstParser<'a> {
// Binary expressions in order of precedence from lowest to highest.
- binary_expr!(logical_or , logical_and , (TokenType::PipePipe));
- binary_expr!(logical_and , range , (TokenType::AmpAmp));
- binary_expr!(range , equality , (TokenType::DotDot));
- binary_expr!(equality , comparison , (TokenType::BangEq | TokenType::EqEq));
- binary_expr!(comparison , bitwise_shifting, (TokenType::Lt | TokenType::Gt | TokenType::LtEq | TokenType::GtEq));
- binary_expr!(bitwise_shifting, additive , (TokenType::LtLt | TokenType::GtGt));
- binary_expr!(additive , multiplicative , (TokenType::Plus | TokenType::Minus));
- binary_expr!(multiplicative , unary , (TokenType::Star | TokenType::Slash | TokenType::Perc));
+ binary_expr!(logical_or , logical_and , (TokenType::PipePipe));
+ binary_expr!(logical_and , range , (TokenType::AmpAmp));
+ binary_expr!(range , equality , (TokenType::DotDot));
+ binary_expr!(equality , comparison , (TokenType::BangEq | TokenType::EqEq));
+ binary_expr!(comparison , additive , (TokenType::Lt | TokenType::Gt | TokenType::LtEq | TokenType::GtEq));
+ binary_expr!(additive , multiplicative, (TokenType::Plus | TokenType::Minus));
+ binary_expr!(multiplicative , unary , (TokenType::Star | TokenType::Slash | TokenType::Perc));
}
#[cfg(test)]
mod tests {
use itertools::Itertools;
- use super::{AstParser, BinaryOp, Expr, Literal};
+ use super::{AstParser, BinaryOp, ExprKind, Literal};
use crate::lexer::Lexer;
- use crate::parser::ast::UnaryOp;
-
- #[test]
- fn basic_expression_a() {
- let lexer = Lexer::new("3 + 5 * 4");
- let tokens = lexer.collect_vec();
-
- let expected_ast = Expr::BinaryOp {
- op: BinaryOp::Add,
- lhs: Box::new(Expr::Literal(Literal::Integer(3))),
- rhs: Box::new(Expr::BinaryOp {
- op: BinaryOp::Mul,
- lhs: Box::new(Expr::Literal(Literal::Integer(5))),
- rhs: Box::new(Expr::Literal(Literal::Integer(4))),
- }),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.expression();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
+ use crate::parser::ast::Expr;
#[test]
- fn basic_expression_b() {
- let lexer = Lexer::new("17 - (-5 + 5) / 6");
+ fn basic_expression() {
+ let lexer = Lexer::new("3 + 5 * 4 - 9 / 3");
let tokens = lexer.collect_vec();
- let expected_ast = Expr::BinaryOp {
- op: BinaryOp::Sub,
- lhs: Box::new(Expr::Literal(Literal::Integer(17))),
- rhs: Box::new(Expr::BinaryOp {
- op: BinaryOp::Div,
- lhs: Box::new(Expr::Grouping(Box::new(Expr::BinaryOp {
- op: BinaryOp::Add,
- lhs: Box::new(Expr::UnaryOp {
- op: UnaryOp::Neg,
- value: Box::new(Expr::Literal(Literal::Integer(5))),
- }),
- rhs: Box::new(Expr::Literal(Literal::Integer(5))),
- }))),
- rhs: Box::new(Expr::Literal(Literal::Integer(6))),
- }),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.expression();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
- #[test]
- fn basic_expression_c() {
- let lexer = Lexer::new("[1, 2, 3]");
- let tokens = lexer.collect_vec();
-
- let expected_ast = Expr::Literal(Literal::List(vec![
- Expr::Literal(Literal::Integer(1)),
- Expr::Literal(Literal::Integer(2)),
- Expr::Literal(Literal::Integer(3)),
- ]));
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.expression();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
- #[test]
- fn basic_expression_d() {
- let lexer = Lexer::new("1 .. 17");
- let tokens = lexer.collect_vec();
-
- let expected_ast = Expr::BinaryOp {
- op: (BinaryOp::Range),
- lhs: (Box::new(Expr::Literal(Literal::Integer(1)))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(17)))),
- };
+ // let expected_ast = Ok(ExprKind::BinaryOp {
+ // op: BinaryOp::Sub,
+ // lhs: Box::new(ExprKind::BinaryOp {
+ // op: BinaryOp::Add,
+ // lhs: Box::new(ExprKind::Literal(Literal::Integer(3))),
+ // rhs: Box::new(ExprKind::BinaryOp {
+ // op: BinaryOp::Mul,
+ // lhs: Box::new(ExprKind::Literal(Literal::Integer(5))),
+ // rhs: Box::new(ExprKind::Literal(Literal::Integer(4))),
+ // }),
+ // }),
+ // rhs: Box::new(ExprKind::BinaryOp {
+ // op: BinaryOp::Div,
+ // lhs: Box::new(ExprKind::Literal(Literal::Integer(9))),
+ // rhs: Box::new(ExprKind::Literal(Literal::Integer(3))),
+ // }),
+ // });
let mut parser = AstParser::new(tokens);
let generated_ast = parser.expression();
- println!("Expected AST:\n{expected_ast:#?}\n\n");
+ // println!("Expected AST:\n{expected_ast:#?}\n\n");
println!("Generated AST:\n{generated_ast:#?}\n\n");
- assert_eq!(expected_ast, generated_ast);
+ assert_eq!(Ok(Expr::new(0, Literal::Integer(0).into())), generated_ast);
}
}
diff --git a/sloth/src/parser/graph.rs b/sloth/src/parser/graph.rs
new file mode 100644
index 0000000..b35be05
--- /dev/null
+++ b/sloth/src/parser/graph.rs
@@ -0,0 +1,160 @@
+use std::fmt::{Error, Write};
+
+use super::ast::{ExprKind, Stmt};
+
+pub struct GraphBuilder {
+ i: i32,
+ graph: String,
+}
+
+impl GraphBuilder {
+ pub fn generate(ast: &[Stmt]) -> Result<String, Error> {
+ let mut this = Self {
+ i: 0,
+ graph: String::new(),
+ };
+
+ this.graph.push_str("digraph {\n");
+ for stmt in ast.iter() {
+ this.traverse_stmt0(stmt)?;
+ }
+ this.i = 0;
+ for stmt in ast.iter() {
+ this.traverse_stmt(stmt)?;
+ }
+ this.graph.push('}');
+
+ Ok(this.graph)
+ }
+
+ fn traverse_stmt0(&mut self, stmt: &Stmt) -> Result<(), Error> {
+ self.i += 1;
+
+ match stmt {
+ Stmt::Block(body) => {
+ writeln!(&mut self.graph, "N{} [shape=box label=\"Block\"];", self.i)?;
+ for stmt in body.iter() {
+ self.traverse_stmt0(stmt)?;
+ }
+ }
+ Stmt::ExprStmt(expr) => {
+ writeln!(
+ &mut self.graph,
+ "N{} [shape=box label=\"ExprStmt\"];",
+ self.i
+ )?;
+ // self.traverse_expr0(expr);
+ }
+ Stmt::IfStmt {
+ condition,
+ if_then,
+ else_then,
+ } => {
+ writeln!(&mut self.graph, "N{} [shape=box label=\"IfStmt\"];", self.i)?;
+ // self.traverse_expr0(condition);
+ self.traverse_stmt0(if_then)?;
+ if let Some(else_then) = else_then {
+ self.traverse_stmt0(else_then)?;
+ }
+ }
+ Stmt::WhileStmt { condition, body } => {
+ writeln!(
+ &mut self.graph,
+ "N{} [shape=box label=\"WhileStmt\"];",
+ self.i
+ )?;
+ // self.traverse_expr0(condition);
+ self.traverse_stmt0(body)?;
+ }
+ Stmt::DefineVariable {
+ identifier,
+ value,
+ typ,
+ } => {
+ writeln!(
+ &mut self.graph,
+ "N{} [shape=box label=\"DefineVariable\\n\\nIdentifier={}\\nType={}\"];",
+ self.i, identifier, typ
+ )?;
+ // self.traverse_expr0(value);
+ }
+ Stmt::AssignVariable { identifier, value } => {
+ writeln!(
+ &mut self.graph,
+ "N{} [shape=box label=\"AssignVariable\\n\\nIdentifier={}\"];",
+ self.i, identifier
+ )?;
+ // self.traverse_expr0(value);
+ }
+ Stmt::DefineFunction {
+ identifier,
+ inputs,
+ output,
+ body,
+ } => {
+ writeln!(
+ &mut self.graph,
+ "N{} [shape=box \
+ label=\"DefineFunction\\n\\nIdentifier={}\\nInputs={}\\nOutput={}\"];",
+ self.i,
+ identifier,
+ inputs.len(),
+ output.is_some()
+ )?;
+ self.traverse_stmt0(body)?;
+ }
+ Stmt::Return(expr) => {
+ writeln!(&mut self.graph, "N{} [shape=box label=\"Return\"];", self.i)?;
+ // self.traverse_expr0(expr);
+ }
+ }
+
+ Ok(())
+ }
+
+ fn traverse_expr0(&mut self, expr: &ExprKind) {
+ self.i += 1;
+ // match expr {
+ // Expr::Grouping(_) => todo!(),
+ // Expr::Literal(_) => todo!(),
+ // Expr::Identifier(_) => todo!(),
+ // Expr::BinaryOp { op, lhs, rhs } => todo!(),
+ // Expr::UnaryOp { op, value } => todo!(),
+ // Expr::Call { callee, args } => todo!(),
+ // }
+ }
+
+ fn traverse_stmt(&mut self, stmt: &Stmt) -> Result<(), Error> {
+ self.i += 1;
+
+ match stmt {
+ Stmt::Block(_) => todo!(),
+ Stmt::ExprStmt(_) => todo!(),
+ Stmt::IfStmt {
+ condition,
+ if_then,
+ else_then,
+ } => todo!(),
+ Stmt::WhileStmt { condition, body } => todo!(),
+ Stmt::DefineVariable {
+ identifier,
+ value,
+ typ,
+ } => todo!(),
+ Stmt::AssignVariable { identifier, value } => todo!(),
+ Stmt::DefineFunction {
+ identifier,
+ inputs,
+ output,
+ body,
+ } => todo!(),
+ Stmt::Return(_) => todo!(),
+ }
+
+ Ok(())
+ }
+
+ fn traverse_expr(&mut self, expr: &ExprKind) {
+ //
+ }
+}
diff --git a/sloth/src/parser/mod.rs b/sloth/src/parser/mod.rs
index 9d77acc..bc47ddd 100644
--- a/sloth/src/parser/mod.rs
+++ b/sloth/src/parser/mod.rs
@@ -1,23 +1,57 @@
pub mod ast;
pub mod expr;
+pub mod graph;
pub mod stmt;
+use self::ast::{Literal, Stmt};
use crate::lexer::{Token, TokenType};
+
+#[derive(thiserror::Error, Debug, PartialEq)]
+pub enum ParsingError {
+ #[error("Invalid operation")]
+ InvalidOp,
+ #[error("Unexpected token")]
+ UnexpectedToken,
+}
+
#[derive(Debug)]
pub struct AstParser<'a> {
tokens: Vec<Token<'a>>,
index: usize,
+ id: i32,
+}
+
+impl<'a> AstParser<'a> {
+ pub fn parse(tokens: Vec<Token<'a>>) -> Result<Vec<Stmt>, ParsingError> {
+ let mut parser = Self::new(tokens);
+
+ let mut statements = Vec::new();
+ while !parser.eof() {
+ statements.push(parser.statement()?);
+ }
+
+ Ok(statements)
+ }
}
/// Implementation containing utilities used by the parsers internal components
impl<'a> AstParser<'a> {
pub fn new(tokens: Vec<Token<'a>>) -> Self {
- Self { tokens, index: 0 }
+ Self {
+ tokens,
+ index: 0,
+ id: 0,
+ }
}
+
pub fn peek(&self) -> &Token {
&self.tokens[self.index]
}
+ pub fn peek2(&self) -> &Token {
+ &self.tokens[self.index + 1]
+ }
+
pub fn advance(&mut self) -> Option<&Token> {
if self.eof() {
return None;
@@ -44,11 +78,35 @@ impl<'a> AstParser<'a> {
self.advance_if(|it| it.tt == *next)
}
- pub fn consume(&mut self, next: TokenType, error: &str) {
+ pub fn consume(&mut self, next: TokenType, error: &str) -> Result<&Token, ParsingError> {
if std::mem::discriminant(&self.peek().tt) != std::mem::discriminant(&next) {
- panic!("{error} at index {:?}", self.index);
+ println!("{error} at index {:?}", self.index);
+ return Err(ParsingError::UnexpectedToken);
}
- self.advance();
+
+ Ok(self.advance().unwrap())
+ }
+
+ pub fn consume_literal(&mut self) -> Result<Literal, ParsingError> {
+ let Some(TokenType::Literal(literal)) = self.advance().map(|it| it.tt.clone()) else {
+ return Err(ParsingError::UnexpectedToken);
+ };
+
+ Ok(literal.into())
+ }
+
+ pub fn consume_identifier(&mut self) -> Result<String, ParsingError> {
+ let Some(TokenType::Identifier(identifier)) = self.advance().map(|it| it.tt.clone()) else {
+ return Err(ParsingError::UnexpectedToken);
+ };
+
+ Ok(identifier)
+ }
+
+ pub fn reserve_id(&mut self) -> i32 {
+ let id = self.id;
+ self.id += 1;
+ id
}
pub fn eof(&self) -> bool {
diff --git a/sloth/src/parser/stmt.rs b/sloth/src/parser/stmt.rs
index 1a961b1..aaa65ff 100644
--- a/sloth/src/parser/stmt.rs
+++ b/sloth/src/parser/stmt.rs
@@ -1,317 +1,161 @@
-use super::ast::{Expr, FuncArgs, Stmt};
-use super::AstParser;
+use super::ast::{FunctionInput, Stmt};
+use super::{AstParser, ParsingError};
use crate::lexer::TokenType;
impl<'a> AstParser<'a> {
- pub fn parse(&mut self) -> Vec<Stmt> {
- let mut statements = Vec::new();
-
- while !self.eof() {
- statements.push(self.statement());
+ pub(super) fn statement(&mut self) -> Result<Stmt, ParsingError> {
+ match self.peek().tt {
+ TokenType::OpeningBrace => self.block(),
+
+ TokenType::If => self.if_stmt(),
+ TokenType::While => self.while_stmt(),
+ TokenType::Var => self.define_variable(),
+ TokenType::Fn => self.define_function(),
+ TokenType::Return => self.return_stmt(),
+
+ _ if self.peek2().tt == TokenType::Eq => self.assign_variable(),
+ _ => self.expression_stmt(),
}
-
- statements
}
- fn statement(&mut self) -> Stmt {
- if self.advance_if_eq(&TokenType::Var) {
- return self.var_statement();
- }
-
- if self.advance_if_eq(&TokenType::Val) {
- return self.val_statement();
- }
-
- if self.advance_if_eq(&TokenType::If) {
- return self.if_statement();
- }
-
- if self.advance_if_eq(&TokenType::For) {
- return self.for_statement();
- }
-
- if self.advance_if_eq(&TokenType::While) {
- return self.while_statement();
- }
-
- if self.advance_if_eq(&TokenType::Fn) {
- return self.function_statement();
- }
-
- if self.advance_if_eq(&TokenType::Return) {
- return self.return_statement();
+ fn if_stmt(&mut self) -> Result<Stmt, ParsingError> {
+ // Consume the if token
+ self.consume(TokenType::If, "Expected if")?;
+
+ // Get the condition and if_then of the if statement
+ let condition = self.expression()?;
+ let if_then = self.block()?;
+
+ // Check if there is an else
+ let mut else_then = None;
+ if self.advance_if_eq(&TokenType::Else) {
+ if self.peek().tt == TokenType::If {
+ else_then = Some(self.if_stmt()?);
+ } else {
+ else_then = Some(self.block()?);
+ }
}
- self.mut_statement()
-
- // If we couldn't parse a statement return an expression statement
- // self.expression_statement()
+ Ok(Stmt::IfStmt {
+ condition,
+ if_then: if_then.into(),
+ else_then: else_then.map(|it| it.into()),
+ })
}
- fn mut_statement(&mut self) -> Stmt {
- let TokenType::Identifier(ident) = self.peek().tt.clone() else {
- panic!("Identifier error {:?}", self.peek());
- };
-
- self.advance();
- let next = self.advance().unwrap().tt.clone();
- if next == TokenType::Eq {
- let value = self.expression();
- self.consume(TokenType::SemiColon, "No semi colon for me i guess");
- return Stmt::AssignVariable {
- name: (ident),
- value: (value),
- };
- } else if next == TokenType::OpeningParen {
- let mut arguments = Vec::<Expr>::new();
-
- if self.peek().tt != TokenType::ClosingParen {
- loop {
- arguments.push(self.expression());
- if !self.advance_if_eq(&TokenType::Comma) {
- break;
- }
- }
- }
+ fn while_stmt(&mut self) -> Result<Stmt, ParsingError> {
+ // Consume the while token
+ self.consume(TokenType::While, "Expected while")?;
- self.consume(
- TokenType::ClosingParen,
- "Expected ')' to close off function call",
- );
+ let condition = self.expression()?;
+ let body = self.block()?;
- self.consume(TokenType::SemiColon, "No semi colon for me i guess");
- return Stmt::ExprStmt(Expr::Call {
- ident: Box::new(Expr::Variable(ident)),
- args: (arguments),
- });
- }
- self.expression_statement()
+ Ok(Stmt::WhileStmt {
+ condition,
+ body: body.into(),
+ })
}
- fn var_statement(&mut self) -> Stmt {
- let TokenType::Identifier(ident) = self.peek().tt.clone() else {
- panic!("Identifier expected after 'var', not {:?}", self.peek());
- };
-
- self.advance();
-
- let mut typ: Option<String> = None;
- if self.peek().tt.clone() == TokenType::Colon {
- self.consume(TokenType::Colon, "How did you even get this error?");
- let TokenType::Identifier(name) = self.peek().tt.clone() else {
- panic!("Type expected after identifier, not {:?}", self.peek());
- };
- self.advance();
- typ = Some(name);
- }
+ // TODO: Make variable types optional
+ fn define_variable(&mut self) -> Result<Stmt, ParsingError> {
+ // Consume the var token
+ self.consume(TokenType::Var, "Expected var")?;
- self.consume(TokenType::Eq, "Expected '=' after identifier at ");
+ // Get the identifier and type
+ let identifier = self.consume_identifier()?;
+ self.consume(TokenType::Colon, "Expected ':'")?;
+ let typ = self.consume_identifier()?;
- let value = self.expression();
+ // Get the default value
+ self.consume(TokenType::Eq, "Expected '='")?;
+ let value = self.expression()?;
- self.consume(TokenType::SemiColon, "Expected ';' at end of statement");
+ self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?;
- Stmt::DefineVariable {
- name: (ident),
- value: (value),
- typ: (typ),
- }
+ Ok(Stmt::DefineVariable {
+ identifier,
+ value,
+ typ,
+ })
}
- fn val_statement(&mut self) -> Stmt {
- let TokenType::Identifier(ident) = self.peek().tt.clone() else {
- panic!("Identifier expected after 'val'");
- };
-
- self.advance(); // Advancing from the identifier
+ // TODO: Make argument types optional
+ fn define_function(&mut self) -> Result<Stmt, ParsingError> {
+ // Consume the fn token
+ self.consume(TokenType::Fn, "Expected fn")?;
- let mut typ: Option<String> = None;
- if self.peek().tt.clone() == TokenType::Colon {
- self.consume(TokenType::Colon, "How did you even get this error?");
- let TokenType::Identifier(name) = self.peek().tt.clone() else {
- panic!("Type expected after identifier, not {:?}", self.peek());
- };
- self.advance();
- typ = Some(name);
- }
+ let identifier = self.consume_identifier()?;
- self.consume(TokenType::Eq, "Expected '=' after identifier");
+ // Get the function inputs
+ self.consume(TokenType::OpeningParen, "Expected '('")?;
- let value = self.expression();
+ let mut inputs = Vec::new();
+ while matches!(self.peek().tt, TokenType::Identifier(_)) {
+ let input_identifier = self.consume_identifier()?;
+ self.consume(TokenType::Colon, "Expected ':'")?;
+ let input_type = self.consume_identifier()?;
- self.consume(TokenType::SemiColon, "Expected ';' at end of statement");
-
- Stmt::DefineValue {
- name: (ident),
- value: (value),
- typ: (typ),
+ inputs.push(FunctionInput {
+ identifier: input_identifier,
+ typ: input_type,
+ });
}
- }
- fn if_statement(&mut self) -> Stmt {
- let condition = self.expression();
+ self.consume(TokenType::ClosingParen, "Expected ')'")?;
- self.consume(
- TokenType::OpeningBrace,
- "Expected '{' at beggining of block",
- );
- let mut body = Vec::new();
- while !self.eof() && self.peek().tt != TokenType::ClosingBrace {
- body.push(self.statement());
- }
- self.advance();
- Stmt::If {
- expr: (condition),
- body: (body),
- else_if: (Vec::new()),
- els: (None),
- } // TODO: implement else if and else
- }
-
- fn for_statement(&mut self) -> Stmt {
- let binding = self.expression();
- let Expr::Variable(binding) = binding else {
- panic!("Left side of for statement must be identifier");
+ // Get the function output
+ let output = if matches!(self.peek().tt, TokenType::Identifier(_)) {
+ Some(self.consume_identifier()?)
+ } else {
+ None
};
- self.consume(
- TokenType::In,
- "Expected 'in' in between identifier and range",
- );
-
- // let range_start = self.expression();
- // self.consume(
- // TokenType::DotDot,
- // "Expected '..' denoting min and max of range",
- // );
- // let range_end = self.expression();
-
- let expr = self.expression();
-
- self.consume(TokenType::OpeningBrace, "Expected '{' after iterator");
-
- let mut body = Vec::new();
- while !self.eof() && self.peek().tt != TokenType::ClosingBrace {
- body.push(self.statement());
- }
- self.advance();
-
- Stmt::For {
- name: (binding),
- iter: (expr),
- body: (body),
- }
- } // TODO: Fix this garbage
-
- fn while_statement(&mut self) -> Stmt {
- let condition = self.expression();
-
- self.consume(
- TokenType::OpeningBrace,
- "Expected '{' at beggining of block",
- );
- let mut body = Vec::new();
- while !self.eof() && self.peek().tt != TokenType::ClosingBrace {
- println!("{:?}", self.peek().tt);
- body.push(self.statement());
- }
- self.consume(
- TokenType::ClosingBrace,
- "Expected '}' after block on while loop",
- );
+ // Get the function body
+ let body = self.block()?;
- self.advance();
- Stmt::While { condition, body }
+ Ok(Stmt::DefineFunction {
+ identifier,
+ inputs,
+ output,
+ body: body.into(),
+ })
}
- fn expression_statement(&mut self) -> Stmt {
- let expr = self.expression();
-
- // FIXME: Move assignment handling
- // if self.advance_if_eq(&TokenType::Eq) {
- // if let Expr::Literal(_ident) = &expr {
- // let value = self.expression();
-
- // self.consume(
- // TokenType::SemiColon,
- // "Expected ';' at end of
- // statement",
- // ); // return Stmt::DefineVariable {
- // // name: (ident.clone()),
- // // value: (value),
- // // typ: (None),
- // // };
- // return Stmt::ExprStmt(expr);
- // }
- // }
-
- self.consume(
- TokenType::SemiColon,
- "Expected ';' at end of expr statement",
- );
- Stmt::ExprStmt(expr)
+ fn return_stmt(&mut self) -> Result<Stmt, ParsingError> {
+ self.consume(TokenType::Return, "Expected return")?;
+ let value = self.expression()?;
+ self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?;
+ Ok(Stmt::Return(value))
}
- fn function_statement(&mut self) -> Stmt {
- let TokenType::Identifier(ident) = self.advance().unwrap().tt.clone() else {
- panic!("Identifier expected after 'fn'");
- };
+ fn assign_variable(&mut self) -> Result<Stmt, ParsingError> {
+ let identifier = self.consume_identifier()?;
+ self.consume(TokenType::Eq, "Expected '='")?;
+ let value = self.expression()?;
+ self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?;
+ Ok(Stmt::AssignVariable { identifier, value })
+ }
- self.consume(TokenType::OpeningParen, "Expected '(' after identifier");
- let mut args: Vec<FuncArgs> = Vec::new();
- while !self.eof() && self.peek().tt != TokenType::ClosingParen {
- let TokenType::Identifier(name) = self.advance().unwrap().tt.clone() else {
- panic!("parameter expected after '('");
- };
-
- let mut typ: Option<String> = None;
-
- if self.peek().tt.clone() == TokenType::Colon {
- self.consume(TokenType::Colon, "How did you even get this error?");
- let TokenType::Identifier(name) = self.peek().tt.clone() else {
- panic!("Type expected after ':', not {:?}", self.peek());
- };
- self.advance();
- typ = Some(name);
- }
+ fn expression_stmt(&mut self) -> Result<Stmt, ParsingError> {
+ let expr = self.expression()?;
+ self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?;
+ Ok(Stmt::ExprStmt(expr))
+ }
- self.advance_if_eq(&TokenType::Comma);
+ fn block(&mut self) -> Result<Stmt, ParsingError> {
+ // Consume the opening brace
+ self.consume(TokenType::OpeningBrace, "Expected '{'")?;
- let arg = FuncArgs {
- name: (name),
- typ: (typ),
- };
- args.push(arg);
- }
- self.advance();
- let mut typ: Option<String> = None;
- if self.peek().tt.clone() == TokenType::Arrow {
- self.advance();
- let TokenType::Identifier(name) = self.peek().tt.clone() else {
- panic!("Type expected after ':', not {:?}", self.peek());
- };
- typ = Some(name);
- self.advance();
- }
- self.consume(TokenType::OpeningBrace, "Expected '{' after parameters");
+ // Get the body of the block
let mut body = Vec::new();
while !self.eof() && self.peek().tt != TokenType::ClosingBrace {
- body.push(self.statement());
+ body.push(self.statement()?);
}
- self.consume(TokenType::ClosingBrace, "Expected '}' after body");
- Stmt::DefineFunction {
- ident: (ident),
- args: (args),
- body: (body),
- return_type: (typ),
- }
- }
+ // Consume the closing brace
+ self.consume(TokenType::ClosingBrace, "Expected '}'")?;
- fn return_statement(&mut self) -> Stmt {
- let expr = self.expression();
- self.consume(TokenType::SemiColon, "Expected ';' after return statement");
- Stmt::Return { value: (expr) }
+ Ok(Stmt::Block(body))
}
}
@@ -321,326 +165,145 @@ mod tests {
use super::{AstParser, Stmt};
use crate::lexer::Lexer;
- use crate::parser::ast::{BinaryOp, Expr, FuncArgs, Literal, UnaryOp};
-
- #[test]
- fn basic_statement_a() {
- let lexer = Lexer::new("var test_a: int = 5 + 3;");
- let tokens = lexer.collect_vec();
-
- let expected_ast = Stmt::DefineVariable {
- name: ("test_a".to_string()),
- value: (Expr::BinaryOp {
- op: (BinaryOp::Add),
- lhs: (Box::new(Expr::Literal(Literal::Integer(5)))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(3)))),
- }),
- typ: Some("int".to_string()),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.statement();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
-
- #[test]
- fn basic_statement_b() {
- let lexer = Lexer::new("val test_b = \"Hello World\";");
- let tokens = lexer.collect_vec();
-
- let expected_ast = Stmt::DefineValue {
- name: ("test_b".to_string()),
- value: (Expr::Literal(Literal::String("Hello World".to_string()))),
- typ: (None),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.statement();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
-
- #[test]
- fn basic_statement_c() {
- let lexer = Lexer::new(
- "\
- fn test_c (a, b, c) {\nreturn (a + b * c);\n}",
- );
- let tokens = lexer.collect_vec();
- println!("{tokens:?}");
-
- let expected_ast = Stmt::DefineFunction {
- ident: ("test_c".to_string()),
- args: (vec![
- FuncArgs {
- name: ("a".to_string()),
- typ: None,
- },
- FuncArgs {
- name: ("b".to_string()),
- typ: None,
- },
- FuncArgs {
- name: ("c".to_string()),
- typ: None,
- },
- ]),
- body: (vec![Stmt::Return {
- value: (Expr::Grouping(Box::new(Expr::BinaryOp {
- op: BinaryOp::Add,
- lhs: Box::new(Expr::Variable("a".to_string())),
- rhs: Box::new(Expr::BinaryOp {
- op: BinaryOp::Mul,
- lhs: Box::new(Expr::Variable("b".to_string())),
- rhs: Box::new(Expr::Variable("c".to_string())),
- }),
- }))),
- }]),
- return_type: (None),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.statement();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
- #[test]
- fn basic_statement_d() {
- let lexer = Lexer::new(
- "\
- while true {\nprint(\"Hello World\");\nprintln(5 + 7/-3);\n}",
- );
- let tokens = lexer.collect_vec();
- println!("{tokens:?}");
-
- let expected_ast = Stmt::While {
- condition: (Expr::Literal(Literal::Bool(true))),
- body: (vec![
- Stmt::ExprStmt(Expr::Call {
- ident: Box::new(Expr::Variable("print".to_string())),
- args: (vec![Expr::Literal(Literal::String("Hello World".to_string()))]),
- }),
- Stmt::ExprStmt(Expr::Call {
- ident: Box::new(Expr::Variable("println".to_string())),
- args: (vec![Expr::BinaryOp {
- op: (BinaryOp::Add),
- lhs: (Box::new(Expr::Literal(Literal::Integer(5)))),
- rhs: (Box::new(Expr::BinaryOp {
- op: (BinaryOp::Div),
- lhs: (Box::new(Expr::Literal(Literal::Integer(7)))),
- rhs: (Box::new(Expr::UnaryOp {
- op: (UnaryOp::Neg),
- value: (Box::new(Expr::Literal(Literal::Integer(3)))),
- })),
- })),
- }]),
- }),
- ]),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.statement();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
- #[test]
- fn basic_statement_e() {
- let lexer = Lexer::new(
- "\
- if a+5 > 10 {\nprint(a);\n}\nif a+5 < 10 {\nprintln(10);\n}\nif a+5 == 10 \
- {\nprint(toString(10));\na = true;\n}",
- );
- let tokens = lexer.collect_vec();
- // println!("{tokens:?}");
-
- let expected_ast = vec![
- Stmt::If {
- expr: (Expr::BinaryOp {
- op: (BinaryOp::Gt),
- lhs: (Box::new(Expr::BinaryOp {
- op: (BinaryOp::Add),
- lhs: (Box::new(Expr::Variable("a".to_string()))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(5)))),
- })),
- rhs: (Box::new(Expr::Literal(Literal::Integer(10)))),
- }),
- body: (vec![Stmt::ExprStmt(Expr::Call {
- ident: (Box::new(Expr::Variable("print".to_string()))),
- args: (vec![Expr::Variable("a".to_string())]),
- })]),
- else_if: (Vec::new()),
- els: (None),
- },
- Stmt::If {
- expr: (Expr::BinaryOp {
- op: (BinaryOp::Lt),
- lhs: (Box::new(Expr::BinaryOp {
- op: (BinaryOp::Add),
- lhs: (Box::new(Expr::Variable("a".to_string()))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(5)))),
- })),
- rhs: (Box::new(Expr::Literal(Literal::Integer(10)))),
- }),
- body: (vec![Stmt::ExprStmt(Expr::Call {
- ident: (Box::new(Expr::Variable("println".to_string()))),
- args: (vec![Expr::Literal(Literal::Integer(10))]),
- })]),
- else_if: (Vec::new()),
- els: (None),
- },
- Stmt::If {
- expr: (Expr::BinaryOp {
- op: (BinaryOp::EqEq),
- lhs: (Box::new(Expr::BinaryOp {
- op: (BinaryOp::Add),
- lhs: (Box::new(Expr::Variable("a".to_string()))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(5)))),
- })),
- rhs: (Box::new(Expr::Literal(Literal::Integer(10)))),
- }),
- body: (vec![
- Stmt::ExprStmt(Expr::Call {
- ident: (Box::new(Expr::Variable("print".to_string()))),
- // ident: (Box::new(Expr::Literal(Literal::String("print".to_string())))),
- args: (vec![Expr::Call {
- ident: (Box::new(Expr::Variable("toString".to_string()))),
- // ident: Box::new(Expr::Literal(Literal::String("toString".
- // to_string()))),
- args: vec![Expr::Literal(Literal::Integer(10))],
- }]),
- }),
- Stmt::AssignVariable {
- name: ("a".to_string()),
- value: (Expr::Literal(Literal::Bool(true))),
- },
- ]),
-
- else_if: (Vec::new()),
- els: (None),
- },
- ];
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.parse();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
-
- #[test]
- fn basic_statement_f() {
- let lexer = Lexer::new("test_a = 5 + 3;");
- let tokens = lexer.collect_vec();
-
- let expected_ast = Stmt::AssignVariable {
- name: ("test_a".to_string()),
- value: (Expr::BinaryOp {
- op: (BinaryOp::Add),
- lhs: (Box::new(Expr::Literal(Literal::Integer(5)))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(3)))),
- }),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.statement();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
- #[test]
- fn basic_statement_g() {
- let lexer = Lexer::new(
- "\
- fn times_two(x: int) -> int {\nval y: int = x*2;\nreturn y;\n}",
- );
- let tokens = lexer.collect_vec();
-
- let expected_ast = Stmt::DefineFunction {
- ident: ("times_two".to_string()),
- args: (vec![FuncArgs {
- name: ("x".to_string()),
- typ: (Some("int".to_string())),
- }]),
- body: (vec![
- Stmt::DefineValue {
- name: "y".to_string(),
- value: (Expr::BinaryOp {
- op: (BinaryOp::Mul),
- lhs: (Box::new(Expr::Variable("x".to_string()))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(2)))),
- }),
- typ: Some("int".to_string()),
- },
- Stmt::Return {
- value: (Expr::Variable("y".to_string())),
- },
- ]),
-
- return_type: Some("int".to_string()),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.statement();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
-
- #[test]
- fn basic_statement_h() {
- let lexer = Lexer::new("for i in 1 .. 3 {\nfor j in [1, 2, 3] {\nprint(j*i);}}");
- let tokens = lexer.collect_vec();
-
- let expected_ast = Stmt::For {
- name: ("i".to_string()),
- iter: (Expr::BinaryOp {
- op: (BinaryOp::Range),
- lhs: (Box::new(Expr::Literal(Literal::Integer(1)))),
- rhs: (Box::new(Expr::Literal(Literal::Integer(3)))),
- }),
- body: (vec![Stmt::For {
- name: ("j".to_string()),
- iter: (Expr::Literal(Literal::List(vec![
- Expr::Literal(Literal::Integer(1)),
- Expr::Literal(Literal::Integer(2)),
- Expr::Literal(Literal::Integer(3)),
- ]))),
- body: (vec![Stmt::ExprStmt(Expr::Call {
- ident: Box::new(Expr::Variable("print".to_string())),
- args: (vec![Expr::BinaryOp {
- op: (BinaryOp::Mul),
- lhs: (Box::new(Expr::Variable("j".to_string()))),
- rhs: (Box::new(Expr::Variable("i".to_string()))),
- }]),
- })]),
- }]),
- };
-
- let mut parser = AstParser::new(tokens);
- let generated_ast = parser.statement();
-
- println!("Expected AST:\n{expected_ast:#?}\n\n");
- println!("Generated AST:\n{generated_ast:#?}\n\n");
-
- assert_eq!(expected_ast, generated_ast);
- }
+ use crate::parser::ast::{BinaryOp, ExprKind, FunctionInput, Literal};
+
+ // #[test]
+ // fn standalone_blocks() {
+ // let tokens = Lexer::new("{{{ 0; }}}").collect_vec();
+ //
+ // let expected_ast =
+ // Ok(Stmt::Block(vec![Stmt::Block(vec![Stmt::Block(vec![
+ // Stmt::ExprStmt(Literal::Integer(0).into()),
+ // ])])]));
+ //
+ // let mut parser = AstParser::new(tokens);
+ // let generated_ast = parser.statement();
+ //
+ // println!("Expected AST:\n{expected_ast:#?}\n\n");
+ // println!("Generated AST:\n{generated_ast:#?}\n\n");
+ //
+ // assert_eq!(expected_ast, generated_ast);
+ // }
+ //
+ // #[test]
+ // fn basic_variable_definition() {
+ // let tokens = Lexer::new("var foo: Int = 5 + 3;").collect_vec();
+ //
+ // let expected_ast = Ok(Stmt::DefineVariable {
+ // identifier: "foo".to_string(),
+ // value: ExprKind::BinaryOp {
+ // op: BinaryOp::Add,
+ // lhs: Box::new(ExprKind::Literal(Literal::Integer(5))),
+ // rhs: Box::new(ExprKind::Literal(Literal::Integer(3))),
+ // },
+ // typ: "Int".to_string(),
+ // });
+ //
+ // let mut parser = AstParser::new(tokens);
+ // let generated_ast = parser.statement();
+ //
+ // println!("Expected AST:\n{expected_ast:#?}\n\n");
+ // println!("Generated AST:\n{generated_ast:#?}\n\n");
+ //
+ // assert_eq!(expected_ast, generated_ast);
+ // }
+ //
+ // #[test]
+ // fn basic_function() {
+ // let tokens = Lexer::new(
+ // r#"
+ // fn foo(bar: Int) Int {
+ // var baz: Int = bar + 1;
+ // baz = baz + 1;
+ // return baz;
+ // }
+ // "#,
+ // )
+ // .collect_vec();
+ //
+ // let expected_ast = Ok(Stmt::DefineFunction {
+ // identifier: "foo".to_owned(),
+ // inputs: vec![FunctionInput {
+ // identifier: "bar".to_owned(),
+ // typ: "Int".to_owned(),
+ // }],
+ // output: Some("Int".to_owned()),
+ // body: Box::new(Stmt::Block(vec![
+ // Stmt::DefineVariable {
+ // identifier: "baz".to_owned(),
+ // value: ExprKind::BinaryOp {
+ // op: BinaryOp::Add,
+ // lhs:
+ // Box::new(ExprKind::Identifier("bar".to_owned())),
+ // rhs: Box::new(Literal::Integer(1).into()), },
+ // typ: "Int".to_owned(),
+ // },
+ // Stmt::AssignVariable {
+ // identifier: "baz".to_owned(),
+ // value: ExprKind::BinaryOp {
+ // op: BinaryOp::Add,
+ // lhs:
+ // Box::new(ExprKind::Identifier("baz".to_owned())),
+ // rhs: Box::new(Literal::Integer(1).into()), },
+ // },
+ // Stmt::Return(ExprKind::Identifier("baz".to_owned())),
+ // ])),
+ // });
+ //
+ // let mut parser = AstParser::new(tokens);
+ // let generated_ast = parser.statement();
+ //
+ // println!("Expected AST:\n{expected_ast:#?}\n\n");
+ // println!("Generated AST:\n{generated_ast:#?}\n\n");
+ //
+ // assert_eq!(expected_ast, generated_ast);
+ // }
+ //
+ // #[test]
+ // fn basic_conditional() {
+ // let tokens = Lexer::new(
+ // r#"
+ // if foo {
+ // 0;
+ // } else if bar {
+ // 1;
+ // } else if baz {
+ // 2;
+ // } else {
+ // 3;
+ // }
+ // "#,
+ // )
+ // .collect_vec();
+ //
+ // let expected_ast = Ok(Stmt::IfStmt {
+ // condition: ExprKind::Identifier("foo".to_owned()),
+ // if_then: Box::new(Stmt::Block(vec![Stmt::ExprStmt(
+ // Literal::Integer(0).into(),
+ // )])),
+ // else_then: Some(Box::new(Stmt::IfStmt {
+ // condition: ExprKind::Identifier("bar".to_owned()),
+ // if_then: Box::new(Stmt::Block(vec![Stmt::ExprStmt(
+ // Literal::Integer(1).into(),
+ // )])),
+ // else_then: Some(Box::new(Stmt::IfStmt {
+ // condition: ExprKind::Identifier("baz".to_owned()),
+ // if_then: Box::new(Stmt::Block(vec![Stmt::ExprStmt(
+ // Literal::Integer(2).into(),
+ // )])),
+ // else_then: Some(Box::new(Stmt::Block(vec![Stmt::ExprStmt(
+ // Literal::Integer(3).into(),
+ // )]))),
+ // })),
+ // })),
+ // });
+ //
+ // let mut parser = AstParser::new(tokens);
+ // let generated_ast = parser.statement();
+ //
+ // println!("Expected AST:\n{expected_ast:#?}\n\n");
+ // println!("Generated AST:\n{generated_ast:#?}\n\n");
+ //
+ // assert_eq!(expected_ast, generated_ast);
+ // }
}