use super::ast::Query;
use super::parser::QueryParser;
use adze_ir::Grammar;
pub fn compile_query(source: &str, grammar: &Grammar) -> Result<Query, super::QueryError> {
let parser = QueryParser::new(source, grammar);
parser.parse()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::query::QueryError;
use adze_ir::{Grammar, SymbolId, Token, TokenPattern};
fn create_test_grammar() -> Grammar {
use adze_ir::{Rule, Symbol};
let mut grammar = Grammar::new("test".to_string());
grammar.tokens.insert(
SymbolId(1),
Token {
name: "identifier".to_string(),
pattern: TokenPattern::Regex("[a-zA-Z]+".to_string()),
fragile: false,
},
);
grammar.tokens.insert(
SymbolId(2),
Token {
name: "number".to_string(),
pattern: TokenPattern::Regex("[0-9]+".to_string()),
fragile: false,
},
);
grammar.rules.entry(SymbolId(10)).or_default().push(Rule {
lhs: SymbolId(10),
rhs: vec![Symbol::NonTerminal(SymbolId(1))],
precedence: None,
associativity: None,
fields: vec![],
production_id: adze_ir::ProductionId(0),
});
grammar.rules.entry(SymbolId(11)).or_default().push(Rule {
lhs: SymbolId(11),
rhs: vec![Symbol::NonTerminal(SymbolId(10))],
precedence: None,
associativity: None,
fields: vec![],
production_id: adze_ir::ProductionId(1),
});
grammar
.rule_names
.insert(SymbolId(1), "identifier".to_string());
grammar.rule_names.insert(SymbolId(2), "number".to_string());
grammar
.rule_names
.insert(SymbolId(10), "expression".to_string());
grammar
.rule_names
.insert(SymbolId(11), "statement".to_string());
use adze_ir::FieldId;
grammar.fields.insert(FieldId(1), "value".to_string());
if let Some(rules) = grammar.rules.get_mut(&SymbolId(11))
&& let Some(rule) = rules.get_mut(0)
{
rule.fields.push((FieldId(1), 0));
}
grammar
}
#[test]
fn test_simple_query() {
let grammar = create_test_grammar();
let query_str = r#"(expression)"#;
let query = compile_query(query_str, &grammar).unwrap();
assert_eq!(query.patterns.len(), 1);
assert_eq!(query.capture_count(), 0);
}
#[test]
fn test_query_with_capture() {
let grammar = create_test_grammar();
let query_str = r#"(expression @expr)"#;
let query = compile_query(query_str, &grammar).unwrap();
assert_eq!(query.patterns.len(), 1);
assert_eq!(query.capture_count(), 1);
assert_eq!(query.capture_index("expr"), Some(0));
}
#[test]
fn test_query_with_field() {
let grammar = create_test_grammar();
let query_str = r#"(statement value: (expression))"#;
match compile_query(query_str, &grammar) {
Ok(query) => assert_eq!(query.patterns.len(), 1),
Err(QueryError::SyntaxError { position, message }) => {
panic!(
"Query compilation failed at position {}: {}",
position, message
);
}
Err(e) => panic!("Query compilation failed: {:?}", e),
}
}
#[test]
fn test_query_with_predicate() {
let grammar = create_test_grammar();
let query_str = r#"
(expression @expr)
(#eq? @expr "test")
"#;
match compile_query(query_str, &grammar) {
Ok(query) => {
assert_eq!(query.patterns.len(), 1);
assert_eq!(query.patterns[0].predicates.len(), 1);
}
Err(QueryError::SyntaxError { position, message }) => {
panic!(
"Query compilation failed at position {}: {}",
position, message
);
}
Err(e) => panic!("Query compilation failed: {:?}", e),
}
}
#[test]
fn test_query_with_quantifiers() {
let grammar = create_test_grammar();
let query_str = r#"(expression (identifier)+ (number)?)"#;
match compile_query(query_str, &grammar) {
Ok(query) => assert_eq!(query.patterns.len(), 1),
Err(QueryError::SyntaxError { position, message }) => {
panic!(
"Query compilation failed at position {}: {}",
position, message
);
}
Err(e) => panic!("Query compilation failed: {:?}", e),
}
}
}