pub mod ast;
pub mod compiler;
pub mod functions;
pub mod optimizer;
pub mod parser;
pub mod variables;
#[cfg(feature = "dsl")]
pub mod macro_support;
use crate::error::Result;
use oxigdal_core::buffer::RasterBuffer;
pub use ast::{BinaryOp, Expr, Program, Statement, Type, UnaryOp};
pub use compiler::CompiledProgram;
pub use functions::FunctionRegistry;
pub use optimizer::{OptLevel, Optimizer};
pub use parser::{parse_expression, parse_program};
pub use variables::{BandContext, Environment, Value};
pub struct RasterDsl {
optimizer: Optimizer,
func_registry: FunctionRegistry,
}
impl Default for RasterDsl {
fn default() -> Self {
Self::new()
}
}
impl RasterDsl {
pub fn new() -> Self {
Self {
optimizer: Optimizer::new(OptLevel::Standard),
func_registry: FunctionRegistry::new(),
}
}
pub fn set_opt_level(&mut self, level: OptLevel) {
self.optimizer = Optimizer::new(level);
}
pub fn opt_level(&self) -> OptLevel {
OptLevel::Standard }
pub fn execute(&self, expression: &str, bands: &[RasterBuffer]) -> Result<RasterBuffer> {
if let Ok(expr) = parse_expression(expression) {
let optimized = self.optimizer.optimize_expr(expr);
let program = Program {
statements: vec![Statement::Expr(Box::new(optimized))],
};
let compiled = CompiledProgram::new(program);
return compiled.execute(bands);
}
let program = parse_program(expression)?;
let optimized = self.optimizer.optimize_program(program);
let compiled = CompiledProgram::new(optimized);
compiled.execute(bands)
}
pub fn compile(&self, expression: &str) -> Result<CompiledProgram> {
if let Ok(expr) = parse_expression(expression) {
let optimized = self.optimizer.optimize_expr(expr);
let program = Program {
statements: vec![Statement::Expr(Box::new(optimized))],
};
return Ok(CompiledProgram::new(program));
}
let program = parse_program(expression)?;
let optimized = self.optimizer.optimize_program(program);
Ok(CompiledProgram::new(optimized))
}
pub fn functions(&self) -> &FunctionRegistry {
&self.func_registry
}
pub fn list_functions(&self) -> Vec<&'static str> {
self.func_registry.function_names()
}
}
#[cfg(test)]
mod tests {
use super::*;
use oxigdal_core::types::RasterDataType;
#[test]
fn test_dsl_simple_expression() {
let band1 = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
let band2 = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
let dsl = RasterDsl::new();
let result = dsl.execute("B1 + B2", &[band1, band2]);
assert!(result.is_ok());
}
#[test]
fn test_dsl_ndvi() {
let nir = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
let red = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
let dsl = RasterDsl::new();
let result = dsl.execute("(B1 - B2) / (B1 + B2)", &[nir, red]);
assert!(result.is_ok());
}
#[test]
fn test_dsl_program() {
let bands = vec![
RasterBuffer::zeros(10, 10, RasterDataType::Float32),
RasterBuffer::zeros(10, 10, RasterDataType::Float32),
];
let program = r#"
let ndvi = (B1 - B2) / (B1 + B2);
ndvi;
"#;
let dsl = RasterDsl::new();
let result = dsl.execute(program, &bands);
assert!(result.is_ok());
}
#[test]
fn test_dsl_optimization() {
let band = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
let mut dsl = RasterDsl::new();
dsl.set_opt_level(OptLevel::Aggressive);
let result = dsl.execute("B1 + 0", &[band]);
assert!(result.is_ok());
}
#[test]
fn test_dsl_compile() {
let dsl = RasterDsl::new();
let compiled = dsl.compile("(B1 - B2) / (B1 + B2)");
assert!(compiled.is_ok());
}
#[test]
fn test_function_list() {
let dsl = RasterDsl::new();
let functions = dsl.list_functions();
assert!(!functions.is_empty());
assert!(functions.contains(&"sqrt"));
assert!(functions.contains(&"sin"));
}
}