jq_lang 0.2.0

Provides an AST for the jq query language
Documentation
pub mod parser_error;
pub mod node_type;
pub mod node;

use parser_error::ParserError;
use node_type::NodeType;
use node::Node;

struct ParserResult {
    pub node_type: NodeType,
    pub value: Option<String>
}

fn parse_input_str(input_str: &str) -> Result<ParserResult, ParserError> {
    if input_str.len() == 1 && input_str == "." {
        Ok(ParserResult {
            node_type: NodeType::Identity,
            value: None
        })
    }
    else if input_str.starts_with(".") && input_str.len() > 1 {
        Ok(ParserResult {
            node_type: NodeType::ObjectIdentifierIndex,
            value: Some(input_str.replace(".", ""))
        })
    }
    else {
        Err(ParserError::new("Invalid Syntax. Expected <filter>"))
    }
}

///
/// ## Convert a jq filter to AST
/// Example:
///
/// ```
/// use jq_lang::to_ast;
/// use jq_lang::node_type::NodeType;
///
/// let ast = to_ast(".").unwrap();
/// assert_eq!(ast.node_type, NodeType::Program);
///```
///
/// Providing an empty string will result in an error:
/// ```
/// use jq_lang::to_ast;
/// let parser_error = to_ast("");
/// assert_eq!(parser_error.is_err(), true);
/// ```
pub fn to_ast(filter: &str) -> Result<Node, ParserError> {
    if filter.len() == 0 {
        return Err(ParserError::new("Cannot parse empty string. Expected <filter>"))
    }

    let mut children = vec!();
    let parser_result = parse_input_str(filter)?;
    children.push(Node::new(parser_result.node_type, None, parser_result.value));

    Ok(Node::new(NodeType::Program, Some(children), None))
}

#[cfg(test)]
mod tests {
    use crate::to_ast;
    use crate::NodeType;

    #[test]
    fn identity_filter_produces_root_node() {
        let ast = to_ast(".").unwrap();
        assert_eq!(ast.node_type, NodeType::Program);
    }

    #[test]
    fn identity_filter_produces_identity_node() {
        let ast = to_ast(".").unwrap();
        let children = ast.children.unwrap();
        let child_node = children.get(0).unwrap();
        assert_eq!(child_node.node_type, NodeType::Identity);
    }

    #[test]
    fn identity_filter_produces_identity_node_has_no_value() {
        let ast = to_ast(".").unwrap();
        let children = ast.children.unwrap();
        let child_node = children.get(0).unwrap();
        assert_eq!(child_node.value, None);
    }

    #[test]
    fn handles_empty_string_produces_error() {
        let ast = to_ast("");
        assert_eq!(ast.is_err(), true);
    }

    #[test]
    fn handles_empty_string_error_has_error_message() {
        let ast = to_ast("");
        assert_eq!(ast.unwrap_err().message(), "Cannot parse empty string. Expected <filter>");
    }

    #[test]
    fn handles_invalid_syntax() {
        let ast = to_ast("banana");
        assert_eq!(ast.unwrap_err().message(), "Invalid Syntax. Expected <filter>");
    }

    #[test]
    fn simple_object_identifier_index_has_correct_type() {
        let ast = to_ast(".foo").unwrap();
        let child = &ast.children.unwrap()[0];

        assert_eq!(child.node_type, NodeType::ObjectIdentifierIndex);
    }

    #[test]
    fn simple_object_identifier_index_has_correct_identifier() {
        let ast = to_ast(".foo").unwrap();
        let child = &ast.children.unwrap()[0];

        assert_eq!(child.value, Some("foo".to_string()));
    }
}