mod define;
mod error;
mod parser;
#[macro_use]
mod function;
mod keyword;
mod operator;
mod token;
mod tokenizer;
#[macro_use]
mod value;
mod context;
mod descriptor;
mod init;
use std::sync::Arc;
pub fn execute(expr: &str, mut ctx: context::Context) -> Result<Value> {
parse_expression(expr)?.exec(&mut ctx)
}
pub fn parse_expression(expr: &str) -> Result<ExprAST> {
init();
parser::Parser::new(expr)?.parse_stmt()
}
pub fn register_function(name: &str, handler: Arc<function::InnerFunction>) {
use crate::function::InnerFunctionManager;
init();
InnerFunctionManager::new().register(name, handler);
}
pub fn register_prefix_op(op: &str, handler: Arc<operator::PrefixOpFunc>) {
use crate::operator::PrefixOpManager;
init();
PrefixOpManager::new().register(op, handler);
}
pub fn register_postfix_op(op: &str, handler: Arc<operator::PostfixOpFunc>) {
use crate::operator::PostfixOpManager;
init();
PostfixOpManager::new().register(op, handler);
}
pub fn register_infix_op(
op: &str,
precedence: i32,
op_type: InfixOpType,
associativity: InfixOpAssociativity,
handler: Arc<operator::InfixOpFunc>,
) {
use crate::operator::InfixOpManager;
init();
InfixOpManager::new().register(op, precedence, op_type, associativity, handler);
}
fn init() {
use crate::init::init;
init();
}
pub type Value = value::Value;
pub type Context = context::Context;
pub type Result<T> = define::Result<T>;
pub type ExprAST<'a> = parser::ExprAST<'a>;
pub type InfixOpType = operator::InfixOpType;
pub type InfixOpAssociativity = operator::InfixOpAssociativity;
#[cfg(test)]
mod tests {
use crate::{
create_context, execute, parse_expression, register_function, register_infix_op,
register_postfix_op, register_prefix_op, InfixOpAssociativity, InfixOpType, Value,
};
use std::sync::Arc;
#[test]
fn test_execute() {
let input = "c = 5+3; c+=10+f; c";
let ctx = create_context!(
"d" => 2,
"b" => true,
"f" => Arc::new(|_| Ok(Value::from(3)))
);
let ans = execute(input, ctx).unwrap();
assert_eq!(ans, 21.into())
}
#[test]
fn test_parse_expression() {
let input = "a + 3*2+test()+[1,2,3,'haha']";
assert!(parse_expression(input).is_ok());
}
#[test]
fn test_register_function() {
register_function("test", Arc::new(|_| return Ok(Value::from("test"))));
let input = "test()";
let ans = execute(input, create_context!());
assert!(ans.is_ok());
assert_eq!(ans.unwrap(), Value::from("test"));
}
#[test]
fn test_register_prefix_op() {
register_prefix_op(
"+++",
Arc::new(|v| {
let mut tmp = v.integer()?;
tmp += 3;
Ok(Value::from(tmp))
}),
);
let input = "+++11";
let ans = execute(input, create_context!());
assert!(ans.is_ok());
assert_eq!(ans.unwrap(), Value::from(14));
}
#[test]
fn test_register_postfix_op() {
register_postfix_op(
"---",
Arc::new(|v| {
let mut tmp = v.integer()?;
tmp -= 3;
Ok(Value::from(tmp))
}),
);
let input = "100---";
let ans = execute(input, create_context!());
assert!(ans.is_ok());
assert_eq!(ans.unwrap(), Value::from(97));
}
#[test]
fn test_register_infix_op() {
register_infix_op(
"---",
100,
InfixOpType::CALC,
InfixOpAssociativity::RIGHT,
Arc::new(|left, right| Ok(Value::from(left.integer()? - right.integer()?))),
);
let input = "100---55---44";
let ans = execute(input, create_context!());
assert!(ans.is_ok());
assert_eq!(ans.unwrap(), Value::from(89));
}
}