From c35a7ba06a47a8b26bd784df552ad4c881383898 Mon Sep 17 00:00:00 2001 From: Mel Date: Fri, 22 Oct 2021 22:44:21 +0200 Subject: Boolean logic and If expressions. --- grammar.ebnf | 6 +- src/interpret/value.rs | 150 +++++++++++++++++++----------------------------- src/interpret/walker.rs | 113 +++++++++++++++++++++--------------- src/lex/lexer.rs | 2 + src/lex/token.rs | 2 + src/parse/ast/nodes.rs | 3 + src/parse/parser.rs | 38 ++++++++++-- 7 files changed, 171 insertions(+), 143 deletions(-) diff --git a/grammar.ebnf b/grammar.ebnf index d99f268..c4c6914 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -18,14 +18,16 @@ Expression = AssignmentExpression; (* Expressions affected by precedence*) (* NOTE: Only allow IDENTIFIERs and their fields as the LValue for now. *) -AssignmentExpression = IDENTIFIER {"." IDENTIFIER} ("=" | ":=") AssignmentExpression | TermExpression; +AssignmentExpression = IDENTIFIER {"." IDENTIFIER} ("=" | ":=") AssignmentExpression | EqualityExpression; +EqualityExpression = ComparisonExpression { ("==" | "!=") ComparisonExpression }; +ComparisonExpression = TermExpression { ("<" | "<=" | ">" | ">=") TermExpression }; TermExpression = FactorExpression { ("+" | "-") FactorExpression }; FactorExpression = UnaryExpression { ("*" | "/") UnaryExpression }; UnaryExpression = ( "-" | "!" ) UnaryExpression | UnitExpression ; (* Unaffected Expressions *) -UnitExpression = FLOAT | INT | STR | GroupExpression | BlockExpression | FnExpression | TypeExpression | FormExpression | IfExpression; +UnitExpression = FLOAT | INT | STR | TRUE | FALSE |GroupExpression | BlockExpression | FnExpression | TypeExpression | FormExpression | IfExpression; GroupExpression = "(" Expression ")"; BlockExpression = Block; diff --git a/src/interpret/value.rs b/src/interpret/value.rs index 0c7843c..1ca0f0e 100644 --- a/src/interpret/value.rs +++ b/src/interpret/value.rs @@ -9,6 +9,7 @@ pub enum Value { Str(String), Float(f64), Int(i64), + Bool(bool), Fn(Ref), Void, } @@ -85,97 +86,66 @@ impl Value { _ => Err(anyhow!("Left operand can't be multiplied.")), } } -} - -// pub enum Value { -// Float(f64), -// Int(i64), -// } - -// impl Add for WalkValue { -// type Output = Self; - -// fn add(self, rhs: Self) -> Self::Output { -// match self { -// Self::Float(float) => match rhs { -// Self::Float(other_float) => Self::Float(float + other_float), -// Self::Int(other_int) => Self::Float(float + other_int as f64), -// }, -// Self::Int(int) => match rhs { -// Self::Float(other_float) => Self::Float(int as f64 + other_float), -// Self::Int(other_int) => Self::Int(int + other_int), -// }, -// } -// } -// } - -// impl Sub for WalkValue { -// type Output = Self; - -// fn sub(self, rhs: Self) -> Self::Output { -// match self { -// Self::Float(float) => match rhs { -// Self::Float(other_float) => Self::Float(float - other_float), -// Self::Int(other_int) => Self::Float(float - other_int as f64), -// }, -// Self::Int(int) => match rhs { -// Self::Float(other_float) => Self::Float(int as f64 - other_float), -// Self::Int(other_int) => Self::Int(int - other_int), -// }, -// } -// } -// } - -// impl Mul for WalkValue { -// type Output = Self; - -// fn mul(self, rhs: Self) -> Self::Output { -// match self { -// Self::Float(float) => match rhs { -// Self::Float(other_float) => Self::Float(float * other_float), -// Self::Int(other_int) => Self::Float(float * other_int as f64), -// }, -// Self::Int(int) => match rhs { -// Self::Float(other_float) => Self::Float(int as f64 * other_float), -// Self::Int(other_int) => Self::Int(int * other_int), -// }, -// } -// } -// } -// impl Div for WalkValue { -// type Output = Self; - -// fn div(self, rhs: Self) -> Self::Output { -// match self { -// Self::Float(float) => match rhs { -// Self::Float(other_float) => Self::Float(float / other_float), -// Self::Int(other_int) => Self::Float(float / other_int as f64), -// }, -// Self::Int(int) => match rhs { -// Self::Float(other_float) => Self::Float(int as f64 / other_float), -// Self::Int(other_int) => Self::Float(int as f64 / other_int as f64), -// }, -// } -// } -// } + pub fn eq(self, rhs: Value) -> Result { + match self { + Value::Str(l) => match rhs { + Value::Str(r) => Ok(Value::Bool(l == r)), + _ => Ok(Value::Bool(false)), + }, + Value::Float(l) => match rhs { + Value::Float(r) => Ok(Value::Bool(l == r)), + _ => Ok(Value::Bool(false)), + }, + Value::Int(l) => match rhs { + Value::Int(r) => Ok(Value::Bool(l == r)), + _ => Ok(Value::Bool(false)), + }, + Value::Bool(l) => match rhs { + Value::Bool(r) => Ok(Value::Bool(l == r)), + _ => Ok(Value::Bool(false)), + }, + _ => Ok(Value::Bool(false)), + } + } -// impl Neg for WalkValue { -// type Output = Self; + pub fn neq(self, rhs: Value) -> Result { + if let Ok(Value::Bool(value)) = self.eq(rhs) { + Ok(Value::Bool(!value)) + } else { + unreachable!() + } + } -// fn neg(self) -> Self::Output { -// match self { -// Self::Float(float) => Self::Float(-float), -// Self::Int(int) => Self::Int(-int), -// } -// } -// } + pub fn gt(self, rhs: Value) -> Result { + match self { + Value::Float(r) => match rhs { + Value::Float(l) => Ok(Value::Bool(r > l)), + Value::Int(l) => Ok(Value::Bool(r > l as f64)), + _ => Err(anyhow!("Right operand can't be compared.")), + }, + Value::Int(r) => match rhs { + Value::Float(l) => Ok(Value::Bool(r as f64 > l)), + Value::Int(l) => Ok(Value::Bool(r > l)), + _ => Err(anyhow!("Right operand can't be compared.")), + }, + _ => Err(anyhow!("Left operand can't be compared.")), + } + } -// impl Display for WalkValue { -// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -// match self { -// Self::Float(float) => write!(f, "{}", float), -// Self::Int(int) => write!(f, "{}", int), -// } -// } -// } + pub fn gte(self, rhs: Value) -> Result { + match self { + Value::Float(r) => match rhs { + Value::Float(l) => Ok(Value::Bool(r >= l)), + Value::Int(l) => Ok(Value::Bool(r >= l as f64)), + _ => Err(anyhow!("Right operand can't be compared.")), + }, + Value::Int(r) => match rhs { + Value::Float(l) => Ok(Value::Bool(r as f64 >= l)), + Value::Int(l) => Ok(Value::Bool(r >= l)), + _ => Err(anyhow!("Right operand can't be compared.")), + }, + _ => Err(anyhow!("Left operand can't be compared.")), + } + } +} diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs index 16f3f1c..79ef87f 100644 --- a/src/interpret/walker.rs +++ b/src/interpret/walker.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc}; use crate::parse::ast::{ expression::Expression, - nodes::{BinaryOperator as BinOp, Literal, UnaryOperator as UnOp}, + nodes::{BinaryOperator as BinOp, BlockNode, Literal, UnaryOperator as UnOp}, statement::Statement, Program, }; @@ -10,7 +10,6 @@ use anyhow::{anyhow, Result}; use super::{scope::Scope, value::Value}; -// No state for now. pub struct Walker { scope: Scope, } @@ -49,36 +48,37 @@ impl Walker { pub fn walk_expression(&mut self, node: &Expression) -> Result { match node { Expression::Binary { left, op, right } => { + // Assignment + // No difference between assignments for now. + if let BinOp::ConstAssign | BinOp::Assign = op { + let identifier = match left.as_ref() { + Expression::Identifier(i) => i, + _ => todo!("Lvalues can only be identifiers."), + }; + + let value = self.walk_expression(right)?; + self.scope.set_var(identifier, value.clone()); + return Ok(value); + } + + let left = self.walk_expression(left)?; + let right = self.walk_expression(right)?; + + // Other operators let new_value = match op { - BinOp::Plus => self - .walk_expression(left)? - .add(self.walk_expression(right)?), - BinOp::Minus => self - .walk_expression(left)? - .sub(self.walk_expression(right)?), - BinOp::Star => self - .walk_expression(left)? - .mul(self.walk_expression(right)?), - BinOp::Slash => self - .walk_expression(left)? - .div(self.walk_expression(right)?), - // No difference between assignments for now. - BinOp::Assign | BinOp::ConstAssign => { - let identifier = match left.as_ref() { - Expression::Identifier(i) => i, - _ => todo!("Lvalues can only be identifiers."), - }; - - let value = self.walk_expression(right)?; - self.scope.set_var(identifier, value.clone()); - Ok(value) - } - // Boolean logic comes later. - BinOp::Eq | BinOp::Neq | BinOp::Gt | BinOp::Gte | BinOp::Lt | BinOp::Lte => { - todo!() - } + BinOp::Plus => left.add(right), + BinOp::Minus => left.sub(right), + BinOp::Star => left.mul(right), + BinOp::Slash => left.div(right), + BinOp::Eq => left.eq(right), + BinOp::Neq => left.neq(right), + BinOp::Gt => left.gt(right), + BinOp::Gte => left.gte(right), + BinOp::Lt => right.gt(left), + BinOp::Lte => right.gte(left), // No structure access yet. BinOp::Dot => todo!(), + _ => unreachable!(), }?; Ok(new_value) @@ -100,32 +100,35 @@ impl Walker { Literal::Int(int) => Value::Int(*int as i64), Literal::Float(float) => Value::Float(*float as f64), Literal::Str(string) => Value::Str(string.clone()), + Literal::Bool(bool) => Value::Bool(*bool), }; Ok(value) } - Expression::Block(block) => { - self.scope.nest(); - - for statement in block.statements.iter() { - self.walk_statement(statement)?; + Expression::Block(block) => self.walk_block(block.as_ref()), + Expression::Fn(fn_node) => { + let node = fn_node.as_ref().clone(); + Ok(Value::Fn(RefCell::new(Rc::new(node)))) + } + Expression::If(if_node) => { + for conditional in &if_node.conditionals { + if let Value::Bool(bool) = self.walk_expression(&conditional.condition)? { + if bool { + return self.walk_block(&conditional.block); + } + } else { + return Err(anyhow!( + "If and Elif expressions can only take boolean values as conditions." + )); + } } - let result = if let Some(tail_expression) = &block.tail_expression { - Ok(self.walk_expression(tail_expression)?) + if let Some(else_conditional) = &if_node.else_block { + self.walk_block(else_conditional) } else { Ok(Value::Void) - }; - - self.scope.unnest(); - - result - } - Expression::Fn(fn_node) => { - let node = fn_node.as_ref().clone(); - Ok(Value::Fn(RefCell::new(Rc::new(node)))) + } } - Expression::If(_) => todo!(), Expression::Identifier(ident) => { if let Some(value) = self.scope.get_var(ident) { Ok(value) @@ -135,4 +138,22 @@ impl Walker { } } } + + fn walk_block(&mut self, block: &BlockNode) -> Result { + self.scope.nest(); + + for statement in block.statements.iter() { + self.walk_statement(statement)?; + } + + let result = if let Some(tail_expression) = &block.tail_expression { + Ok(self.walk_expression(tail_expression)?) + } else { + Ok(Value::Void) + }; + + self.scope.unnest(); + + result + } } diff --git a/src/lex/lexer.rs b/src/lex/lexer.rs index 12dd4d0..f9278aa 100644 --- a/src/lex/lexer.rs +++ b/src/lex/lexer.rs @@ -187,6 +187,8 @@ impl<'s> Lexer<'s> { "type" => TokenVariant::KeywordType, "form" => TokenVariant::KeywordForm, "self" => TokenVariant::KeywordSelf, + "true" => TokenVariant::KeywordTrue, + "false" => TokenVariant::KeywordFalse, "return" => TokenVariant::KeywordReturn, "print" => TokenVariant::KeywordPrint, _ => TokenVariant::Ident(buffer), diff --git a/src/lex/token.rs b/src/lex/token.rs index efd4c5a..5debbfd 100644 --- a/src/lex/token.rs +++ b/src/lex/token.rs @@ -55,6 +55,8 @@ pub enum TokenVariant { KeywordElse, KeywordForm, KeywordType, + KeywordTrue, + KeywordFalse, KeywordSelf, KeywordReturn, KeywordPrint, diff --git a/src/parse/ast/nodes.rs b/src/parse/ast/nodes.rs index 2347d5b..36b15c8 100644 --- a/src/parse/ast/nodes.rs +++ b/src/parse/ast/nodes.rs @@ -63,6 +63,7 @@ pub enum Literal { Int(u32), Float(f32), Str(String), + Bool(bool), } impl Literal { @@ -71,6 +72,8 @@ impl Literal { Int(int) => Self::Int(int), Float(float) => Self::Float(float), Str(string) => Self::Str(string), + KeywordTrue => Self::Bool(true), + KeywordFalse => Self::Bool(false), _ => panic!("Can't create literal from '{:?}'.", token.variant), } } diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 41fd954..219065b 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -76,7 +76,7 @@ impl> Parser { fn assignment_expression(&mut self) -> Result { // Parse any expressions as l-values for now. - let left = self.term_expression()?; + let left = self.equality_expression()?; if let Some(op) = consume_if!(self, Assign | ConstAssign) { let right = self.assignment_expression()?; @@ -91,6 +91,38 @@ impl> Parser { } } + fn equality_expression(&mut self) -> Result { + let mut left = self.comparison_expression()?; + + while let Some(op) = consume_if!(self, OpEq | OpNeq) { + let right = self.comparison_expression()?; + + left = Expression::Binary { + left: Box::new(left), + op: BinaryOperator::from_token(op), + right: Box::new(right), + }; + } + + Ok(left) + } + + fn comparison_expression(&mut self) -> Result { + let mut left = self.term_expression()?; + + while let Some(op) = consume_if!(self, OpGt | OpGte | OpLt | OpLte) { + let right = self.term_expression()?; + + left = Expression::Binary { + left: Box::new(left), + op: BinaryOperator::from_token(op), + right: Box::new(right), + }; + } + + Ok(left) + } + fn term_expression(&mut self) -> Result { let mut left = self.factor_expression()?; @@ -143,10 +175,6 @@ impl> Parser { 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 -- cgit 1.4.1