hlx 1.2.5

Configuration language designed specifically for ml/ai/data systems
Documentation
use crate::dna::atp::lexer::{tokenize_with_locations, SourceMap};
use crate::dna::atp::parser::{Parser, ParseError};
use crate::dna::atp::ast::HelixAst;
use crate::dna::atp::value::Value;
use crate::dna::atp::interpreter::HelixInterpreter;
use crate::hel::error::HlxError;
#[derive(Debug)]
pub enum DispatchResult {
    Parsed(HelixAst),
    Executed(Value),
    #[cfg(feature = "js")]
    ParseError(napi::Error<ParseError>),
    #[cfg(not(feature = "js"))]
    ParseError(ParseError),
    ExecutionError(HlxError),
}
pub struct HelixDispatcher {
    interpreter: Option<HelixInterpreter>,
}
impl HelixDispatcher {
    pub fn new() -> Self {
        Self { interpreter: None }
    }
    pub async fn initialize(&mut self) -> Result<(), HlxError> {
        self.interpreter = Some(HelixInterpreter::new().await?);
        Ok(())
    }
    #[cfg(feature = "js")]
    pub fn parse_only(&self, source: &str) -> Result<HelixAst, napi::Error<ParseError>> {
        crate::parse(source).map_err(|e| e.into())
    }
    #[cfg(not(feature = "js"))]
    pub fn parse_only(&self, source: &str) -> Result<HelixAst, ParseError> {
        crate::parse(source)
    }
    pub async fn parse_and_execute(
        &mut self,
        source: &str,
    ) -> Result<DispatchResult, HlxError> {
        if self.interpreter.is_none() {
            self.initialize().await?;
        }
        let ast = match crate::parse(source) {
            Ok(ast) => ast,
            Err(parse_err) => return Ok(DispatchResult::ParseError(parse_err)),
        };
        if let Some(ref mut interpreter) = self.interpreter {
            match interpreter.execute_ast(&ast).await {
                Ok(value) => Ok(DispatchResult::Executed(value.into())),
                Err(exec_err) => Ok(DispatchResult::ExecutionError(exec_err)),
            }
        } else {
            Err(
                HlxError::execution_error(
                    "Interpreter not initialized",
                    "Call initialize() before executing code",
                ),
            )
        }
    }
    pub async fn parse_dsl(&mut self, source: &str) -> Result<DispatchResult, HlxError> {
        let tokens_with_loc = tokenize_with_locations(source)
            .map_err(|e| {
                HlxError::invalid_input(
                    format!("Lexer error: {}", e),
                    "Check syntax and try again",
                )
            })?;
        let source_map = SourceMap {
            tokens: tokens_with_loc.clone(),
            source: source.to_string(),
        };
        let mut parser = Parser::new_with_source_map(source_map);
        match parser.parse() {
            Ok(ast) => Ok(DispatchResult::Parsed(ast)),
            Err(parse_err) => {
                let parse_error = ParseError {
                    message: parse_err,
                    location: None,
                    token_index: 0,
                    expected: None,
                    found: String::new(),
                    context: String::new(),
                };
                Ok(DispatchResult::ParseError(parse_error.into()))
            }
        }
    }
    pub fn interpreter(&self) -> Option<&HelixInterpreter> {
        self.interpreter.as_ref()
    }
    pub fn interpreter_mut(&mut self) -> Option<&mut HelixInterpreter> {
        self.interpreter.as_mut()
    }
    pub fn is_ready(&self) -> bool {
        self.interpreter.is_some()
    }
}
#[cfg(feature = "js")]
pub fn parse_helix(source: &str) -> Result<HelixAst, napi::Error<ParseError>> {
    crate::parse(source).map_err(|e| e.into())
}
#[cfg(not(feature = "js"))]
pub fn parse_helix(source: &str) -> Result<HelixAst, ParseError> {
    crate::parse(source)
}
#[cfg(feature = "js")]
pub fn parse_and_validate(
    source: &str,
) -> Result<crate::atp::types::HelixConfig, napi::Error<String>> {
    crate::parse_and_validate(source).map_err(|e| e.into())
}
#[cfg(not(feature = "js"))]
pub fn parse_and_validate(source: &str) -> Result<crate::atp::types::HelixConfig, String> {
    crate::parse_and_validate(source)
}
pub async fn execute_helix(source: &str) -> Result<Value, HlxError> {
    let mut dispatcher = HelixDispatcher::new();
    dispatcher.initialize().await?;
    match dispatcher.parse_and_execute(source).await? {
        DispatchResult::Executed(value) => Ok(value),
        DispatchResult::ParseError(err) => {
            Err(
                HlxError::invalid_input(
                    format!("Parse error: {}", err),
                    "Check syntax and try again",
                ),
            )
        }
        DispatchResult::ExecutionError(err) => Err(err),
        DispatchResult::Parsed(_) => {
            Err(
                HlxError::execution_error(
                    "Parsed AST but no execution result",
                    "Use parse_helix for parsing only",
                ),
            )
        }
    }
}
#[cfg(feature = "js")]
pub async fn parse_helix_dsl(source: &str) -> Result<HelixAst, napi::Error<ParseError>> {
    let mut dispatcher = HelixDispatcher::new();
    match dispatcher.parse_dsl(source).await {
        Ok(DispatchResult::Parsed(ast)) => Ok(ast),
        Ok(DispatchResult::ParseError(err)) => Err(err),
        _ => {
            let parse_error = ParseError {
                message: "Unexpected dispatch result".to_string(),
                location: None,
                token_index: 0,
                expected: None,
                found: String::new(),
                context: String::new(),
            };
            Err(parse_error.into())
        }
    }
}
#[cfg(not(feature = "js"))]
pub async fn parse_helix_dsl(source: &str) -> Result<HelixAst, ParseError> {
    let mut dispatcher = HelixDispatcher::new();
    match dispatcher.parse_dsl(source).await {
        Ok(DispatchResult::Parsed(ast)) => Ok(ast),
        Ok(DispatchResult::ParseError(err)) => Err(err),
        _ => {
            let parse_error = ParseError {
                message: "Unexpected dispatch result".to_string(),
                location: None,
                token_index: 0,
                expected: None,
                found: String::new(),
                context: String::new(),
            };
            Err(parse_error)
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[tokio::test]
    async fn test_parse_only() {
        let source = r#"
        agent "test_agent" {
            capabilities ["coding", "analysis"]
            backstory {
                "A helpful AI assistant"
            }
        }
        "#;
        let dispatcher = HelixDispatcher::new();
        let result = dispatcher.parse_only(source);
        if let Err(ref e) = result {
            println!("Parse error: {:?}", e);
        }
        assert!(result.is_ok());
    }
    #[tokio::test]
    async fn test_parse_and_execute() {
        let source = r#"
        @date("Y-m-d")
        "#;
        let mut dispatcher = HelixDispatcher::new();
        let result = dispatcher.parse_and_execute(source).await;
        assert!(result.is_ok());
        if let Ok(DispatchResult::Executed(value)) = result {
            match value {
                Value::String(date_str) => assert!(! date_str.is_empty()),
                _ => panic!("Expected string value"),
            }
        }
    }
    #[tokio::test]
    async fn test_execute_expression() {
        let source = "@date(\"Y-m-d\")";
        let mut dispatcher = HelixDispatcher::new();
        dispatcher.initialize().await.unwrap();
        let result = dispatcher.parse_and_execute(source).await;
        assert!(result.is_ok());
        if let Ok(DispatchResult::Executed(value)) = result {
            match value {
                Value::String(date_str) => assert!(! date_str.is_empty()),
                _ => panic!("Expected string value"),
            }
        }
    }
}