diff options
Diffstat (limited to 'src/parse')
| -rw-r--r-- | src/parse/ast.rs | 55 | ||||
| -rw-r--r-- | src/parse/ast/expression.rs | 127 | ||||
| -rw-r--r-- | src/parse/ast/mod.rs | 21 | ||||
| -rw-r--r-- | src/parse/ast/statement.rs | 39 | ||||
| -rw-r--r-- | src/parse/ast/value.rs | 106 | ||||
| -rw-r--r-- | src/parse/macros.rs | 59 | ||||
| -rw-r--r-- | src/parse/mod.rs | 1 | ||||
| -rw-r--r-- | src/parse/parser.rs | 252 |
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, + }) + } } |
