Add indexes
This commit is contained in:
parent
85d954181b
commit
d99e3cb861
@ -4,11 +4,12 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Identifier, Logic, Math, Type, ValueNode};
|
use super::{AbstractTree, Identifier, Index, 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),
|
||||||
|
Index(Box<Index<'src>>),
|
||||||
Logic(Box<Logic<'src>>),
|
Logic(Box<Logic<'src>>),
|
||||||
Math(Box<Math<'src>>),
|
Math(Box<Math<'src>>),
|
||||||
Value(ValueNode<'src>),
|
Value(ValueNode<'src>),
|
||||||
@ -18,6 +19,7 @@ impl<'src> AbstractTree for Expression<'src> {
|
|||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Identifier(identifier) => identifier.expected_type(_context),
|
Expression::Identifier(identifier) => identifier.expected_type(_context),
|
||||||
|
Expression::Index(index) => index.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::Math(math) => math.expected_type(_context),
|
||||||
Expression::Value(value_node) => value_node.expected_type(_context),
|
Expression::Value(value_node) => value_node.expected_type(_context),
|
||||||
@ -27,6 +29,7 @@ impl<'src> AbstractTree for Expression<'src> {
|
|||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Identifier(identifier) => identifier.validate(_context),
|
Expression::Identifier(identifier) => identifier.validate(_context),
|
||||||
|
Expression::Index(index) => index.validate(_context),
|
||||||
Expression::Logic(logic) => logic.validate(_context),
|
Expression::Logic(logic) => logic.validate(_context),
|
||||||
Expression::Math(math) => math.validate(_context),
|
Expression::Math(math) => math.validate(_context),
|
||||||
Expression::Value(value_node) => value_node.validate(_context),
|
Expression::Value(value_node) => value_node.validate(_context),
|
||||||
@ -36,6 +39,7 @@ impl<'src> AbstractTree for Expression<'src> {
|
|||||||
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::Index(index) => index.run(_context),
|
||||||
Expression::Logic(logic) => logic.run(_context),
|
Expression::Logic(logic) => logic.run(_context),
|
||||||
Expression::Math(math) => math.run(_context),
|
Expression::Math(math) => math.run(_context),
|
||||||
Expression::Value(value_node) => value_node.run(_context),
|
Expression::Value(value_node) => value_node.run(_context),
|
||||||
|
76
src/abstract_tree/index.rs
Normal file
76
src/abstract_tree/index.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{AbstractTree, Expression, Type, ValueNode};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct Index<'src> {
|
||||||
|
left: Expression<'src>,
|
||||||
|
right: Expression<'src>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'src> Index<'src> {
|
||||||
|
pub fn new(left: Expression<'src>, right: Expression<'src>) -> Self {
|
||||||
|
Self { left, right }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'src> AbstractTree for Index<'src> {
|
||||||
|
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
let left_type = self.left.expected_type(context)?;
|
||||||
|
|
||||||
|
if let (
|
||||||
|
Expression::Value(ValueNode::List(expression_list)),
|
||||||
|
Expression::Value(ValueNode::Integer(index)),
|
||||||
|
) = (&self.left, &self.right)
|
||||||
|
{
|
||||||
|
let expression = if let Some(expression) = expression_list.get(*index as usize) {
|
||||||
|
expression
|
||||||
|
} else {
|
||||||
|
return Ok(Type::None);
|
||||||
|
};
|
||||||
|
|
||||||
|
expression.expected_type(context)
|
||||||
|
} else {
|
||||||
|
Err(ValidationError::CannotIndex(left_type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
|
let left_type = self.left.expected_type(context)?;
|
||||||
|
|
||||||
|
match left_type {
|
||||||
|
Type::List => todo!(),
|
||||||
|
Type::ListOf(_) => todo!(),
|
||||||
|
Type::ListExact(_) => {
|
||||||
|
let right_type = self.right.expected_type(context)?;
|
||||||
|
|
||||||
|
if let Type::Integer = right_type {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ValidationError::CannotIndexWith(left_type, right_type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ValidationError::CannotIndex(left_type)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
|
let left_value = self.left.run(_context)?;
|
||||||
|
let right_value = self.right.run(_context)?;
|
||||||
|
|
||||||
|
if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) {
|
||||||
|
Ok(list
|
||||||
|
.get(index as usize)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(Value::none))
|
||||||
|
} else {
|
||||||
|
Err(RuntimeError::ValidationFailure(
|
||||||
|
ValidationError::CannotIndexWith(left_value.r#type(), right_value.r#type()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ pub mod assignment;
|
|||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
|
pub mod index;
|
||||||
pub mod logic;
|
pub mod logic;
|
||||||
pub mod r#loop;
|
pub mod r#loop;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
@ -11,7 +12,7 @@ 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, math::Math, r#loop::Loop, r#type::Type, statement::Statement,
|
index::Index, logic::Logic, math::Math, r#loop::Loop, r#type::Type, statement::Statement,
|
||||||
value_node::ValueNode,
|
value_node::ValueNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,7 +26,15 @@ impl<'src> AbstractTree for ValueNode<'src> {
|
|||||||
ValueNode::Boolean(_) => Type::Boolean,
|
ValueNode::Boolean(_) => Type::Boolean,
|
||||||
ValueNode::Float(_) => Type::Float,
|
ValueNode::Float(_) => Type::Float,
|
||||||
ValueNode::Integer(_) => Type::Integer,
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
ValueNode::List(_) => Type::List,
|
ValueNode::List(items) => {
|
||||||
|
let mut item_types = Vec::with_capacity(items.len());
|
||||||
|
|
||||||
|
for expression in items {
|
||||||
|
item_types.push(expression.expected_type(_context)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::ListExact(item_types)
|
||||||
|
}
|
||||||
ValueNode::Map(_) => Type::Map,
|
ValueNode::Map(_) => Type::Map,
|
||||||
ValueNode::Range(_) => Type::Range,
|
ValueNode::Range(_) => Type::Range,
|
||||||
ValueNode::String(_) => Type::String,
|
ValueNode::String(_) => Type::String,
|
||||||
|
@ -85,6 +85,8 @@ impl Error {
|
|||||||
"The variable {identifier} does not exist."
|
"The variable {identifier} does not exist."
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
ValidationError::CannotIndex(_) => todo!(),
|
||||||
|
ValidationError::CannotIndexWith(_, _) => todo!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
report.finish()
|
report.finish()
|
||||||
@ -137,6 +139,8 @@ impl From<ValidationError> for RuntimeError {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ValidationError {
|
pub enum ValidationError {
|
||||||
|
CannotIndex(Type),
|
||||||
|
CannotIndexWith(Type, Type),
|
||||||
ExpectedBoolean,
|
ExpectedBoolean,
|
||||||
ExpectedIntegerOrFloat,
|
ExpectedIntegerOrFloat,
|
||||||
RwLockPoison(RwLockPoisonError),
|
RwLockPoison(RwLockPoisonError),
|
||||||
|
@ -95,7 +95,6 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
use Operator::*;
|
use Operator::*;
|
||||||
|
|
||||||
let logic_and_math = 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)))
|
||||||
@ -143,6 +142,11 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
infix(left(1), just(Token::Operator(Modulo)), |left, right| {
|
infix(left(1), just(Token::Operator(Modulo)), |left, right| {
|
||||||
Expression::Math(Box::new(Math::Modulo(left, right)))
|
Expression::Math(Box::new(Math::Modulo(left, right)))
|
||||||
}),
|
}),
|
||||||
|
infix(
|
||||||
|
left(3),
|
||||||
|
just(Token::Control(Control::Dot)),
|
||||||
|
|left, right| Expression::Index(Box::new(Index::new(left, right))),
|
||||||
|
),
|
||||||
))
|
))
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
|
16
src/value.rs
16
src/value.rs
@ -103,6 +103,22 @@ impl Value {
|
|||||||
Err(ValidationError::ExpectedBoolean)
|
Err(ValidationError::ExpectedBoolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_list(&self) -> Option<&Vec<Value>> {
|
||||||
|
if let ValueInner::List(list) = self.inner().as_ref() {
|
||||||
|
Some(list)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_integer(&self) -> Option<i64> {
|
||||||
|
if let ValueInner::Integer(integer) = self.inner().as_ref() {
|
||||||
|
Some(*integer)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_none(&self) -> bool {
|
pub fn is_none(&self) -> bool {
|
||||||
self == get_none()
|
self == get_none()
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,13 @@ fn logic() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn math() {
|
fn math() {
|
||||||
assert_eq!(interpret("1 + 1"), Ok(Value::integer(2)));
|
assert_eq!(interpret("1 + 1"), Ok(Value::integer(2)));
|
||||||
assert_eq!(interpret("21 + 19 + 1 * 2"), Ok(Value::integer(42)));
|
assert_eq!(
|
||||||
|
interpret("2 * (21 + 19 + 1 * 2) / 2"),
|
||||||
|
Ok(Value::integer(42))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_index() {
|
||||||
|
assert_eq!(interpret("foo = [1, 2, 3]; foo.2"), Ok(Value::integer(3)));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user