Initial commit
This commit is contained in:
201
src/compilation/mod.rs
Normal file
201
src/compilation/mod.rs
Normal file
@@ -0,0 +1,201 @@
|
||||
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<T> = Result<T, CompileError>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FullType {
|
||||
Basic(Type),
|
||||
Array(Box<FullType>),
|
||||
Object(Arc<dyn ObjectTypeDefinition>),
|
||||
EnumConstant(Vec<String>),
|
||||
}
|
||||
|
||||
impl FullType {
|
||||
pub fn from_simple(t: Type) -> CompileResult<Self> {
|
||||
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<Arc<dyn ObjectTypeDefinition>> {
|
||||
match self {
|
||||
FullType::Object(t) => Some(t.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_element_type(&self) -> Option<FullType> {
|
||||
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<FullType>;
|
||||
|
||||
fn get_method_headers(&self, name: &str) -> Option<Vec<&MethodHeader>>;
|
||||
|
||||
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<FullType> {
|
||||
None
|
||||
}
|
||||
|
||||
fn get_method_headers(&self, _name: &str) -> Option<Vec<&MethodHeader>> {
|
||||
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<TypedFormula>) -> CompileResult<TypedFormula>;
|
||||
}
|
||||
|
||||
pub trait InstanceMethod {
|
||||
fn get_header(&self) -> &MethodHeader;
|
||||
fn call(&self, instance: TypedFormula, args: Vec<TypedFormula>) -> CompileResult<TypedFormula>;
|
||||
}
|
||||
|
||||
pub struct MethodHeader {
|
||||
pub method_id: String,
|
||||
pub return_type: FullType,
|
||||
pub argument_types: Vec<FullType>,
|
||||
}
|
||||
|
||||
impl MethodHeader {
|
||||
pub fn new(method_id: String, return_type: Type, argument_types: Vec<Type>) -> 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;
|
||||
Reference in New Issue
Block a user