Implement top-level API with docs

This commit is contained in:
Jeff 2023-09-29 02:53:31 -04:00
parent cdf79f8763
commit 4907dd9f8f
11 changed files with 84 additions and 1989 deletions

View File

@ -2,10 +2,7 @@
//!
//! To deal with errors from dependencies, either create a new error variant
//! or use the MacroFailure variant if the error can only occur inside a macro.
use crate::{
operator::Operator, token::PartialToken, value::value_type::ValueType, value::Value, Node,
ToolInfo,
};
use crate::{value::value_type::ValueType, value::Value, ToolInfo};
use std::{fmt, io, time::SystemTimeError};
@ -118,10 +115,6 @@ pub enum Error {
actual: Value,
},
/// Tried to append a child to a leaf node.
/// Leaf nodes cannot have children.
AppendedToLeafNode(Node),
/// Tried to append a child to a node such that the precedence of the child
/// is not higher. This error should never occur. If it does, please file a
/// bug report.
@ -154,9 +147,9 @@ pub enum Error {
/// An operator is used with a wrong combination of types.
WrongTypeCombination {
/// The operator that whose evaluation caused the error.
operator: Operator,
expected: ValueType,
/// The types that were used in the operator causing it to fail.
actual: Vec<ValueType>,
actual: ValueType,
},
/// An opening brace without a matching closing brace was found.
@ -169,16 +162,6 @@ pub enum Error {
/// For example, writing `4(5)` would yield this error, as the `4` does not have any operands.
MissingOperatorOutsideOfBrace,
/// A `PartialToken` is unmatched, such that it cannot be combined into a full `Token`.
/// This happens if for example a single `=` is found, surrounded by whitespace.
/// It is not a token, but it is part of the string representation of some tokens.
UnmatchedPartialToken {
/// The unmatched partial token.
first: PartialToken,
/// The token that follows the unmatched partial token and that cannot be matched to the partial token, or `None`, if `first` is the last partial token in the stream.
second: Option<PartialToken>,
},
/// An addition operation performed by Rust failed.
AdditionError {
/// The first argument of the addition.
@ -351,10 +334,6 @@ impl Error {
Error::TypeError { actual, expected }
}
pub fn wrong_type_combination(operator: Operator, actual: Vec<ValueType>) -> Self {
Error::WrongTypeCombination { operator, actual }
}
pub fn expected_string(actual: Value) -> Self {
Error::ExpectedString { actual }
}
@ -410,13 +389,6 @@ impl Error {
Error::ExpectedCollection { actual }
}
pub(crate) fn unmatched_partial_token(
first: PartialToken,
second: Option<PartialToken>,
) -> Self {
Error::UnmatchedPartialToken { first, second }
}
pub(crate) fn addition_error(augend: Value, addend: Value) -> Self {
Error::AdditionError { augend, addend }
}
@ -540,7 +512,6 @@ impl fmt::Display for Error {
actual
)
}
AppendedToLeafNode(node) => write!(f, "Syntax error at \"{node}\"."),
PrecedenceViolation => write!(
f,
"Tried to append a node to another node with higher precedence."
@ -561,11 +532,6 @@ impl fmt::Display for Error {
"Type Error. The value {actual} is not one of the following: {expected:?}.",
)
}
WrongTypeCombination { operator, actual } => write!(
f,
"The operator {:?} was called with a wrong combination of types: {:?}",
operator, actual
),
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
MissingOperatorOutsideOfBrace { .. } => write!(
@ -574,22 +540,6 @@ impl fmt::Display for Error {
any arguments on the right, or found a closing parenthesis that is succeeded by \
something that does not take any arguments on the left."
),
UnmatchedPartialToken { first, second } => {
if let Some(second) = second {
write!(
f,
"Found a partial token '{}' that should not be followed by '{}'.",
first, second
)
} else {
write!(
f,
"Found a partial token '{}' that should be followed by another partial \
token.",
first
)
}
}
AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend),
SubtractionError {
minuend,
@ -637,6 +587,7 @@ impl fmt::Display for Error {
),
UnexpectedSourceNode { expected, actual } => write!(f, "Unexpected source node. Expected {expected}, but found {actual}."),
ExpectedFieldName => write!(f, "Expected a field name for this node, but none was found."),
WrongTypeCombination { expected, actual } => write!(f, "Wrong type combination. Expected {expected}, found {actual}."),
}
}
}

View File

@ -1,58 +1,62 @@
//! The top level of Dust's API with functions in interpret Dust code.
use std::ops::Range;
//! The top level of Dust's API with functions to interpret Dust code.
use tree_sitter::{Node, Parser, Tree, TreeCursor};
use crate::{language, Error, Result, Value, VariableMap};
/// Evaluate the given expression string.
/// Evaluate the given source code.
///
/// Returns a vector of results from evaluating the source code. Each comment
/// and statemtent will have its own result.
///
/// # Examples
///
/// ```rust
/// # use dust_lib::*;
/// assert_eq!(eval("1 + 2 + 3"), Ok(Value::from(6)));
/// assert_eq!(eval("1 + 2 + 3"), vec![Ok(Value::from(6))]);
/// ```
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval(source: &str) -> Result<Value> {
pub fn eval(source: &str) -> Vec<Result<Value>> {
let mut context = VariableMap::new();
eval_with_context(source, &mut context)
}
/// Evaluate the given expression string with the given context.
/// Evaluate the given source code with the given context.
///
/// # Examples
///
/// ```rust
/// # use dust_lib::*;
/// let mut context = VariableMap::new();
///
/// context.set_value("one".into(), 1.into()).unwrap(); // Do proper error handling here
/// context.set_value("two".into(), 2.into()).unwrap(); // Do proper error handling here
/// context.set_value("three".into(), 3.into()).unwrap(); // Do proper error handling here
/// assert_eq!(eval_with_context("one + two + three", &mut context), Ok(Value::from(6)));
///
/// let dust_code = "one + two + three; one - two - three;";
///
/// assert_eq!(
/// eval_with_context(dust_code, &mut context),
/// vec![Ok(Value::from(6)), Ok(Value::from(-4))]
/// );
/// ```
pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Result<Value> {
pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Vec<Result<Value>> {
let mut parser = Parser::new();
parser.set_language(language()).unwrap();
let tree = parser.parse(source, None).unwrap();
let sexp = tree.root_node().to_sexp();
println!("{sexp}");
let evaluator = Evaluator::new(tree.clone(), source).unwrap();
let mut cursor = tree.walk();
let results = evaluator.run(context, &mut cursor, source);
println!("{sexp}");
println!("{evaluator:?}");
println!("{results:?}");
println!("{context:?}");
Ok(Value::Empty)
results
}
#[derive(Debug)]
@ -159,7 +163,7 @@ impl Statement {
#[derive(Debug)]
enum Expression {
Identifier(&'static str),
Identifier(String),
Value(Value),
Operation(Operation),
}
@ -176,7 +180,10 @@ impl Expression {
let child = node.child(0).unwrap();
if child.kind() == "identifier" {
todo!()
let byte_range = child.byte_range();
let identifier = &source[byte_range];
Ok(Self::Identifier(identifier.to_string()))
} else if child.kind() == "value" {
Ok(Expression::Value(Value::new(child, source)?))
} else if child.kind() == "operation" {
@ -214,7 +221,7 @@ impl Expression {
#[derive(Debug)]
struct Operation {
left: Box<Expression>,
operator: &'static str,
operator: String,
right: Box<Expression>,
}
@ -224,7 +231,7 @@ impl Operation {
let second_child = node.child(1).unwrap();
let third_child = node.child(2).unwrap();
let left = { Box::new(Expression::new(first_child, source)?) };
let operator = { second_child.child(0).unwrap().kind() };
let operator = { second_child.child(0).unwrap().kind().to_string() };
let right = { Box::new(Expression::new(third_child, source)?) };
Ok(Operation {
@ -242,11 +249,40 @@ impl Operation {
) -> Result<Value> {
let left = self.left.run(context, &mut cursor, source)?;
let right = self.right.run(context, &mut cursor, source)?;
let result = match self.operator {
let result = match self.operator.as_str() {
"+" => left + right,
"=" => {
if let Expression::Identifier(key) = self.left.as_ref() {
context.set_value(key, right)?;
}
Ok(Value::Empty)
}
_ => return Err(Error::CustomMessage("Operator not supported.".to_string())),
};
Ok(result?)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn evaluate_empty() {
assert_eq!(eval("()"), vec![Ok(Value::Empty)]);
assert_eq!(eval("1;"), vec![Ok(Value::Empty)]);
assert_eq!(eval("'foobar';"), vec![Ok(Value::Empty)]);
}
#[test]
fn evaluate_integer() {
assert_eq!(eval("1"), vec![Ok(Value::Integer(1))]);
}
#[test]
fn evaluate_string() {
assert_eq!(eval("'one'"), vec![Ok(Value::String("one".to_string()))]);
}
}

View File

@ -7,10 +7,7 @@
pub use crate::{
error::*,
interface::*,
operator::Operator,
token::PartialToken,
tools::{Tool, ToolInfo, TOOL_LIST},
tree::Node,
value::{
function::Function, table::Table, time::Time, value_type::ValueType,
variable_map::VariableMap, Value,
@ -21,9 +18,6 @@ pub mod tools;
mod error;
mod interface;
mod operator;
mod token;
mod tree;
mod value;
use tree_sitter::Language;

View File

@ -32,19 +32,21 @@ fn main() {
return run_cli_shell();
}
let eval_result = if let Some(path) = args.path {
let eval_results = if let Some(path) = args.path {
let file_contents = read_to_string(path).unwrap();
eval(&file_contents)
} else if let Some(command) = args.command {
eval(&command)
} else {
Ok(Value::Empty)
vec![Ok(Value::Empty)]
};
match eval_result {
Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"),
for result in eval_results {
match result {
Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"),
}
}
}
@ -147,11 +149,13 @@ fn run_cli_shell() {
rl.add_history_entry(line).unwrap();
let eval_result = eval_with_context(line, &mut context);
let eval_results = eval_with_context(line, &mut context);
match eval_result {
Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"),
for result in eval_results {
match result {
Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"),
}
}
}
Err(ReadlineError::Interrupted) => {

View File

@ -1,547 +0,0 @@
use std::fmt::{self, Display, Formatter};
use crate::{error::*, value::Value, Result, VariableMap};
/// An enum that represents operators in the operator tree.
#[derive(Debug, PartialEq, Clone)]
pub enum Operator {
/// A root node in the operator tree.
/// The whole expression is stored under a root node, as well as each subexpression surrounded by parentheses.
RootNode,
/// A binary addition operator.
Add,
/// A binary subtraction operator.
Sub,
/// A unary negation operator.
Neg,
/// A binary multiplication operator.
Mul,
/// A binary division operator.
Div,
/// A binary modulo operator.
Mod,
/// A binary exponentiation operator.
Exp,
/// A binary equality comparator.
Eq,
/// A binary inequality comparator.
Neq,
/// A binary greater-than comparator.
Gt,
/// A binary lower-than comparator.
Lt,
/// A binary greater-than-or-equal comparator.
Geq,
/// A binary lower-than-or-equal comparator.
Leq,
/// A binary logical and operator.
And,
/// A binary logical or operator.
Or,
/// A binary logical not operator.
Not,
/// A binary assignment operator.
Assign,
/// A binary add-assign operator.
AddAssign,
/// A binary subtract-assign operator.
SubAssign,
/// A binary multiply-assign operator.
MulAssign,
/// A binary divide-assign operator.
DivAssign,
/// A binary modulo-assign operator.
ModAssign,
/// A binary exponentiate-assign operator.
ExpAssign,
/// A binary and-assign operator.
AndAssign,
/// A binary or-assign operator.
OrAssign,
/// An n-ary tuple constructor.
Tuple,
/// An n-ary subexpression chain.
Chain,
/// A constant value.
Const {
/** The value of the constant. */
value: Value,
},
/// A write to a variable identifier.
VariableIdentifierWrite {
/// The identifier of the variable.
identifier: String,
},
/// A read from a variable identifier.
VariableIdentifierRead {
/// The identifier of the variable.
identifier: String,
},
/// A function identifier.
FunctionIdentifier {
/// The identifier of the function.
identifier: String,
},
}
impl Operator {
pub(crate) fn value(value: Value) -> Self {
Operator::Const { value }
}
pub(crate) fn variable_identifier_write(identifier: String) -> Self {
Operator::VariableIdentifierWrite { identifier }
}
pub(crate) fn variable_identifier_read(identifier: String) -> Self {
Operator::VariableIdentifierRead { identifier }
}
pub(crate) fn function_identifier(identifier: String) -> Self {
Operator::FunctionIdentifier { identifier }
}
/// Returns the precedence of the operator.
/// A high precedence means that the operator has priority to be deeper in the tree.
pub(crate) const fn precedence(&self) -> i32 {
use crate::operator::Operator::*;
match self {
RootNode => 200,
Add | Sub => 95,
Neg => 110,
Mul | Div | Mod => 100,
Exp => 120,
Eq | Neq | Gt | Lt | Geq | Leq => 80,
And => 75,
Or => 70,
Not => 110,
Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => 50,
Tuple => 40,
Chain => 0,
Const { .. } => 200,
VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => 200,
FunctionIdentifier { .. } => 190,
}
}
/// Returns true if chains of operators with the same precedence as this one should be evaluated left-to-right,
/// and false if they should be evaluated right-to-left.
/// Left-to-right chaining has priority if operators with different order but same precedence are chained.
pub(crate) const fn is_left_to_right(&self) -> bool {
use crate::operator::Operator::*;
!matches!(self, Assign | FunctionIdentifier { .. })
}
/// Returns true if chains of this operator should be flattened into one operator with many arguments.
pub(crate) const fn is_sequence(&self) -> bool {
use crate::operator::Operator::*;
matches!(self, Tuple | Chain)
}
/// True if this operator is a leaf, meaning it accepts no arguments.
// Make this a const fn as soon as whatever is missing gets stable (issue #57563)
pub(crate) fn is_leaf(&self) -> bool {
self.max_argument_amount() == Some(0)
}
/// Returns the maximum amount of arguments required by this operator.
pub(crate) const fn max_argument_amount(&self) -> Option<usize> {
use crate::operator::Operator::*;
match self {
Add | Sub | Mul | Div | Mod | Exp | Eq | Neq | Gt | Lt | Geq | Leq | And | Or
| Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => Some(2),
Tuple | Chain => None,
Not | Neg | RootNode => Some(1),
Const { .. } => Some(0),
VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => Some(0),
FunctionIdentifier { .. } => Some(1),
}
}
/// Returns true if this operator is unary, i.e. it requires exactly one argument.
pub(crate) fn is_unary(&self) -> bool {
self.max_argument_amount() == Some(1) && *self != Operator::RootNode
}
/// Evaluates the operator with the given arguments and context.
pub(crate) fn eval(&self, arguments: &[Value], context: &VariableMap) -> Result<Value> {
use crate::operator::Operator::*;
match self {
RootNode => {
if let Some(first) = arguments.first() {
Ok(first.clone())
} else {
Ok(Value::Empty)
}
}
Add => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
let mut result = String::with_capacity(a.len() + b.len());
result.push_str(a);
result.push_str(b);
Ok(Value::String(result))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
let result = a.checked_add(b);
if let Some(result) = result {
Ok(Value::Integer(result))
} else {
Err(Error::addition_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_number(), arguments[1].as_number())
{
Ok(Value::Float(a + b))
} else {
Err(Error::wrong_type_combination(
self.clone(),
vec![
arguments.get(0).unwrap().into(),
arguments.get(1).unwrap().into(),
],
))
}
}
Sub => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
let result = a.checked_sub(b);
if let Some(result) = result {
Ok(Value::Integer(result))
} else {
Err(Error::subtraction_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} else {
Ok(Value::Float(
arguments[0].as_number()? - arguments[1].as_number()?,
))
}
}
Neg => {
Error::expect_operator_argument_amount(arguments.len(), 1)?;
arguments[0].as_number()?;
if let Ok(a) = arguments[0].as_int() {
let result = a.checked_neg();
if let Some(result) = result {
Ok(Value::Integer(result))
} else {
Err(Error::negation_error(arguments[0].clone()))
}
} else {
Ok(Value::Float(-arguments[0].as_number()?))
}
}
Mul => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
let result = a.checked_mul(b);
if let Some(result) = result {
Ok(Value::Integer(result))
} else {
Err(Error::multiplication_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} else {
Ok(Value::Float(
arguments[0].as_number()? * arguments[1].as_number()?,
))
}
}
Div => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
let result = a.checked_div(b);
if let Some(result) = result {
Ok(Value::Integer(result))
} else {
Err(Error::division_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} else {
Ok(Value::Float(
arguments[0].as_number()? / arguments[1].as_number()?,
))
}
}
Mod => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
let result = a.checked_rem(b);
if let Some(result) = result {
Ok(Value::Integer(result))
} else {
Err(Error::modulation_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} else {
Ok(Value::Float(
arguments[0].as_number()? % arguments[1].as_number()?,
))
}
}
Exp => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
Ok(Value::Float(
arguments[0].as_number()?.powf(arguments[1].as_number()?),
))
}
Eq => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
Ok(Value::Boolean(arguments[0] == arguments[1]))
}
Neq => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
Ok(Value::Boolean(arguments[0] != arguments[1]))
}
Gt => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a > b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a > b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? > arguments[1].as_number()?,
))
}
}
Lt => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a < b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a < b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? < arguments[1].as_number()?,
))
}
}
Geq => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a >= b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a >= b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? >= arguments[1].as_number()?,
))
}
}
Leq => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a <= b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a <= b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? <= arguments[1].as_number()?,
))
}
}
And => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?;
Ok(Value::Boolean(a && b))
}
Or => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?;
Ok(Value::Boolean(a || b))
}
Not => {
Error::expect_operator_argument_amount(arguments.len(), 1)?;
let a = arguments[0].as_boolean()?;
Ok(Value::Boolean(!a))
}
Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => Err(Error::ContextNotMutable),
Tuple => Ok(Value::List(arguments.into())),
Chain => {
if arguments.is_empty() {
return Err(Error::expect_operator_argument_amount(0, 1).unwrap_err());
}
Ok(arguments.last().cloned().unwrap_or(Value::Empty))
}
Const { value } => {
Error::expect_operator_argument_amount(arguments.len(), 0)?;
Ok(value.clone())
}
VariableIdentifierWrite { identifier } => {
Error::expect_operator_argument_amount(arguments.len(), 0)?;
Ok(identifier.clone().into())
}
VariableIdentifierRead { identifier } => {
Error::expect_operator_argument_amount(arguments.len(), 0)?;
if let Some(value) = context.get_value(identifier)? {
Ok(value)
} else {
Err(Error::VariableIdentifierNotFound(identifier.clone()))
}
}
FunctionIdentifier { identifier } => {
Error::expect_operator_argument_amount(arguments.len(), 1)?;
let arguments = &arguments[0];
context.call_function(identifier, arguments)
}
}
}
/// Evaluates the operator with the given arguments and mutable context.
pub(crate) fn eval_mut(&self, arguments: &[Value], context: &mut VariableMap) -> Result<Value> {
use crate::operator::Operator::*;
match self {
Assign => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
let target = arguments[0].as_string()?;
context.set_value(target, arguments[1].clone())?;
Ok(Value::Empty)
}
AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign | AndAssign
| OrAssign => {
Error::expect_operator_argument_amount(arguments.len(), 2)?;
let target = arguments[0].as_string()?;
let left_value = Operator::VariableIdentifierRead {
identifier: target.clone(),
}
.eval(&Vec::new(), context)?;
let arguments = vec![left_value, arguments[1].clone()];
let result = match self {
AddAssign => Operator::Add.eval(&arguments, context),
SubAssign => Operator::Sub.eval(&arguments, context),
MulAssign => Operator::Mul.eval(&arguments, context),
DivAssign => Operator::Div.eval(&arguments, context),
ModAssign => Operator::Mod.eval(&arguments, context),
ExpAssign => Operator::Exp.eval(&arguments, context),
AndAssign => Operator::And.eval(&arguments, context),
OrAssign => Operator::Or.eval(&arguments, context),
_ => unreachable!(
"Forgot to add a match arm for an assign operation: {}",
self
),
}?;
context.set_value(target, result)?;
Ok(Value::Empty)
}
_ => self.eval(arguments, context),
}
}
}
impl Display for Operator {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use crate::operator::Operator::*;
match self {
RootNode => Ok(()),
Add => write!(f, "+"),
Sub => write!(f, "-"),
Neg => write!(f, "-"),
Mul => write!(f, "*"),
Div => write!(f, "/"),
Mod => write!(f, "%"),
Exp => write!(f, "^"),
Eq => write!(f, "=="),
Neq => write!(f, "!="),
Gt => write!(f, ">"),
Lt => write!(f, "<"),
Geq => write!(f, ">="),
Leq => write!(f, "<="),
And => write!(f, "&&"),
Or => write!(f, "||"),
Not => write!(f, "!"),
Assign => write!(f, " = "),
AddAssign => write!(f, " += "),
SubAssign => write!(f, " -= "),
MulAssign => write!(f, " *= "),
DivAssign => write!(f, " /= "),
ModAssign => write!(f, " %= "),
ExpAssign => write!(f, " ^= "),
AndAssign => write!(f, " &&= "),
OrAssign => write!(f, " ||= "),
Tuple => write!(f, ", "),
Chain => write!(f, "; "),
Const { value } => write!(f, "{}", value),
VariableIdentifierWrite { identifier } | VariableIdentifierRead { identifier } => {
write!(f, "{}", identifier)
}
FunctionIdentifier { identifier } => write!(f, "{}", identifier),
}
}
}

View File

@ -1,562 +0,0 @@
use std::fmt::{self, Display, Formatter};
use crate::error::{Error, Result};
#[derive(Clone, PartialEq, Debug)]
pub enum Token {
// Arithmetic
Plus,
Minus,
Star,
Slash,
Percent,
Hat,
// Logic
Eq,
Neq,
Gt,
Lt,
Geq,
Leq,
And,
Or,
Not,
// Precedence
LBrace,
RBrace,
// Assignment
Assign,
PlusAssign,
MinusAssign,
StarAssign,
SlashAssign,
PercentAssign,
HatAssign,
AndAssign,
OrAssign,
// Special
Comma,
Semicolon,
Yield(String, String),
// Values, Variables and Functions
Identifier(String),
Float(f64),
Int(i64),
Boolean(bool),
String(String),
Function(String),
}
/// A partial token is an input character whose meaning depends on the characters around it.
#[derive(Clone, Debug, PartialEq)]
pub enum PartialToken {
/// A partial token that unambiguously maps to a single token.
Token(Token),
/// A partial token that is a literal.
Literal(String),
/// A plus character '+'.
Plus,
/// A minus character '-'.
Minus,
/// A star character '*'.
Star,
/// A slash character '/'.
Slash,
/// A percent character '%'.
Percent,
/// A hat character '^'.
Hat,
/// A whitespace character, e.g. ' '.
Whitespace,
/// An equal-to character '='.
Eq,
/// An exclamation mark character '!'.
ExclamationMark,
/// A greater-than character '>'.
Gt,
/// A lower-than character '<'.
Lt,
/// An ampersand character '&'.
Ampersand,
/// A vertical bar character '|'.
VerticalBar,
}
// Make this a const fn as soon as is_whitespace and to_string get stable (issue #57563)
fn char_to_partial_token(c: char) -> PartialToken {
match c {
'+' => PartialToken::Plus,
'-' => PartialToken::Minus,
'*' => PartialToken::Star,
'/' => PartialToken::Slash,
'%' => PartialToken::Percent,
'^' => PartialToken::Hat,
'(' => PartialToken::Token(Token::LBrace),
')' => PartialToken::Token(Token::RBrace),
',' => PartialToken::Token(Token::Comma),
';' => PartialToken::Token(Token::Semicolon),
'=' => PartialToken::Eq,
'!' => PartialToken::ExclamationMark,
'>' => PartialToken::Gt,
'<' => PartialToken::Lt,
'&' => PartialToken::Ampersand,
'|' => PartialToken::VerticalBar,
c => {
if c.is_whitespace() {
PartialToken::Whitespace
} else {
PartialToken::Literal(c.to_string())
}
}
}
}
impl Token {
#[cfg(not(tarpaulin_include))]
pub(crate) const fn is_leftsided_value(&self) -> bool {
match self {
Token::Plus => false,
Token::Minus => false,
Token::Star => false,
Token::Slash => false,
Token::Percent => false,
Token::Hat => false,
Token::Eq => false,
Token::Neq => false,
Token::Gt => false,
Token::Lt => false,
Token::Geq => false,
Token::Leq => false,
Token::And => false,
Token::Or => false,
Token::Not => false,
Token::LBrace => true,
Token::RBrace => false,
Token::Comma => false,
Token::Semicolon => false,
Token::Yield(_, _) => false,
Token::Assign => false,
Token::PlusAssign => false,
Token::MinusAssign => false,
Token::StarAssign => false,
Token::SlashAssign => false,
Token::PercentAssign => false,
Token::HatAssign => false,
Token::AndAssign => false,
Token::OrAssign => false,
Token::Identifier(_) => true,
Token::Float(_) => true,
Token::Int(_) => true,
Token::Boolean(_) => true,
Token::String(_) => true,
Token::Function(_) => true,
}
}
#[cfg(not(tarpaulin_include))]
pub(crate) const fn is_rightsided_value(&self) -> bool {
match self {
Token::Plus => false,
Token::Minus => false,
Token::Star => false,
Token::Slash => false,
Token::Percent => false,
Token::Hat => false,
Token::Eq => false,
Token::Neq => false,
Token::Gt => false,
Token::Lt => false,
Token::Geq => false,
Token::Leq => false,
Token::And => false,
Token::Or => false,
Token::Not => false,
Token::LBrace => false,
Token::RBrace => true,
Token::Comma => false,
Token::Semicolon => false,
Token::Yield(_, _) => false,
Token::Assign => false,
Token::PlusAssign => false,
Token::MinusAssign => false,
Token::StarAssign => false,
Token::SlashAssign => false,
Token::PercentAssign => false,
Token::HatAssign => false,
Token::AndAssign => false,
Token::OrAssign => false,
Token::Identifier(_) => true,
Token::Float(_) => true,
Token::Int(_) => true,
Token::Boolean(_) => true,
Token::String(_) => true,
Token::Function(_) => true,
}
}
#[cfg(not(tarpaulin_include))]
pub(crate) fn is_assignment(&self) -> bool {
use Token::*;
matches!(
self,
Assign
| PlusAssign
| MinusAssign
| StarAssign
| SlashAssign
| PercentAssign
| HatAssign
| AndAssign
| OrAssign
)
}
}
/// Parses an escape sequence within a string literal.
fn parse_escape_sequence<Iter: Iterator<Item = char>>(iter: &mut Iter) -> Result<char> {
match iter.next() {
Some('"') => Ok('"'),
Some('\\') => Ok('\\'),
Some(c) => Err(Error::IllegalEscapeSequence(format!("\\{}", c))),
None => Err(Error::IllegalEscapeSequence("\\".to_string())),
}
}
/// Parses a string value from the given character iterator.
///
/// The first character from the iterator is interpreted as first character of the string.
/// The string is terminated by a double quote `"`.
/// Occurrences of `"` within the string can be escaped with `\`.
/// The backslash needs to be escaped with another backslash `\`.
fn parse_string_literal<Iter: Iterator<Item = char>>(mut iter: &mut Iter) -> Result<PartialToken> {
let mut result = String::new();
while let Some(c) = iter.next() {
match c {
'"' => break,
'\\' => result.push(parse_escape_sequence(&mut iter)?),
c => result.push(c),
}
}
Ok(PartialToken::Token(Token::String(result)))
}
fn parse_function<Iter: Iterator<Item = char>>(mut iter: &mut Iter) -> Result<PartialToken> {
let mut result = String::new();
while let Some(c) = iter.next() {
match c {
'\'' => break,
'\\' => result.push(parse_escape_sequence(&mut iter)?),
c => result.push(c),
}
}
Ok(PartialToken::Token(Token::Function(result)))
}
/// Converts a string to a vector of partial tokens.
fn str_to_partial_tokens(string: &str) -> Result<Vec<PartialToken>> {
let mut result = Vec::new();
let mut iter = string.chars().peekable();
while let Some(c) = iter.next() {
if c == '"' {
result.push(parse_string_literal(&mut iter)?);
} else if c == '\'' {
result.push(parse_function(&mut iter)?)
} else {
let partial_token = char_to_partial_token(c);
let if_let_successful =
if let (Some(PartialToken::Literal(last)), PartialToken::Literal(literal)) =
(result.last_mut(), &partial_token)
{
last.push_str(literal);
true
} else {
false
};
if !if_let_successful {
result.push(partial_token);
}
}
}
Ok(result)
}
/// Resolves all partial tokens by converting them to complex tokens.
fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> Result<Vec<Token>> {
let mut result = Vec::new();
while !tokens.is_empty() {
let first = tokens[0].clone();
let second = tokens.get(1).cloned();
let third = tokens.get(2).cloned();
let mut cutoff = 2;
result.extend(
match first {
PartialToken::Token(token) => {
cutoff = 1;
Some(token)
}
PartialToken::Plus => match second {
Some(PartialToken::Eq) => Some(Token::PlusAssign),
_ => {
cutoff = 1;
Some(Token::Plus)
}
},
PartialToken::Minus => match second {
Some(PartialToken::Eq) => Some(Token::MinusAssign),
_ => {
cutoff = 1;
Some(Token::Minus)
}
},
PartialToken::Star => match second {
Some(PartialToken::Eq) => Some(Token::StarAssign),
_ => {
cutoff = 1;
Some(Token::Star)
}
},
PartialToken::Slash => match second {
Some(PartialToken::Eq) => Some(Token::SlashAssign),
_ => {
cutoff = 1;
Some(Token::Slash)
}
},
PartialToken::Percent => match second {
Some(PartialToken::Eq) => Some(Token::PercentAssign),
_ => {
cutoff = 1;
Some(Token::Percent)
}
},
PartialToken::Hat => match second {
Some(PartialToken::Eq) => Some(Token::HatAssign),
_ => {
cutoff = 1;
Some(Token::Hat)
}
},
PartialToken::Literal(literal) => {
cutoff = 1;
if let Ok(number) = parse_dec_or_hex(&literal) {
Some(Token::Int(number))
} else if let Ok(number) = literal.parse::<f64>() {
Some(Token::Float(number))
} else if let Ok(boolean) = literal.parse::<bool>() {
Some(Token::Boolean(boolean))
} else {
// If there are two tokens following this one, check if the next one is
// a plus or a minus. If so, then attempt to parse all three tokens as a
// scientific notation number of the form `<coefficient>e{+,-}<exponent>`,
// for example [Literal("10e"), Minus, Literal("3")] => "1e-3".parse().
match (second, third) {
(Some(second), Some(third))
if second == PartialToken::Minus
|| second == PartialToken::Plus =>
{
if let Ok(number) =
format!("{}{}{}", literal, second, third).parse::<f64>()
{
cutoff = 3;
Some(Token::Float(number))
} else {
Some(Token::Identifier(literal.to_string()))
}
}
_ => Some(Token::Identifier(literal.to_string())),
}
}
}
PartialToken::Whitespace => {
cutoff = 1;
None
}
PartialToken::Eq => match second {
Some(PartialToken::Eq) => Some(Token::Eq),
_ => {
cutoff = 1;
Some(Token::Assign)
}
},
PartialToken::ExclamationMark => match second {
Some(PartialToken::Eq) => Some(Token::Neq),
_ => {
cutoff = 1;
Some(Token::Not)
}
},
PartialToken::Gt => match second {
Some(PartialToken::Eq) => Some(Token::Geq),
_ => {
cutoff = 1;
Some(Token::Gt)
}
},
PartialToken::Lt => match second {
Some(PartialToken::Eq) => Some(Token::Leq),
_ => {
cutoff = 1;
Some(Token::Lt)
}
},
PartialToken::Ampersand => match second {
Some(PartialToken::Ampersand) => match third {
Some(PartialToken::Eq) => {
cutoff = 3;
Some(Token::AndAssign)
}
_ => Some(Token::And),
},
_ => return Err(Error::unmatched_partial_token(first, second)),
},
PartialToken::VerticalBar => match second {
Some(PartialToken::VerticalBar) => match third {
Some(PartialToken::Eq) => {
cutoff = 3;
Some(Token::OrAssign)
}
_ => Some(Token::Or),
},
_ => return Err(Error::unmatched_partial_token(first, second)),
},
}
.into_iter(),
);
tokens = &tokens[cutoff..];
}
Ok(result)
}
impl Display for Token {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use self::Token::*;
match self {
Plus => write!(f, "+"),
Minus => write!(f, "-"),
Star => write!(f, "*"),
Slash => write!(f, "/"),
Percent => write!(f, "%"),
Hat => write!(f, "^"),
// Logic
Eq => write!(f, "=="),
Neq => write!(f, "!="),
Gt => write!(f, ">"),
Lt => write!(f, "<"),
Geq => write!(f, ">="),
Leq => write!(f, "<="),
And => write!(f, "&&"),
Or => write!(f, "||"),
Not => write!(f, "!"),
// Precedence
LBrace => write!(f, "("),
RBrace => write!(f, ")"),
// Assignment
Assign => write!(f, "="),
PlusAssign => write!(f, "+="),
MinusAssign => write!(f, "-="),
StarAssign => write!(f, "*="),
SlashAssign => write!(f, "/="),
PercentAssign => write!(f, "%="),
HatAssign => write!(f, "^="),
AndAssign => write!(f, "&&="),
OrAssign => write!(f, "||="),
// Special
Comma => write!(f, ","),
Semicolon => write!(f, ";"),
// Values => write!(f, ""), Variables and Functions
Identifier(identifier) => identifier.fmt(f),
Float(float) => float.fmt(f),
Int(int) => int.fmt(f),
Boolean(boolean) => boolean.fmt(f),
String(string) => fmt::Debug::fmt(string, f),
Function(string) => write!(f, "'{string}'"),
Yield(_, _) => todo!(),
}
}
}
impl Display for PartialToken {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use self::PartialToken::*;
match self {
Token(token) => token.fmt(f),
Literal(literal) => literal.fmt(f),
Whitespace => write!(f, " "),
Plus => write!(f, "+"),
Minus => write!(f, "-"),
Star => write!(f, "*"),
Slash => write!(f, "/"),
Percent => write!(f, "%"),
Hat => write!(f, "^"),
Eq => write!(f, "="),
ExclamationMark => write!(f, "!"),
Gt => write!(f, ">"),
Lt => write!(f, "<"),
Ampersand => write!(f, "&"),
VerticalBar => write!(f, "|"),
}
}
}
pub(crate) fn tokenize(string: &str) -> Result<Vec<Token>> {
partial_tokens_to_tokens(&str_to_partial_tokens(string)?)
}
fn parse_dec_or_hex(literal: &str) -> std::result::Result<i64, std::num::ParseIntError> {
if let Some(literal) = literal.strip_prefix("0x") {
literal.parse()
} else {
literal.parse()
}
}
#[cfg(test)]
mod tests {
use crate::token::{tokenize, Token};
#[test]
fn assignment_lhs_is_identifier() {
let tokens = tokenize("a = 1").unwrap();
assert_eq!(
tokens.as_slice(),
[
Token::Identifier("a".to_string()),
Token::Assign,
Token::Int(1)
]
);
}
}

View File

@ -233,8 +233,7 @@ impl eframe::App for GuiApp {
}
if submit.clicked() {
self.eval_result =
eval_with_context(&self.text_edit_buffer, &mut self.whale_context);
todo!()
}
});
},

View File

@ -1,94 +0,0 @@
use crate::{operator::Operator, Node};
use std::slice::{Iter, IterMut};
/// An iterator that traverses an operator tree in pre-order.
pub struct NodeIter<'a> {
stack: Vec<Iter<'a, Node>>,
}
impl<'a> NodeIter<'a> {
fn new(node: &'a Node) -> Self {
NodeIter {
stack: vec![node.children.iter()],
}
}
}
impl<'a> Iterator for NodeIter<'a> {
type Item = &'a Node;
fn next(&mut self) -> Option<Self::Item> {
loop {
let mut result = None;
if let Some(last) = self.stack.last_mut() {
if let Some(next) = last.next() {
result = Some(next);
} else {
// Can not fail because we just borrowed last.
// We just checked that the iterator is empty, so we can safely discard it.
let _ = self.stack.pop().unwrap();
}
} else {
return None;
}
if let Some(result) = result {
self.stack.push(result.children.iter());
return Some(result);
}
}
}
}
/// An iterator that mutably traverses an operator tree in pre-order.
pub struct OperatorIterMut<'a> {
stack: Vec<IterMut<'a, Node>>,
}
impl<'a> OperatorIterMut<'a> {
fn new(node: &'a mut Node) -> Self {
OperatorIterMut {
stack: vec![node.children.iter_mut()],
}
}
}
impl<'a> Iterator for OperatorIterMut<'a> {
type Item = &'a mut Operator;
fn next(&mut self) -> Option<Self::Item> {
loop {
let mut result = None;
if let Some(last) = self.stack.last_mut() {
if let Some(next) = last.next() {
result = Some(next);
} else {
// Can not fail because we just borrowed last.
// We just checked that the iterator is empty, so we can safely discard it.
let _ = self.stack.pop().unwrap();
}
} else {
return None;
}
if let Some(result) = result {
self.stack.push(result.children.iter_mut());
return Some(&mut result.operator);
}
}
}
}
impl Node {
/// Returns an iterator over all nodes in this tree.
pub fn iter(&self) -> impl Iterator<Item = &Node> {
NodeIter::new(self)
}
/// Returns a mutable iterator over all operators in this tree.
pub fn iter_operators_mut(&mut self) -> impl Iterator<Item = &mut Operator> {
OperatorIterMut::new(self)
}
}

View File

@ -1,691 +0,0 @@
use crate::Function;
use crate::{token::Token, VariableMap};
use crate::{
error::{Error, Result},
operator::*,
value::Value,
};
use std::{
fmt::{self, Display, Formatter},
mem,
};
#[cfg(not(tarpaulin_include))]
mod iter;
/// A node in the operator tree.
/// The operator tree is created by the crate-level `build_operator_tree` method.
/// It can be evaluated for a given context with the `Node::eval` method.
///
/// The advantage of constructing the operator tree separately from the actual evaluation is that it can be evaluated arbitrarily often with different contexts.
#[derive(Debug, PartialEq, Clone)]
pub struct Node {
operator: Operator,
children: Vec<Node>,
}
impl Node {
fn new(operator: Operator) -> Self {
Self {
children: Vec::new(),
operator,
}
}
fn root_node() -> Self {
Self::new(Operator::RootNode)
}
pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| match node.operator() {
Operator::VariableIdentifierWrite { identifier }
| Operator::VariableIdentifierRead { identifier }
| Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()),
_ => None,
})
}
/// Returns an iterator over all identifiers in this expression, allowing mutation.
/// Each occurrence of an identifier is returned separately.
pub fn iter_identifiers_mut(&mut self) -> impl Iterator<Item = &mut String> {
self.iter_operators_mut()
.filter_map(|operator| match operator {
Operator::VariableIdentifierWrite { identifier }
| Operator::VariableIdentifierRead { identifier }
| Operator::FunctionIdentifier { identifier } => Some(identifier),
_ => None,
})
}
/// Returns an iterator over all variable identifiers in this expression.
/// Each occurrence of a variable identifier is returned separately.
pub fn iter_variable_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| match node.operator() {
Operator::VariableIdentifierWrite { identifier }
| Operator::VariableIdentifierRead { identifier } => Some(identifier.as_str()),
_ => None,
})
}
/// Returns an iterator over all variable identifiers in this expression, allowing mutation.
/// Each occurrence of a variable identifier is returned separately.
pub fn iter_variable_identifiers_mut(&mut self) -> impl Iterator<Item = &mut String> {
self.iter_operators_mut()
.filter_map(|operator| match operator {
Operator::VariableIdentifierWrite { identifier }
| Operator::VariableIdentifierRead { identifier } => Some(identifier),
_ => None,
})
}
/// Returns an iterator over all read variable identifiers in this expression.
/// Each occurrence of a variable identifier is returned separately.
pub fn iter_read_variable_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| match node.operator() {
Operator::VariableIdentifierRead { identifier } => Some(identifier.as_str()),
_ => None,
})
}
/// Returns an iterator over all read variable identifiers in this expression, allowing mutation.
/// Each occurrence of a variable identifier is returned separately.
pub fn iter_read_variable_identifiers_mut(&mut self) -> impl Iterator<Item = &mut String> {
self.iter_operators_mut()
.filter_map(|operator| match operator {
Operator::VariableIdentifierRead { identifier } => Some(identifier),
_ => None,
})
}
/// Returns an iterator over all write variable identifiers in this expression.
/// Each occurrence of a variable identifier is returned separately.
pub fn iter_write_variable_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| match node.operator() {
Operator::VariableIdentifierWrite { identifier } => Some(identifier.as_str()),
_ => None,
})
}
/// Returns an iterator over all write variable identifiers in this expression, allowing mutation.
/// Each occurrence of a variable identifier is returned separately.
pub fn iter_write_variable_identifiers_mut(&mut self) -> impl Iterator<Item = &mut String> {
self.iter_operators_mut()
.filter_map(|operator| match operator {
Operator::VariableIdentifierWrite { identifier } => Some(identifier),
_ => None,
})
}
/// Returns an iterator over all function identifiers in this expression.
/// Each occurrence of a function identifier is returned separately.
pub fn iter_function_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| match node.operator() {
Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()),
_ => None,
})
}
/// Returns an iterator over all function identifiers in this expression, allowing mutation.
/// Each occurrence of a variable identifier is returned separately.
pub fn iter_function_identifiers_mut(&mut self) -> impl Iterator<Item = &mut String> {
self.iter_operators_mut()
.filter_map(|operator| match operator {
Operator::FunctionIdentifier { identifier } => Some(identifier),
_ => None,
})
}
/// Evaluates the operator tree rooted at this node with the given context. Fails if one of the
/// operators in the expression tree fails.
pub fn eval_with_context(&self, context: &VariableMap) -> Result<Value> {
let mut arguments = Vec::new();
for child in self.children() {
arguments.push(child.eval_with_context(context)?);
}
self.operator().eval(&arguments, context)
}
/// Evaluates the operator tree rooted at this node with the given mutable context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_with_context_mut(&self, context: &mut VariableMap) -> Result<Value> {
let mut arguments = Vec::new();
for child in self.children() {
arguments.push(child.eval_with_context_mut(context)?);
}
self.operator().eval_mut(&arguments, context)
}
/// Evaluates the operator tree rooted at this node.
/// Fails if one of the operators in the expression tree fails.
pub fn eval(&self) -> Result<Value> {
self.eval_with_context_mut(&mut VariableMap::new())
}
/// Evaluates the operator tree rooted at this node into a string with an the given context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_string_with_context(&self, context: &VariableMap) -> Result<String> {
match self.eval_with_context(context) {
Ok(Value::String(string)) => Ok(string),
Ok(value) => Err(Error::expected_string(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a float with an the given context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_float_with_context(&self, context: &VariableMap) -> Result<f64> {
match self.eval_with_context(context) {
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(Error::expected_float(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into an integer with an the given context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_int_with_context(&self, context: &VariableMap) -> Result<i64> {
match self.eval_with_context(context) {
Ok(Value::Integer(int)) => Ok(int),
Ok(value) => Err(Error::expected_int(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a float with an the given context. If
/// the result of the expression is an integer, it is silently converted into a float. Fails /// if one of the operators in the expression tree fails.
pub fn eval_number_with_context(&self, context: &VariableMap) -> Result<f64> {
match self.eval_with_context(context) {
Ok(Value::Integer(int)) => Ok(int as f64),
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(Error::expected_number(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a boolean with an the given context
/// Fails if one of the operators in the expression tree fails.
pub fn eval_boolean_with_context(&self, context: &VariableMap) -> Result<bool> {
match self.eval_with_context(context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
Ok(value) => Err(Error::expected_boolean(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a tuple with an the given context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_tuple_with_context(&self, context: &VariableMap) -> Result<Vec<Value>> {
match self.eval_with_context(context) {
Ok(Value::List(tuple)) => Ok(tuple),
Ok(value) => Err(Error::expected_list(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into an empty value with an the given context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_empty_with_context(&self, context: &VariableMap) -> Result<()> {
match self.eval_with_context(context) {
Ok(Value::Empty) => Ok(()),
Ok(value) => Err(Error::expected_empty(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a string with an the given mutable context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_string_with_context_mut(&self, context: &mut VariableMap) -> Result<String> {
match self.eval_with_context_mut(context) {
Ok(Value::String(string)) => Ok(string),
Ok(value) => Err(Error::expected_string(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a float with an the given mutable context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_float_with_context_mut(&self, context: &mut VariableMap) -> Result<f64> {
match self.eval_with_context_mut(context) {
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(Error::expected_float(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into an integer with an the given mutable context.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_int_with_context_mut(&self, context: &mut VariableMap) -> Result<i64> {
match self.eval_with_context_mut(context) {
Ok(Value::Integer(int)) => Ok(int),
Ok(value) => Err(Error::expected_int(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a float with an the given mutable context.
/// If the result of the expression is an integer, it is silently converted into a float.
/// Fails if one of the operators in the expression tree fails.
pub fn eval_number_with_context_mut(&self, context: &mut VariableMap) -> Result<f64> {
match self.eval_with_context_mut(context) {
Ok(Value::Integer(int)) => Ok(int as f64),
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(Error::expected_number(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a boolean with an the given mutable /// context. Fails if one of the operators in the expression tree fails.
pub fn eval_boolean_with_context_mut(&self, context: &mut VariableMap) -> Result<bool> {
match self.eval_with_context_mut(context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
Ok(value) => Err(Error::expected_boolean(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a tuple with an the given mutable /// context. Fails if one of the operators in the expression tree fails.
pub fn eval_tuple_with_context_mut(&self, context: &mut VariableMap) -> Result<Vec<Value>> {
match self.eval_with_context_mut(context) {
Ok(Value::List(tuple)) => Ok(tuple),
Ok(value) => Err(Error::expected_list(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into an empty value with an the given /// mutable context. Fails if one of the operators in the expression tree fails.
pub fn eval_empty_with_context_mut(&self, context: &mut VariableMap) -> Result<()> {
match self.eval_with_context_mut(context) {
Ok(Value::Empty) => Ok(()),
Ok(value) => Err(Error::expected_empty(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a string. Fails if one of the /// operators in the expression tree fails.
pub fn eval_string(&self) -> Result<String> {
self.eval_string_with_context_mut(&mut VariableMap::new())
}
/// Evaluates the operator tree rooted at this node into a float. Fails if one of the operators /// in the expression tree fails.
pub fn eval_float(&self) -> Result<f64> {
self.eval_float_with_context_mut(&mut VariableMap::new())
}
/// Evaluates the operator tree rooted at this node into an integer. Fails if one of the
/// operators in the expression tree fails.
pub fn eval_int(&self) -> Result<i64> {
self.eval_int_with_context_mut(&mut VariableMap::new())
}
/// Evaluates the operator tree rooted at this node into a float. If the result of the
/// expression is an integer, it is silently converted into a float. Fails if one of the /// operators in the expression tree fails.
pub fn eval_number(&self) -> Result<f64> {
self.eval_number_with_context_mut(&mut VariableMap::new())
}
/// Evaluates the operator tree rooted at this node into a boolean. Fails if one of the /// operators in the expression tree fails.
pub fn eval_boolean(&self) -> Result<bool> {
self.eval_boolean_with_context_mut(&mut VariableMap::new())
}
/// Evaluates the operator tree rooted at this node into a tuple. Fails if one of the operators /// in the expression tree fails.
pub fn eval_tuple(&self) -> Result<Vec<Value>> {
self.eval_tuple_with_context_mut(&mut VariableMap::new())
}
/// Evaluates the operator tree rooted at this node into an empty value. Fails if one of the /// operators in the expression tree fails.
pub fn eval_empty(&self) -> Result<()> {
self.eval_empty_with_context_mut(&mut VariableMap::new())
}
/// Returns the children of this node as a slice.
pub fn children(&self) -> &[Node] {
&self.children
}
/// Returns the operator associated with this node.
pub fn operator(&self) -> &Operator {
&self.operator
}
/// Returns a mutable reference to the vector containing the children of this node.
///
/// WARNING: Writing to this might have unexpected results, as some operators require certain amounts and types of arguments.
pub fn children_mut(&mut self) -> &mut Vec<Node> {
&mut self.children
}
/// Returns a mutable reference to the operator associated with this node.
///
/// WARNING: Writing to this might have unexpected results, as some operators require different amounts and types of arguments.
pub fn operator_mut(&mut self) -> &mut Operator {
&mut self.operator
}
fn has_enough_children(&self) -> bool {
Some(self.children().len()) == self.operator().max_argument_amount()
}
fn has_too_many_children(&self) -> bool {
if let Some(max_argument_amount) = self.operator().max_argument_amount() {
self.children().len() > max_argument_amount
} else {
false
}
}
fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> Result<()> {
// println!(
// "Inserting {:?} into {:?}, is_root_node = {is_root_node}",
// node.operator(),
// self.operator()
// );
// println!("Self is {:?}", self);
if self.operator().precedence() < node.operator().precedence() || node.operator().is_unary() || is_root_node
// Right-to-left chaining
|| (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right())
{
if self.operator().is_leaf() {
Err(Error::AppendedToLeafNode(node))
} else if self.has_enough_children() {
// Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child
let last_child_operator = self.children.last().unwrap().operator();
if last_child_operator.precedence()
< node.operator().precedence() || node.operator().is_unary()
// Right-to-left chaining
|| (last_child_operator.precedence()
== node.operator().precedence() && !last_child_operator.is_left_to_right() && !node.operator().is_left_to_right())
{
// println!(
// "Recursing into {:?}",
// self.children.last().unwrap().operator()
// );
// Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child
self.children
.last_mut()
.unwrap()
.insert_back_prioritized(node, false)
} else {
// println!("Rotating");
if node.operator().is_leaf() {
return Err(Error::AppendedToLeafNode(node));
}
// Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child
let last_child = self.children.pop().unwrap();
// Root nodes have at most one child
// TODO I am not sure if this is the correct error
if self.operator() == &Operator::RootNode && !self.children().is_empty() {
return Err(Error::MissingOperatorOutsideOfBrace);
}
// Do not insert root nodes into root nodes.
// TODO I am not sure if this is the correct error
if self.operator() == &Operator::RootNode
&& node.operator() == &Operator::RootNode
{
return Err(Error::MissingOperatorOutsideOfBrace);
}
self.children.push(node);
let node = self.children.last_mut().unwrap();
// Root nodes have at most one child
// TODO I am not sure if this is the correct error
if node.operator() == &Operator::RootNode && !node.children().is_empty() {
return Err(Error::MissingOperatorOutsideOfBrace);
}
// Do not insert root nodes into root nodes.
// TODO I am not sure if this is the correct error
if node.operator() == &Operator::RootNode
&& last_child.operator() == &Operator::RootNode
{
return Err(Error::MissingOperatorOutsideOfBrace);
}
node.children.push(last_child);
Ok(())
}
} else {
// println!("Inserting as specified");
self.children.push(node);
Ok(())
}
} else {
Err(Error::PrecedenceViolation)
}
}
}
impl Display for Node {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.operator.fmt(f)?;
for child in self.children() {
write!(f, " {}", child)?;
}
Ok(())
}
}
fn collapse_root_stack_to(
root_stack: &mut Vec<Node>,
mut root: Node,
collapse_goal: &Node,
) -> Result<Node> {
loop {
if let Some(mut potential_higher_root) = root_stack.pop() {
// TODO I'm not sure about this >, as I have no example for different sequence operators with the same precedence
if potential_higher_root.operator().precedence() > collapse_goal.operator().precedence()
{
potential_higher_root.children.push(root);
root = potential_higher_root;
} else {
root_stack.push(potential_higher_root);
break;
}
} else {
// This is the only way the topmost root node could have been removed
return Err(Error::UnmatchedRBrace);
}
}
Ok(root)
}
fn collapse_all_sequences(root_stack: &mut Vec<Node>) -> Result<()> {
// println!("Collapsing all sequences");
// println!("Initial root stack is: {:?}", root_stack);
let mut root = if let Some(root) = root_stack.pop() {
root
} else {
return Err(Error::UnmatchedRBrace);
};
loop {
// println!("Root is: {:?}", root);
if root.operator() == &Operator::RootNode {
// This should fire if parsing something like `4(5)`
if root.has_too_many_children() {
return Err(Error::MissingOperatorOutsideOfBrace);
}
root_stack.push(root);
break;
}
if let Some(mut potential_higher_root) = root_stack.pop() {
if root.operator().is_sequence() {
potential_higher_root.children.push(root);
root = potential_higher_root;
} else {
// This should fire if parsing something like `4(5)`
if root.has_too_many_children() {
return Err(Error::MissingOperatorOutsideOfBrace);
}
root_stack.push(potential_higher_root);
root_stack.push(root);
break;
}
} else {
// This is the only way the topmost root node could have been removed
return Err(Error::UnmatchedRBrace);
}
}
// println!("Root stack after collapsing all sequences is: {:?}", root_stack);
Ok(())
}
pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> Result<Node> {
let mut root_stack = vec![Node::root_node()];
let mut last_token_is_rightsided_value = false;
let mut token_iter = tokens.iter().peekable();
while let Some(token) = token_iter.next().cloned() {
let next = token_iter.peek().cloned();
let node = match token.clone() {
Token::Plus => Some(Node::new(Operator::Add)),
Token::Minus => {
if last_token_is_rightsided_value {
Some(Node::new(Operator::Sub))
} else {
Some(Node::new(Operator::Neg))
}
}
Token::Star => Some(Node::new(Operator::Mul)),
Token::Slash => Some(Node::new(Operator::Div)),
Token::Percent => Some(Node::new(Operator::Mod)),
Token::Hat => Some(Node::new(Operator::Exp)),
Token::Eq => Some(Node::new(Operator::Eq)),
Token::Neq => Some(Node::new(Operator::Neq)),
Token::Gt => Some(Node::new(Operator::Gt)),
Token::Lt => Some(Node::new(Operator::Lt)),
Token::Geq => Some(Node::new(Operator::Geq)),
Token::Leq => Some(Node::new(Operator::Leq)),
Token::And => Some(Node::new(Operator::And)),
Token::Or => Some(Node::new(Operator::Or)),
Token::Not => Some(Node::new(Operator::Not)),
Token::LBrace => {
root_stack.push(Node::root_node());
None
}
Token::RBrace => {
if root_stack.len() <= 1 {
return Err(Error::UnmatchedRBrace);
} else {
collapse_all_sequences(&mut root_stack)?;
root_stack.pop()
}
}
Token::Assign => Some(Node::new(Operator::Assign)),
Token::PlusAssign => Some(Node::new(Operator::AddAssign)),
Token::MinusAssign => Some(Node::new(Operator::SubAssign)),
Token::StarAssign => Some(Node::new(Operator::MulAssign)),
Token::SlashAssign => Some(Node::new(Operator::DivAssign)),
Token::PercentAssign => Some(Node::new(Operator::ModAssign)),
Token::HatAssign => Some(Node::new(Operator::ExpAssign)),
Token::AndAssign => Some(Node::new(Operator::AndAssign)),
Token::OrAssign => Some(Node::new(Operator::OrAssign)),
Token::Comma => Some(Node::new(Operator::Tuple)),
Token::Semicolon => Some(Node::new(Operator::Chain)),
Token::Identifier(identifier) => {
let mut result = Some(Node::new(Operator::variable_identifier_read(
identifier.clone(),
)));
if let Some(next) = next {
if next.is_assignment() {
result = Some(Node::new(Operator::variable_identifier_write(
identifier.clone(),
)));
} else if next.is_leftsided_value() {
result = Some(Node::new(Operator::function_identifier(identifier)));
}
}
result
}
Token::Float(float) => Some(Node::new(Operator::value(Value::Float(float)))),
Token::Int(int) => Some(Node::new(Operator::value(Value::Integer(int)))),
Token::Boolean(boolean) => Some(Node::new(Operator::value(Value::Boolean(boolean)))),
Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))),
Token::Function(string) => Some(Node::new(Operator::value(Value::Function(
Function::new(&string),
)))),
Token::Yield(_, _) => todo!(),
};
if let Some(mut node) = node {
// Need to pop and then repush here, because Rust 1.33.0 cannot release the mutable borrow of root_stack before the end of this complete if-statement
if let Some(mut root) = root_stack.pop() {
if node.operator().is_sequence() {
// println!("Found a sequence operator");
// println!("Stack before sequence operation: {:?}, {:?}", root_stack, root);
// If root.operator() and node.operator() are of the same variant, ...
if mem::discriminant(root.operator()) == mem::discriminant(node.operator()) {
// ... we create a new root node for the next expression in the sequence
root.children.push(Node::root_node());
root_stack.push(root);
} else if root.operator() == &Operator::RootNode {
// If the current root is an actual root node, we start a new sequence
node.children.push(root);
node.children.push(Node::root_node());
root_stack.push(Node::root_node());
root_stack.push(node);
} else {
// Otherwise, we combine the sequences based on their precedences
// TODO I'm not sure about this <, as I have no example for different sequence operators with the same precedence
if root.operator().precedence() < node.operator().precedence() {
// If the new sequence has a higher precedence, it is part of the last element of the current root sequence
if let Some(last_root_child) = root.children.pop() {
node.children.push(last_root_child);
node.children.push(Node::root_node());
root_stack.push(root);
root_stack.push(node);
} else {
// Once a sequence has been pushed on top of the stack, it also gets a child
unreachable!()
}
} else {
// If the new sequence doesn't have a higher precedence, then all sequences with a higher precedence are collapsed below this one
root = collapse_root_stack_to(&mut root_stack, root, &node)?;
node.children.push(root);
root_stack.push(node);
}
}
// println!("Stack after sequence operation: {:?}", root_stack);
} else if root.operator().is_sequence() {
if let Some(mut last_root_child) = root.children.pop() {
last_root_child.insert_back_prioritized(node, true)?;
root.children.push(last_root_child);
root_stack.push(root);
} else {
// Once a sequence has been pushed on top of the stack, it also gets a child
unreachable!()
}
} else {
root.insert_back_prioritized(node, true)?;
root_stack.push(root);
}
} else {
return Err(Error::UnmatchedRBrace);
}
}
last_token_is_rightsided_value = token.is_rightsided_value();
}
// In the end, all sequences are implicitly terminated
collapse_all_sequences(&mut root_stack)?;
if root_stack.len() > 1 {
Err(Error::UnmatchedLBrace)
} else if let Some(root) = root_stack.pop() {
Ok(root)
} else {
Err(Error::UnmatchedRBrace)
}
}

View File

@ -13,11 +13,11 @@ impl Function {
}
pub fn run(&self) -> Result<Value> {
eval(&self.0)
todo!()
}
pub fn run_with_context(&self, context: &mut VariableMap) -> Result<Value> {
eval_with_context(&self.0, context)
todo!()
}
}

View File

@ -10,7 +10,7 @@ use serde::{
ser::SerializeTuple,
Deserialize, Serialize, Serializer,
};
use tree_sitter::{Node, TreeCursor};
use tree_sitter::Node;
use std::{
cmp::Ordering,
@ -66,7 +66,12 @@ impl Value {
Ok(Value::Integer(raw))
}
"string" => Ok(Value::String(value_snippet.to_string())),
"string" => {
let without_quotes = &value_snippet[1..value_snippet.len() - 1];
Ok(Value::String(without_quotes.to_string()))
}
"empty" => Ok(Value::Empty),
_ => Err(Error::UnexpectedSourceNode {
expected: "raw value",
actual: child.kind(),