aboutsummaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-20 22:15:08 +0200
committerMel <einebeere@gmail.com>2021-10-20 22:15:08 +0200
commita4980b8dbf1394c2b302f1de7c72d2264426b86e (patch)
tree97160332c53d8036ea3f6865ff60dabb2c55ef49 /src/parse
parent8d5a74566beba45f4642838102c5a066ef2aa18d (diff)
downloadrabbithole-a4980b8dbf1394c2b302f1de7c72d2264426b86e.tar.zst
rabbithole-a4980b8dbf1394c2b302f1de7c72d2264426b86e.zip
Statement parsing.
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/ast.rs55
-rw-r--r--src/parse/ast/expression.rs127
-rw-r--r--src/parse/ast/mod.rs21
-rw-r--r--src/parse/ast/statement.rs39
-rw-r--r--src/parse/ast/value.rs106
-rw-r--r--src/parse/macros.rs59
-rw-r--r--src/parse/mod.rs1
-rw-r--r--src/parse/parser.rs252
8 files changed, 566 insertions, 94 deletions
diff --git a/src/parse/ast.rs b/src/parse/ast.rs
deleted file mode 100644
index 0f7ea34..0000000
--- a/src/parse/ast.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use std::fmt::Display;
-
-use crate::lex::token::Token;
-
-#[derive(Debug)]
-pub enum Expression {
- Binary {
- left: Box<Expression>,
- op: Token,
- right: Box<Expression>,
- },
- Unary {
- op: Token,
- right: Box<Expression>,
- },
- Group(Box<Expression>),
- Literal(Token),
-}
-
-impl Display for Expression {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.nested_fmt(f, 0)
- }
-}
-
-impl Expression {
- fn nested_fmt(&self, f: &mut std::fmt::Formatter<'_>, depth: usize) -> std::fmt::Result {
- let pad = " ".repeat(depth);
- match self {
- Expression::Binary { left, op, right } => {
- writeln!(f, "{}Binary:", pad)?;
- writeln!(f, "{}- Left:", pad)?;
- left.nested_fmt(f, depth + 1)?;
- writeln!(f, "{}- Operator: {:?}", pad, op.variant)?;
- writeln!(f, "{}- Right:", pad)?;
- right.nested_fmt(f, depth + 1)?;
- }
- Expression::Unary { op, right } => {
- writeln!(f, "{}Unary:", pad)?;
- writeln!(f, "{}- Operator: {:?}", pad, op.variant)?;
- writeln!(f, "{}- Right:", pad)?;
- right.nested_fmt(f, depth + 1)?;
- }
- Expression::Group(node) => {
- writeln!(f, "{}Group:", pad)?;
- node.nested_fmt(f, depth + 1)?;
- }
- Expression::Literal(token) => {
- writeln!(f, "{}Literal: {:?}", pad, token.variant)?;
- }
- }
-
- Ok(())
- }
-}
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
new file mode 100644
index 0000000..8563492
--- /dev/null
+++ b/src/parse/ast/expression.rs
@@ -0,0 +1,127 @@
+use std::fmt::{self, Display, Formatter};
+
+use super::value::{
+ BinaryOperator, Block, ConditionalBlock, FnHeader, Identifier, Literal, UnaryOperator,
+};
+
+#[derive(Debug)]
+pub enum Expression {
+ Binary {
+ left: Box<Expression>,
+ op: BinaryOperator,
+ right: Box<Expression>,
+ },
+ Unary {
+ op: UnaryOperator,
+ right: Box<Expression>,
+ },
+ Group(Box<Expression>),
+ Block(Box<Block>),
+ Fn {
+ header: FnHeader,
+ body: Box<Block>,
+ },
+ If {
+ conditionals: Vec<ConditionalBlock>,
+ else_block: Option<Box<Block>>,
+ },
+ Literal(Literal),
+ Identifier(Identifier),
+}
+
+impl Display for Expression {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ self.nested_fmt(f, 0)
+ }
+}
+
+impl Expression {
+ pub(crate) fn nested_fmt(&self, f: &mut Formatter<'_>, depth: usize) -> fmt::Result {
+ let pad = " ".repeat(depth);
+ match self {
+ Expression::Binary { left, op, right } => {
+ writeln!(f, "{}Binary:", pad)?;
+ writeln!(f, "{}- Left:", pad)?;
+ left.nested_fmt(f, depth + 1)?;
+ writeln!(f, "{}- Operator: {:?}", pad, op)?;
+ writeln!(f, "{}- Right:", pad)?;
+ right.nested_fmt(f, depth + 1)?;
+ }
+ Expression::Unary { op, right } => {
+ writeln!(f, "{}Unary:", pad)?;
+ writeln!(f, "{}- Operator: {:?}", pad, op)?;
+ writeln!(f, "{}- Right:", pad)?;
+ right.nested_fmt(f, depth + 1)?;
+ }
+ Expression::Group(node) => {
+ writeln!(f, "{}Group:", pad)?;
+ node.nested_fmt(f, depth + 1)?;
+ }
+ Expression::Block(block) => {
+ Self::block_fmt(f, block, depth + 1)?;
+ }
+ Expression::Fn { header, body } => {
+ write!(f, "{}Fn (", pad)?;
+
+ // Write self receiver
+ if header.has_self_receiver {
+ write!(f, "self, ")?;
+ }
+
+ // Write parameters
+ for p in header.parameters.iter() {
+ write!(
+ f,
+ "{}: {}, ",
+ p.identifier,
+ p.type_constraint.as_ref().unwrap_or(&"_".into())
+ )?;
+ }
+
+ // Write return type
+ writeln!(
+ f,
+ ") -> {}:",
+ header.return_type.as_ref().unwrap_or(&"_".into())
+ )?;
+ Self::block_fmt(f, body, depth + 1)?;
+ }
+ Expression::Literal(literal) => {
+ writeln!(f, "{}Literal: {:?}", pad, literal)?;
+ }
+ Expression::Identifier(identifier) => {
+ writeln!(f, "{}Identifier: {:?}", pad, identifier)?;
+ }
+ Expression::If { conditionals, else_block } => {
+ writeln!(f, "{}If:", pad)?;
+ for (i, c) in conditionals.iter().enumerate() {
+ writeln!(f, "{}- Condition {}:", pad, i)?;
+ c.condition.nested_fmt(f, depth + 1)?;
+ writeln!(f, "{}- Body {}:", pad, i)?;
+ Self::block_fmt(f, &c.block, depth + 1)?;
+ }
+ if let Some(e) = else_block {
+ writeln!(f, "{}- Else:", pad)?;
+ Self::block_fmt(f, e, depth + 1)?;
+ }
+ },
+ }
+
+ Ok(())
+ }
+
+ fn block_fmt(f: &mut Formatter<'_>, block: &Block, depth: usize) -> fmt::Result {
+ let pad = " ".repeat(depth);
+ writeln!(f, "{}Block:", pad)?;
+ for (i, statement) in block.statements.iter().enumerate() {
+ writeln!(f, "{}- {}:", pad, i)?;
+ statement.nested_fmt(f, depth + 1)?;
+ }
+ if let Some(tail_expression) = &block.tail_expression {
+ writeln!(f, "{}- Tail:", pad)?;
+ tail_expression.nested_fmt(f, depth + 1)?;
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/parse/ast/mod.rs b/src/parse/ast/mod.rs
new file mode 100644
index 0000000..257675f
--- /dev/null
+++ b/src/parse/ast/mod.rs
@@ -0,0 +1,21 @@
+use std::fmt::Display;
+
+use self::statement::Statement;
+
+pub mod expression;
+pub mod statement;
+pub mod value;
+
+#[derive(Debug)]
+pub struct Program {
+ pub statements: Vec<Statement>,
+}
+
+impl Display for Program {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ for statement in self.statements.iter() {
+ writeln!(f, "{}", statement)?;
+ }
+ Ok(())
+ }
+}
diff --git a/src/parse/ast/statement.rs b/src/parse/ast/statement.rs
new file mode 100644
index 0000000..eec589e
--- /dev/null
+++ b/src/parse/ast/statement.rs
@@ -0,0 +1,39 @@
+use std::fmt::Display;
+
+use super::expression::Expression;
+
+#[derive(Debug)]
+pub enum Statement {
+ Expression(Expression),
+ Print(Expression),
+ Return(Expression),
+}
+
+impl Display for Statement {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.nested_fmt(f, 0)
+ }
+}
+
+impl Statement {
+ pub(crate) fn nested_fmt(
+ &self,
+ f: &mut std::fmt::Formatter<'_>,
+ depth: usize,
+ ) -> std::fmt::Result {
+ let pad = " ".repeat(depth);
+ match self {
+ Statement::Expression(expression) => expression.nested_fmt(f, depth)?,
+ Statement::Print(expression) => {
+ writeln!(f, "{}Print:", pad)?;
+ expression.nested_fmt(f, depth + 1)?;
+ }
+ Statement::Return(expression) => {
+ writeln!(f, "{}Return:", pad)?;
+ expression.nested_fmt(f, depth + 1)?;
+ }
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/parse/ast/value.rs b/src/parse/ast/value.rs
new file mode 100644
index 0000000..263cb58
--- /dev/null
+++ b/src/parse/ast/value.rs
@@ -0,0 +1,106 @@
+use crate::lex::token::{Token, TokenVariant::*};
+
+use super::{expression::Expression, statement::Statement};
+
+#[derive(Debug)]
+pub enum BinaryOperator {
+ Plus,
+ Minus,
+ Star,
+ Slash,
+ Eq,
+ Neq,
+ Gt,
+ Gte,
+ Lt,
+ Lte,
+ Assign,
+ ConstAssign,
+ Dot,
+}
+
+impl BinaryOperator {
+ pub fn from_token(token: Token) -> Self {
+ match token.variant {
+ OpPlus => Self::Plus,
+ OpMinus => Self::Minus,
+ OpStar => Self::Star,
+ OpSlash => Self::Slash,
+ OpEq => Self::Eq,
+ OpNeq => Self::Neq,
+ OpLt => Self::Lt,
+ OpGt => Self::Gt,
+ OpLte => Self::Lte,
+ OpGte => Self::Gte,
+ Assign => Self::Assign,
+ ConstAssign => Self::ConstAssign,
+ Dot => Self::Dot,
+ _ => panic!("Can't create binary operator from '{:?}'.", token.variant)
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum UnaryOperator {
+ Plus,
+ Minus,
+ Not,
+}
+
+impl UnaryOperator {
+ pub fn from_token(token: Token) -> Self {
+ match token.variant {
+ OpPlus => Self::Plus,
+ OpMinus => Self::Minus,
+ OpNot => Self::Not,
+ _ => panic!("Can't create unary operator from '{:?}'.", token.variant)
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum Literal {
+ Int(u32),
+ Float(f32),
+ Str(String),
+}
+
+impl Literal {
+ pub fn from_token(token: Token) -> Self {
+ match token.variant {
+ Int(int) => Self::Int(int),
+ Float(float) => Self::Float(float),
+ Str(string) => Self::Str(string),
+ _ => panic!("Can't create literal from '{:?}'.", token.variant)
+ }
+ }
+}
+
+pub type Identifier = String;
+
+// If the contraint is None the type will have to be inferred
+// during analysis.
+#[derive(Debug)]
+pub struct TypedIdentifier {
+ pub identifier: Identifier,
+ pub type_constraint: Option<Identifier>,
+}
+
+#[derive(Debug)]
+pub struct FnHeader {
+ pub has_self_receiver: bool,
+ pub parameters: Vec<TypedIdentifier>,
+ pub return_type: Option<Identifier>,
+}
+
+#[derive(Debug)]
+pub struct Block {
+ pub statements: Vec<Statement>,
+ pub tail_expression: Option<Expression>,
+}
+
+#[derive(Debug)]
+pub struct ConditionalBlock {
+ pub condition: Expression,
+ pub block: Block,
+}
diff --git a/src/parse/macros.rs b/src/parse/macros.rs
new file mode 100644
index 0000000..0b09152
--- /dev/null
+++ b/src/parse/macros.rs
@@ -0,0 +1,59 @@
+#[macro_export]
+macro_rules! check {
+ ($self:ident, $($variant:pat_param)|+) => {
+ if let Some(token) = $self.tokens.peek() {
+ if let Token {variant: $( $variant )|+, ..} = token {
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! consume {
+ ($self:ident, $($variant:pat_param)|+) => {
+ if let Some(token) = $self.tokens.next() {
+ if let Token {variant: $( $variant )|+, ..} = token {
+ Ok(token)
+ } else {
+ Err(anyhow!(
+ // Make a better error message
+ "Received unexpected token: '{:?}'.",
+ token.variant
+ ))
+ }
+ } else {
+ // Here too
+ Err(anyhow!("Expected a token."))
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! consume_if {
+ ($self:ident, $($variant:pat_param)|+) => {
+ if let Some(token) = $self.tokens.peek() {
+ if let Token {variant: $( $variant )|+, ..} = token {
+ Some($self.tokens.next().unwrap())
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! inner {
+ ($token:expr, $variant:path ) => {
+ match $token.variant {
+ $variant(inner) => inner,
+ _ => panic!("Tried getting inner content of incorrect variant.")
+ }
+ };
+} \ No newline at end of file
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index a310c76..e45e6fa 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -1,2 +1,3 @@
pub mod ast;
+mod macros;
pub mod parser;
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index dc99262..0316a35 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,7 +1,19 @@
+use super::ast::expression::Expression;
+use super::ast::statement::Statement;
+use super::ast::value::UnaryOperator;
+use super::ast::Program;
+use crate::check;
+use crate::consume;
+use crate::consume_if;
+use crate::inner;
use crate::lex::token::Token;
-use crate::lex::token::TokenVariant;
use crate::lex::token::TokenVariant::*;
-use crate::parse::ast::Expression;
+use crate::parse::ast::value::BinaryOperator;
+use crate::parse::ast::value::Block;
+use crate::parse::ast::value::ConditionalBlock;
+use crate::parse::ast::value::FnHeader;
+use crate::parse::ast::value::Literal;
+use crate::parse::ast::value::TypedIdentifier;
use anyhow::anyhow;
use anyhow::Result;
use std::iter::Peekable;
@@ -17,30 +29,75 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
}
- pub fn parse(&mut self) -> Result<Expression> {
- self.expression()
+ pub fn parse(&mut self) -> Result<Program> {
+ let mut statements = Vec::new();
+
+ while !check!(self, Eof) {
+ statements.push(self.statement()?);
+ }
+
+ Ok(Program { statements })
+ }
+
+ fn statement(&mut self) -> Result<Statement> {
+ let token = self.tokens.peek().expect("Expected token.");
+ match token.variant {
+ KeywordPrint => self.print_statement(),
+ KeywordReturn => self.return_statement(),
+ _ => self.expression_statement(),
+ }
+ }
+
+ fn return_statement(&mut self) -> Result<Statement> {
+ consume!(self, KeywordReturn)?;
+ let expression = self.expression()?;
+ consume!(self, SemiColon)?;
+ Ok(Statement::Return(expression))
+ }
+
+ fn print_statement(&mut self) -> Result<Statement> {
+ consume!(self, KeywordPrint)?;
+ let expression = self.expression()?;
+ consume!(self, SemiColon)?;
+ Ok(Statement::Print(expression))
+ }
+
+ fn expression_statement(&mut self) -> Result<Statement> {
+ let expression = self.expression()?;
+ consume!(self, SemiColon)?;
+ Ok(Statement::Expression(expression))
}
fn expression(&mut self) -> Result<Expression> {
- self.term_expression()
+ self.assignment_expression()
+ }
+
+ fn assignment_expression(&mut self) -> Result<Expression> {
+ // Parse any expressions as l-values for now.
+ let left = self.term_expression()?;
+
+ if let Some(op) = consume_if!(self, Assign | ConstAssign) {
+ let right = self.assignment_expression()?;
+
+ Ok(Expression::Binary {
+ left: Box::new(left),
+ op: BinaryOperator::from_token(op),
+ right: Box::new(right),
+ })
+ } else {
+ Ok(left)
+ }
}
fn term_expression(&mut self) -> Result<Expression> {
let mut left = self.factor_expression()?;
- while matches!(
- self.tokens.peek(),
- Some(Token {
- variant: OpPlus | OpMinus,
- ..
- })
- ) {
- let op = self.tokens.next().unwrap();
+ while let Some(op) = consume_if!(self, OpPlus | OpMinus) {
let right = self.factor_expression()?;
left = Expression::Binary {
left: Box::new(left),
- op,
+ op: BinaryOperator::from_token(op),
right: Box::new(right),
};
}
@@ -51,19 +108,12 @@ impl<T: Iterator<Item = Token>> Parser<T> {
fn factor_expression(&mut self) -> Result<Expression> {
let mut left = self.unary_expression()?;
- while matches!(
- self.tokens.peek(),
- Some(Token {
- variant: OpSlash | OpStar,
- ..
- })
- ) {
- let op = self.tokens.next().unwrap();
+ while let Some(op) = consume_if!(self, OpSlash | OpStar) {
let right = self.unary_expression()?;
left = Expression::Binary {
left: Box::new(left),
- op,
+ op: BinaryOperator::from_token(op),
right: Box::new(right),
};
}
@@ -72,13 +122,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
fn unary_expression(&mut self) -> Result<Expression> {
- let expression = if let Some(Token {
- variant: OpPlus | OpMinus | OpNot,
- ..
- }) = self.tokens.peek()
- {
+ let expression = if check!(self, OpPlus | OpMinus | OpNot) {
Expression::Unary {
- op: self.tokens.next().unwrap(),
+ op: UnaryOperator::from_token(self.tokens.next().unwrap()),
right: Box::new(self.unary_expression()?),
}
} else {
@@ -89,20 +135,113 @@ impl<T: Iterator<Item = Token>> Parser<T> {
}
fn unit_expression(&mut self) -> Result<Expression> {
- if let Some(token) = self.tokens.next() {
+ if let Some(token) = self.tokens.peek() {
match token.variant {
- Int(_) | Float(_) => Ok(Expression::Literal(token)),
+ Int(_) | Float(_) | Str(_) => {
+ let literal = self.tokens.next().unwrap();
+ Ok(Expression::Literal(Literal::from_token(literal)))
+ }
+ // Identifier(_) => match self.tokens.next().unwrap().variant {
+ // Identifier(identifier) => Ok(Expression::Identifier(identifier)),
+ // _ => unreachable!(),
+ // },
+ Ident(_) => Ok(Expression::Identifier(inner!(
+ self.tokens.next().unwrap(),
+ Ident
+ ))),
GroupOpen => {
+ consume!(self, GroupOpen)?;
let expression = self.expression()?;
- if let Some(Token {
- variant: TokenVariant::GroupClose,
- ..
- }) = self.tokens.next()
- {
- Ok(Expression::Group(Box::new(expression)))
- } else {
- Err(anyhow!("Expected ')' after grouping."))
+ consume!(self, GroupClose)?;
+ Ok(Expression::Group(Box::new(expression)))
+ }
+ BlockOpen => Ok(Expression::Block(Box::new(self.block()?))),
+ KeywordFn => {
+ consume!(self, KeywordFn)?;
+ let token = self.tokens.next().expect("Expected function header.");
+
+ let header = {
+ let has_self_receiver = if let KeywordSelf = token.variant {
+ consume_if!(self, Comma);
+ true
+ } else {
+ false
+ };
+
+ let mut parameters = Vec::new();
+ while let Some(token) = consume_if!(self, Ident(_)) {
+ let parameter_name = inner!(token, Ident);
+
+ let type_constraint = if consume_if!(self, Colon).is_some() {
+ Some(inner!(consume!(self, Ident(_))?, Ident))
+ } else {
+ None
+ };
+
+ parameters.push(TypedIdentifier {
+ identifier: parameter_name,
+ type_constraint,
+ });
+
+ if consume_if!(self, Comma).is_none() {
+ break;
+ }
+ }
+
+ let return_type = if consume_if!(self, Arrow).is_some() {
+ Some(inner!(consume!(self, Ident(_))?, Ident))
+ } else {
+ None
+ };
+
+ FnHeader {
+ has_self_receiver,
+ parameters,
+ return_type,
+ }
+ };
+
+ let body = self.block()?;
+
+ Ok(Expression::Fn {
+ header,
+ body: Box::new(body),
+ })
+ }
+ KeywordIf => {
+ consume!(self, KeywordIf)?;
+
+ let mut conditionals = Vec::new();
+
+ let if_condition = self.expression()?;
+ let if_block = self.block()?;
+
+ conditionals.push(ConditionalBlock {
+ condition: if_condition,
+ block: if_block,
+ });
+
+ // Elifs
+ while consume_if!(self, KeywordElif).is_some() {
+ let elif_condition = self.expression()?;
+ let elif_block = self.block()?;
+
+ conditionals.push(ConditionalBlock {
+ condition: elif_condition,
+ block: elif_block,
+ });
}
+
+ let else_conditional = if consume_if!(self, KeywordElse).is_some() {
+ Some(self.block()?)
+ } else {
+ None
+ };
+
+ Ok(Expression::If {
+ conditionals,
+ else_block: else_conditional.map(Box::new),
+ })
}
_ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
}
@@ -110,4 +249,39 @@ impl<T: Iterator<Item = Token>> Parser<T> {
Err(anyhow!("Expected expression."))
}
}
+
+ fn block(&mut self) -> Result<Block> {
+ consume!(self, BlockOpen)?;
+
+ let mut statements = Vec::new();
+ let mut tail_expression = None;
+
+ loop {
+ let token = self.tokens.peek().expect("Unclosed block.");
+ match token.variant {
+ KeywordReturn | KeywordPrint => {
+ statements.push(self.statement()?);
+ }
+ BlockClose => {
+ break;
+ }
+ _ => {
+ let expression = self.expression()?;
+ if consume_if!(self, SemiColon).is_some() {
+ statements.push(Statement::Expression(expression));
+ } else {
+ tail_expression = Some(expression);
+ break;
+ }
+ }
+ }
+ }
+
+ consume!(self, BlockClose)?;
+
+ Ok(Block {
+ statements,
+ tail_expression,
+ })
+ }
}