use std::sync::Arc; use bigdecimal::{num_bigint::BigInt, BigDecimal, ParseBigDecimalError}; use crate::{bool_formula::Comparator, types::Type}; use self::{ parser::{BinaryOp, UnaryOp}, typed_formula::TypedFormula, }; mod compiler; mod lexer; mod parser; mod typed_formula; #[derive(Debug)] pub enum CompileError { UnexpectedToken { expected: String, found: String, }, UnexpectedUnparsedToken { found: String, }, UnexpectedEndOfInput, CannotParseDecimal(ParseBigDecimalError), IntegerMustBeIntegral(BigDecimal), IntegerTooLarge(BigInt), CannotCompileNumberAsType(BigDecimal, Type), CannotUseStringAsType(String, Type), WrongNumberOfArguments { expected: usize, found: usize, }, InvalidArgumentType { expected: Type, found: Type, }, InvalidLocalType { name: String, expected: Type, found: Type, }, VariableNotFound(String), ConditionMustBeBool, ConditionalBranchesMustHaveSameType(Type, Type), InvalidUnaryOperand(UnaryOp, Type), InvalidBinaryOperand(BinaryOp, Type, Type), InvalidComparator(Comparator, Type, Type), IndexMustBeInteger, ValueNotAnArray, InvalidMethodTarget, NotAnObject, MethodNotFound { name: String, }, NoMatchingMethod { name: String, args: usize, }, AmbiguousMethodCall { name: String, args: usize, }, NotABasicType { found: Type, }, } pub type CompileResult = Result; #[derive(Clone)] pub enum FullType { Basic(Type), Array(Box), Object(Arc), EnumConstant(Vec), } impl FullType { pub fn from_simple(t: Type) -> CompileResult { match t { Type::Bool | Type::Int | Type::Decimal | Type::String | Type::Date | Type::DateTime => { Ok(FullType::Basic(t)) } Type::BoolArray | Type::IntArray | Type::DecimalArray | Type::StringArray | Type::DateArray | Type::DateTimeArray => Ok(FullType::Array(Box::new(FullType::Basic( t.array().unwrap(), )))), other => Err(CompileError::NotABasicType { found: other }), } } pub fn matches(&self, other: &Type) -> bool { match self { FullType::Basic(t1) => t1 == other, FullType::Array(t1) => t1.simplified().array() == Some(other.clone()), FullType::Object(_) => other == &Type::Object, FullType::EnumConstant(_) => false, } } pub fn simplified(&self) -> Type { match self { FullType::Basic(t) => t.clone(), FullType::Array(t) => t.simplified().array().unwrap_or(Type::ObjectArray), FullType::Object(_) => Type::Object, FullType::EnumConstant(_) => Type::String, } } pub fn object(&self) -> Option> { match self { FullType::Object(t) => Some(t.clone()), _ => None, } } pub fn array_element_type(&self) -> Option { match self { FullType::Basic(t) => match &t { Type::BoolArray => Some(FullType::Basic(Type::Bool)), Type::IntArray => Some(FullType::Basic(Type::Int)), Type::DecimalArray => Some(FullType::Basic(Type::Decimal)), Type::StringArray => Some(FullType::Basic(Type::String)), Type::DateArray => Some(FullType::Basic(Type::Date)), Type::DateTimeArray => Some(FullType::Basic(Type::DateTime)), Type::ObjectArray => Some(FullType::Basic(Type::Object)), _ => None, }, FullType::Array(t) => Some(*t.clone()), _ => None, } } } pub trait ObjectTypeDefinition { fn get_field_type(&self, name: &str) -> Option; fn get_method_headers(&self, name: &str) -> Option>; fn get_static_method(&self, id: &str) -> Option<&dyn StaticMethod>; fn get_instance_method(&self, id: &str) -> Option<&dyn InstanceMethod>; } pub struct EmptyRoot; impl ObjectTypeDefinition for EmptyRoot { fn get_field_type(&self, _name: &str) -> Option { None } fn get_method_headers(&self, _name: &str) -> Option> { None } fn get_static_method(&self, _id: &str) -> Option<&dyn StaticMethod> { None } fn get_instance_method(&self, _id: &str) -> Option<&dyn InstanceMethod> { None } } pub trait StaticMethod { fn get_header(&self) -> &MethodHeader; fn call(&self, args: Vec) -> CompileResult; } pub trait InstanceMethod { fn get_header(&self) -> &MethodHeader; fn call(&self, instance: TypedFormula, args: Vec) -> CompileResult; } pub struct MethodHeader { pub method_id: String, pub return_type: FullType, pub argument_types: Vec, } impl MethodHeader { pub fn new(method_id: String, return_type: Type, argument_types: Vec) -> Self { Self { method_id, return_type: FullType::Basic(return_type), argument_types: argument_types.into_iter().map(FullType::Basic).collect(), } } } pub use compiler::{compile_formula, compile_formula_as}; #[cfg(test)] mod tests;