about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--grammar.ebnf6
-rw-r--r--src/interpret/value.rs150
-rw-r--r--src/interpret/walker.rs113
-rw-r--r--src/lex/lexer.rs2
-rw-r--r--src/lex/token.rs2
-rw-r--r--src/parse/ast/nodes.rs3
-rw-r--r--src/parse/parser.rs38
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<FnNode>),
     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<Value> {
+        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<Value> {
+        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<Value> {
+        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<Value> {
+        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<Value> {
         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<Value> {
+        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<T: Iterator<Item = Token>> Parser<T> {
 
     fn assignment_expression(&mut self) -> Result<Expression> {
         // 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<T: Iterator<Item = Token>> Parser<T> {
         }
     }
 
+    fn equality_expression(&mut self) -> Result<Expression> {
+        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<Expression> {
+        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<Expression> {
         let mut left = self.factor_expression()?;
 
@@ -143,10 +175,6 @@ impl<T: Iterator<Item = Token>> Parser<T> {
                     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