hamelin_translation 0.3.10

Lowering and IR for Hamelin query language
Documentation
//! Lowering entry point for converting TypedStatement to IR.
//!
//! This module provides the public API for lowering Hamelin's type-checked AST
//! to the intermediate representation (IR).

use std::rc::Rc;
use std::sync::Arc;

use hamelin_lib::err::TranslationErrors;
use hamelin_lib::func::registry::FunctionRegistry;
use hamelin_lib::provider::{EnvironmentProvider, NoOpProvider};
use hamelin_lib::tree::ast::identifier::{CompoundIdentifier, Identifier, SimpleIdentifier};
use hamelin_lib::tree::typed_ast::context::StatementTranslationContext;
use hamelin_lib::tree::typed_ast::query::TypedStatement;

use crate::ir::IRStatement;
use crate::normalize::normalize_statement;

/// Lower a TypedStatement to IR with default options.
///
/// This is the simplest entry point for lowering. For custom configuration,
/// use [`lower_with()`] instead.
pub fn lower(statement: Rc<TypedStatement>) -> Result<IRStatement, TranslationErrors> {
    LoweringOptions::default().lower(statement)
}

/// Create a LoweringOptions builder for custom configuration.
///
/// # Example
///
/// ```
/// use std::sync::Arc;
/// use hamelin_lib::func::registry::FunctionRegistry;
/// use hamelin_translation::lower_with;
///
/// let options = lower_with()
///     .with_registry(Arc::new(FunctionRegistry::default()))
///     .with_timestamp_field("ts");
///
/// // options.lower(typed_statement) would convert to IR
/// ```
pub fn lower_with() -> LoweringOptions {
    LoweringOptions::default()
}

/// Options for lowering a TypedStatement to IR.
///
/// Configure the lowering process with custom providers, registries, and field names.
/// Use [`lower_with()`] to create an instance with defaults.
#[derive(Clone)]
pub struct LoweringOptions {
    registry: Arc<FunctionRegistry>,
    provider: Arc<dyn EnvironmentProvider>,
    timestamp_field: Identifier,
    message_field: Identifier,
}

impl Default for LoweringOptions {
    fn default() -> Self {
        Self {
            registry: Arc::new(FunctionRegistry::default()),
            provider: Arc::new(NoOpProvider::default()),
            timestamp_field: SimpleIdentifier::new("timestamp").into(),
            message_field: CompoundIdentifier::new(
                SimpleIdentifier::new("event"),
                SimpleIdentifier::new("original"),
                vec![],
            )
            .into(),
        }
    }
}

impl LoweringOptions {
    /// Set a custom function registry.
    pub fn with_registry(mut self, registry: Arc<FunctionRegistry>) -> Self {
        self.registry = registry;
        self
    }

    /// Set a custom environment provider for table schema lookups.
    pub fn with_provider(mut self, provider: Arc<dyn EnvironmentProvider>) -> Self {
        self.provider = provider;
        self
    }

    /// Set the timestamp field used by WITHIN normalization.
    ///
    /// Defaults to "timestamp".
    pub fn with_timestamp_field(mut self, field: impl Into<Identifier>) -> Self {
        self.timestamp_field = field.into();
        self
    }

    /// Set the message field used by PARSE when no source is specified.
    ///
    /// Defaults to "event.original".
    pub fn with_message_field(mut self, field: impl Into<Identifier>) -> Self {
        self.message_field = field.into();
        self
    }

    /// Lower a TypedStatement to IR.
    ///
    /// Runs all normalization passes and converts to IR.
    /// Returns the first error encountered, if any.
    pub fn lower(self, statement: Rc<TypedStatement>) -> Result<IRStatement, TranslationErrors> {
        // Build StatementTranslationContext from options
        let mut ctx = StatementTranslationContext::new(self.registry, self.provider)
            .with_timestamp_field(self.timestamp_field)
            .with_message_field(self.message_field);

        // Run normalization passes
        let normalized =
            normalize_statement(statement, &mut ctx).map_err(|e| (*e).clone().single())?;

        // Convert normalized TypedStatement to IRStatement
        IRStatement::from_typed(normalized, &mut ctx).map_err(|e| (*e).clone().single())
    }
}