aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--grammar.ebnf12
-rw-r--r--src/interpret/walker.rs43
-rw-r--r--src/lex/lexer.rs7
-rw-r--r--src/lex/token.rs10
-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
12 files changed, 612 insertions, 120 deletions
diff --git a/grammar.ebnf b/grammar.ebnf
index 425c64a..d99f268 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -25,7 +25,7 @@ UnaryExpression = ( "-" | "!" ) UnaryExpression | UnitExpression ;
(* Unaffected Expressions *)
-UnitExpression = FLOAT | INT | STR | GroupExpression | BlockExpression | FnExpression | | TypeExpression | FormExpression | IfExpression;
+UnitExpression = FLOAT | INT | STR | GroupExpression | BlockExpression | FnExpression | TypeExpression | FormExpression | IfExpression;
GroupExpression = "(" Expression ")";
BlockExpression = Block;
@@ -37,16 +37,14 @@ IfExpression = "if" Expression Block { "elif" Expression Block } [ "else" Block
(* Parts *)
-FnHeader = (FnSingleParameter | FnMultipleParameters) ["->" Type];
-FnSingleParameter = "self" | FnParameter;
-FnMultipleParameters = "(" FnSingleParameter { "," FnParameter} ")";
-FnParameter = IdentiferType;
+FnHeader = (FnParameters) ["->" Type];
+FnParameters = ("self" | FnParameter) { "," FnParameter};
(* Utils *)
Block = "{" { Statement } [Expression] "}";
-TypeBlock = "{" [ IdentiferType ] { "," IdentiferType } "}";
+TypeBlock = "{" [ TypedIdentifier ] { "," TypedIdentifier } "}";
-IdentiferType = IDENTIFIER ":" Type;
+TypedIdentifier = IDENTIFIER [":" Type];
(* NOTE: Type doesn't include anything other than simple named types for now. *)
Type = IDENTIFIER;
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index e301d44..817e94e 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -3,7 +3,10 @@ use std::{
ops::{Add, Div, Mul, Neg, Sub},
};
-use crate::{lex::token::TokenVariant::*, parse::ast::Expression};
+use crate::parse::ast::{
+ expression::Expression,
+ value::{BinaryOperator, Literal, UnaryOperator},
+};
use anyhow::Result;
// No state for now.
@@ -20,12 +23,20 @@ impl Walker {
let left_value = self.walk(left)?;
let right_value = self.walk(right)?;
- let new_value = match op.variant {
- OpPlus => left_value + right_value,
- OpMinus => left_value - right_value,
- OpStar => left_value * right_value,
- OpSlash => left_value / right_value,
- _ => unreachable!(),
+ let new_value = match op {
+ BinaryOperator::Plus => left_value + right_value,
+ BinaryOperator::Minus => left_value - right_value,
+ BinaryOperator::Star => left_value * right_value,
+ BinaryOperator::Slash => left_value / right_value,
+ BinaryOperator::Eq => todo!(),
+ BinaryOperator::Neq => todo!(),
+ BinaryOperator::Gt => todo!(),
+ BinaryOperator::Gte => todo!(),
+ BinaryOperator::Lt => todo!(),
+ BinaryOperator::Lte => todo!(),
+ BinaryOperator::Assign => todo!(),
+ BinaryOperator::ConstAssign => todo!(),
+ BinaryOperator::Dot => todo!(),
};
Ok(new_value)
@@ -33,25 +44,25 @@ impl Walker {
Expression::Unary { op, right } => {
let value = self.walk(right)?;
- let new_value = match op.variant {
- OpPlus => value,
- OpMinus => -value,
- OpNot => todo!("Implement boolean arithmetic."),
- _ => unreachable!(),
+ let new_value = match op {
+ UnaryOperator::Plus => value,
+ UnaryOperator::Minus => -value,
+ UnaryOperator::Not => todo!("Implement boolean arithmetic."),
};
Ok(new_value)
}
Expression::Group(node) => self.walk(node),
Expression::Literal(token) => {
- let value = match token.variant {
- Int(int) => WalkValue::Int(int as i64),
- Float(float) => WalkValue::Float(float as f64),
- _ => unreachable!(),
+ let value = match token {
+ Literal::Int(int) => WalkValue::Int(*int as i64),
+ Literal::Float(float) => WalkValue::Float(*float as f64),
+ _ => todo!(),
};
Ok(value)
}
+ _ => todo!(),
}
}
}
diff --git a/src/lex/lexer.rs b/src/lex/lexer.rs
index 6e188a0..b6fee0d 100644
--- a/src/lex/lexer.rs
+++ b/src/lex/lexer.rs
@@ -181,10 +181,15 @@ impl<'s> Lexer<'s> {
let variant = match buffer.as_str() {
"fn" => TokenVariant::KeywordFn,
+ "if" => TokenVariant::KeywordIf,
+ "elif" => TokenVariant::KeywordElif,
+ "else" => TokenVariant::KeywordElse,
"type" => TokenVariant::KeywordType,
"form" => TokenVariant::KeywordForm,
"self" => TokenVariant::KeywordSelf,
- _ => TokenVariant::Identifier(buffer),
+ "return" => TokenVariant::KeywordReturn,
+ "print" => TokenVariant::KeywordPrint,
+ _ => TokenVariant::Ident(buffer),
};
Token { location, variant }
diff --git a/src/lex/token.rs b/src/lex/token.rs
index 3694525..efd4c5a 100644
--- a/src/lex/token.rs
+++ b/src/lex/token.rs
@@ -10,7 +10,7 @@ pub struct Token {
pub variant: TokenVariant,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub enum TokenVariant {
// Basic math operators
OpPlus,
@@ -45,13 +45,19 @@ pub enum TokenVariant {
Int(u32),
Float(f32),
Str(String),
- Identifier(String),
+
+ Ident(String),
// Keywords
KeywordFn,
+ KeywordIf,
+ KeywordElif,
+ KeywordElse,
KeywordForm,
KeywordType,
KeywordSelf,
+ KeywordReturn,
+ KeywordPrint,
Unknown(char),
Eof,
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,
+ })
+ }
}