pub mod adapter;
mod ast;
mod encoding;
mod error;
mod exec;
mod lexer;
mod parser;
pub mod reflect;
pub use encoding::{base64, base64_decode, sha256, sha256_hex};
pub mod highlight;
pub mod quantity;
mod stdlib;
pub mod temporal;
mod unparse;
mod value;
pub use adapter::{AllowShell, AstAdapter, NodeId, QuantifierBound, WithNow};
pub use error::{QuarbError, Result};
pub use exec::QueryResult;
pub use parser::Defs;
pub use value::Value;
pub fn run(query: &str, adapter: &impl AstAdapter) -> Result<QueryResult> {
let tokens = lexer::lex(query)?;
let ast = parser::parse_with_data(&tokens, Defs::default(), Some(adapter))?;
exec::gate_shell(&ast, adapter)?;
Ok(exec::eval(&ast, adapter))
}
pub fn run_traced(query: &str, adapter: &impl AstAdapter) -> Result<Vec<(NodeId, Option<Value>)>> {
let tokens = lexer::lex(query)?;
let ast = parser::parse_with_data(&tokens, Defs::default(), Some(adapter))?;
exec::gate_shell(&ast, adapter)?;
Ok(exec::eval_traced(&ast, adapter))
}
pub fn parse_defs(text: &str) -> Result<Defs> {
let tokens = lexer::lex(&strip_defs_comments(text))?;
parser::parse_defs(&tokens)
}
pub fn strip_defs_comments(text: &str) -> String {
text.lines()
.map(|l| if l.trim_start().starts_with('#') { "" } else { l })
.collect::<Vec<_>>()
.join("\n")
}
pub fn run_with_defs(query: &str, defs: &Defs, adapter: &impl AstAdapter) -> Result<QueryResult> {
let tokens = lexer::lex(query)?;
let ast = parser::parse_with_data(&tokens, defs.clone(), Some(adapter))?;
exec::gate_shell(&ast, adapter)?;
Ok(exec::eval(&ast, adapter))
}
pub fn run_traced_with_defs(
query: &str,
defs: &Defs,
adapter: &impl AstAdapter,
) -> Result<Vec<(NodeId, Option<Value>)>> {
let tokens = lexer::lex(query)?;
let ast = parser::parse_with_data(&tokens, defs.clone(), Some(adapter))?;
exec::gate_shell(&ast, adapter)?;
Ok(exec::eval_traced(&ast, adapter))
}
pub fn is_calculator(query: &str) -> bool {
let Ok(tokens) = lexer::lex(query) else {
return false;
};
let Ok(ast) = parser::parse_with_defs(&tokens, Defs::default()) else {
return false;
};
ast.correlations.is_empty()
&& !ast.branches.is_empty()
&& ast.branches.iter().all(|b| {
matches!(b.anchor, ast::Anchor::Root) && b.steps.is_empty() && b.projection.is_none()
})
}
pub fn expand(query: &str, defs: &Defs) -> Result<String> {
let tokens = lexer::lex(query)?;
let ast = parser::parse_with_defs(&tokens, defs.clone())?;
Ok(unparse::unparse(&ast))
}
pub fn expand_with(query: &str, defs: &Defs, adapter: &impl AstAdapter) -> Result<String> {
let tokens = lexer::lex(query)?;
let ast = parser::parse_with_data(&tokens, defs.clone(), Some(adapter))?;
Ok(unparse::unparse(&ast))
}