This commit is contained in:
Jeff 2024-03-07 06:33:54 -05:00
parent 4d76023775
commit c51b142130
7 changed files with 164 additions and 12 deletions

View File

@ -4,12 +4,13 @@ use crate::{
Value, Value,
}; };
use super::{AbstractTree, Identifier, Logic, Type, ValueNode}; use super::{AbstractTree, Identifier, Logic, Math, Type, ValueNode};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Expression<'src> { pub enum Expression<'src> {
Identifier(Identifier), Identifier(Identifier),
Logic(Box<Logic<'src>>), Logic(Box<Logic<'src>>),
Math(Box<Math<'src>>),
Value(ValueNode<'src>), Value(ValueNode<'src>),
} }
@ -18,6 +19,7 @@ impl<'src> AbstractTree for Expression<'src> {
match self { match self {
Expression::Identifier(identifier) => identifier.expected_type(_context), Expression::Identifier(identifier) => identifier.expected_type(_context),
Expression::Logic(logic) => logic.expected_type(_context), Expression::Logic(logic) => logic.expected_type(_context),
Expression::Math(math) => math.expected_type(_context),
Expression::Value(value_node) => value_node.expected_type(_context), Expression::Value(value_node) => value_node.expected_type(_context),
} }
} }
@ -26,15 +28,17 @@ impl<'src> AbstractTree for Expression<'src> {
match self { match self {
Expression::Identifier(identifier) => identifier.validate(_context), Expression::Identifier(identifier) => identifier.validate(_context),
Expression::Logic(logic) => logic.validate(_context), Expression::Logic(logic) => logic.validate(_context),
Expression::Math(math) => math.validate(_context),
Expression::Value(value_node) => value_node.validate(_context), Expression::Value(value_node) => value_node.validate(_context),
} }
} }
fn run(self, context: &Context) -> Result<Value, RuntimeError> { fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
match self { match self {
Expression::Identifier(identifier) => identifier.run(context), Expression::Identifier(identifier) => identifier.run(_context),
Expression::Logic(logic) => logic.run(context), Expression::Logic(logic) => logic.run(_context),
Expression::Value(value_node) => value_node.run(context), Expression::Math(math) => math.run(_context),
Expression::Value(value_node) => value_node.run(_context),
} }
} }
} }

86
src/abstract_tree/math.rs Normal file
View File

@ -0,0 +1,86 @@
use crate::{
context::Context,
error::{RuntimeError, ValidationError},
value::ValueInner,
Value,
};
use super::{AbstractTree, Expression, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Math<'src> {
Add(Expression<'src>, Expression<'src>),
Subtract(Expression<'src>, Expression<'src>),
Multiply(Expression<'src>, Expression<'src>),
Divide(Expression<'src>, Expression<'src>),
Modulo(Expression<'src>, Expression<'src>),
}
impl<'src> AbstractTree for Math<'src> {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
match self {
Math::Add(left, _)
| Math::Subtract(left, _)
| Math::Multiply(left, _)
| Math::Divide(left, _)
| Math::Modulo(left, _) => left.expected_type(_context),
}
}
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
match self {
Math::Add(left, right)
| Math::Subtract(left, right)
| Math::Multiply(left, right)
| Math::Divide(left, right)
| Math::Modulo(left, right) => {
let left_type = left.expected_type(context)?;
let right_type = right.expected_type(context)?;
match (left_type, right_type) {
(Type::Integer, Type::Integer)
| (Type::Float, Type::Float)
| (Type::Integer, Type::Float)
| (Type::Float, Type::Integer) => Ok(()),
_ => Err(ValidationError::ExpectedIntegerOrFloat),
}
}
}
}
fn run(self, context: &Context) -> Result<Value, RuntimeError> {
match self {
Math::Add(left, right) => {
let left_value = left.run(context)?;
let right_value = right.run(context)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref())
{
Ok(Value::integer(left + right))
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat,
))
}
}
Math::Subtract(_, _) => todo!(),
Math::Multiply(left, right) => {
let left_value = left.run(context)?;
let right_value = right.run(context)?;
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
(left_value.inner().as_ref(), right_value.inner().as_ref())
{
Ok(Value::integer(left * right))
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedIntegerOrFloat,
))
}
}
Math::Divide(_, _) => todo!(),
Math::Modulo(_, _) => todo!(),
}
}
}

View File

@ -4,13 +4,15 @@ pub mod expression;
pub mod identifier; pub mod identifier;
pub mod logic; pub mod logic;
pub mod r#loop; pub mod r#loop;
pub mod math;
pub mod statement; pub mod statement;
pub mod r#type; pub mod r#type;
pub mod value_node; pub mod value_node;
pub use self::{ pub use self::{
assignment::Assignment, block::Block, expression::Expression, identifier::Identifier, assignment::Assignment, block::Block, expression::Expression, identifier::Identifier,
logic::Logic, r#loop::Loop, r#type::Type, statement::Statement, value_node::ValueNode, logic::Logic, math::Math, r#loop::Loop, r#type::Type, statement::Statement,
value_node::ValueNode,
}; };
use crate::{ use crate::{

View File

@ -67,6 +67,12 @@ impl Error {
Label::new(span.start..span.end).with_message("Expected boolean."), Label::new(span.start..span.end).with_message("Expected boolean."),
); );
} }
ValidationError::ExpectedIntegerOrFloat => {
report = report.with_label(
Label::new(span.start..span.end)
.with_message("Expected integer or float."),
);
}
ValidationError::RwLockPoison(_) => todo!(), ValidationError::RwLockPoison(_) => todo!(),
ValidationError::TypeCheck(TypeCheckError { actual, expected }) => { ValidationError::TypeCheck(TypeCheckError { actual, expected }) => {
report = report.with_label(Label::new(span.start..span.end).with_message( report = report.with_label(Label::new(span.start..span.end).with_message(
@ -132,6 +138,7 @@ impl From<ValidationError> for RuntimeError {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum ValidationError { pub enum ValidationError {
ExpectedBoolean, ExpectedBoolean,
ExpectedIntegerOrFloat,
RwLockPoison(RwLockPoisonError), RwLockPoison(RwLockPoisonError),
TypeCheck(TypeCheckError), TypeCheck(TypeCheckError),
VariableNotFound(Identifier), VariableNotFound(Identifier),

View File

@ -144,16 +144,16 @@ pub fn lexer<'src>() -> impl Parser<
just("!").padded().to(Operator::Not), just("!").padded().to(Operator::Not),
just("!=").padded().to(Operator::NotEqual), just("!=").padded().to(Operator::NotEqual),
just("||").padded().to(Operator::Or), just("||").padded().to(Operator::Or),
// assignment
just("=").padded().to(Operator::Assign),
just("+=").padded().to(Operator::AddAssign),
just("-=").padded().to(Operator::SubAssign),
// math // math
just("+").padded().to(Operator::Add), just("+").padded().to(Operator::Add),
just("-").padded().to(Operator::Subtract), just("-").padded().to(Operator::Subtract),
just("*").padded().to(Operator::Multiply), just("*").padded().to(Operator::Multiply),
just("/").padded().to(Operator::Divide), just("/").padded().to(Operator::Divide),
just("%").padded().to(Operator::Modulo), just("%").padded().to(Operator::Modulo),
// assignment
just("=").padded().to(Operator::Assign),
just("+=").padded().to(Operator::AddAssign),
just("-=").padded().to(Operator::SubAssign),
)) ))
.map(Token::Operator); .map(Token::Operator);
@ -196,6 +196,18 @@ pub fn lexer<'src>() -> impl Parser<
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn math_operators() {
assert_eq!(
lex("1 + 1").unwrap(),
vec![
(Token::Integer(1), (0..1).into()),
(Token::Operator(Operator::Add), (2..4).into()),
(Token::Integer(1), (4..5).into())
]
)
}
#[test] #[test]
fn keywords() { fn keywords() {
assert_eq!(lex("int").unwrap()[0].0, Token::Keyword("int")) assert_eq!(lex("int").unwrap()[0].0, Token::Keyword("int"))

View File

@ -90,7 +90,8 @@ pub fn parser<'src>() -> DustParser<'src> {
use Operator::*; use Operator::*;
let logic = atom let logic_and_math = atom
.clone()
.pratt(( .pratt((
prefix(2, just(Token::Operator(Not)), |expression| { prefix(2, just(Token::Operator(Not)), |expression| {
Expression::Logic(Box::new(Logic::Not(expression))) Expression::Logic(Box::new(Logic::Not(expression)))
@ -123,10 +124,31 @@ pub fn parser<'src>() -> DustParser<'src> {
infix(left(1), just(Token::Operator(Or)), |left, right| { infix(left(1), just(Token::Operator(Or)), |left, right| {
Expression::Logic(Box::new(Logic::Or(left, right))) Expression::Logic(Box::new(Logic::Or(left, right)))
}), }),
infix(left(1), just(Token::Operator(Add)), |left, right| {
Expression::Math(Box::new(Math::Add(left, right)))
}),
infix(left(1), just(Token::Operator(Subtract)), |left, right| {
Expression::Math(Box::new(Math::Subtract(left, right)))
}),
infix(left(2), just(Token::Operator(Multiply)), |left, right| {
Expression::Math(Box::new(Math::Multiply(left, right)))
}),
infix(left(2), just(Token::Operator(Divide)), |left, right| {
Expression::Math(Box::new(Math::Divide(left, right)))
}),
infix(left(1), just(Token::Operator(Modulo)), |left, right| {
Expression::Math(Box::new(Math::Modulo(left, right)))
}),
)) ))
.boxed(); .boxed();
choice((r#enum, logic, identifier_expression, list, basic_value)) choice((
r#enum,
logic_and_math,
identifier_expression,
list,
basic_value,
))
}); });
let statement = recursive(|statement| { let statement = recursive(|statement| {
@ -208,6 +230,17 @@ mod tests {
use super::*; use super::*;
#[test]
fn math() {
assert_eq!(
parse(&lex("1 + 1").unwrap()).unwrap()[0].0,
Statement::Expression(Expression::Math(Box::new(Math::Add(
Expression::Value(ValueNode::Integer(1)),
Expression::Value(ValueNode::Integer(1))
))))
);
}
#[test] #[test]
fn r#loop() { fn r#loop() {
assert_eq!( assert_eq!(

View File

@ -95,6 +95,14 @@ impl Value {
Err(ValidationError::ExpectedBoolean) Err(ValidationError::ExpectedBoolean)
} }
pub fn as_number(&self) -> Result<bool, ValidationError> {
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
return Ok(*boolean);
}
Err(ValidationError::ExpectedBoolean)
}
pub fn is_none(&self) -> bool { pub fn is_none(&self) -> bool {
self == get_none() self == get_none()
} }