use adze_ir::SymbolId;
use std::collections::HashMap;
use thiserror::Error;
#[derive(Debug, Clone)]
pub struct Query {
pub source: String,
pub patterns: Vec<Pattern>,
pub capture_names: HashMap<String, u32>,
pub property_settings: Vec<PropertySetting>,
pub property_predicates: Vec<PropertyPredicate>,
}
#[derive(Debug, Clone)]
pub struct Pattern {
pub root: PatternNode,
pub predicates: Vec<Predicate>,
pub start_byte: usize,
}
#[derive(Debug, Clone)]
pub struct PatternNode {
pub symbol: SymbolId,
pub children: Vec<PatternChild>,
pub fields: HashMap<String, PatternNode>,
pub capture: Option<u32>,
pub is_named: bool,
pub quantifier: Quantifier,
}
#[derive(Debug, Clone)]
pub enum PatternChild {
Node(PatternNode),
Token(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Quantifier {
One, Optional, Plus, Star, }
#[derive(Debug, Clone)]
pub enum Predicate {
Eq {
capture1: u32,
capture2: Option<u32>,
value: Option<String>,
},
NotEq {
capture1: u32,
capture2: Option<u32>,
value: Option<String>,
},
Match { capture: u32, regex: String },
NotMatch { capture: u32, regex: String },
Set {
property: String,
capture: Option<u32>,
value: Option<String>,
},
Is {
property: String,
capture: Option<u32>,
value: Option<String>,
},
IsNot {
property: String,
capture: Option<u32>,
value: Option<String>,
},
AnyOf { capture: u32, values: Vec<String> },
Custom {
name: String,
args: Vec<PredicateArg>,
},
}
#[derive(Debug, Clone)]
pub enum PredicateArg {
Capture(u32),
String(String),
}
#[derive(Debug, Clone)]
pub struct PropertySetting {
pub key: String,
pub value: Option<String>,
pub capture: Option<u32>,
}
#[derive(Debug, Clone)]
pub struct PropertyPredicate {
pub key: String,
pub value: Option<String>,
pub capture: Option<u32>,
pub is_positive: bool,
}
#[derive(Debug, Error)]
pub enum QueryError {
#[error("Syntax error at position {position}: {message}")]
SyntaxError { position: usize, message: String },
#[error("Undefined node type: {0}")]
UndefinedNodeType(String),
#[error("Invalid field name: {0}")]
InvalidField(String),
#[error("Invalid capture name: {0}")]
InvalidCapture(String),
#[error("Invalid predicate: {0}")]
InvalidPredicate(String),
#[error("Regex error: {0}")]
RegexError(String),
#[error("Capture index out of bounds: {0}")]
CaptureIndexOutOfBounds(u32),
}
impl Query {
pub fn new() -> Self {
Query {
source: String::new(),
patterns: Vec::new(),
capture_names: HashMap::new(),
property_settings: Vec::new(),
property_predicates: Vec::new(),
}
}
pub fn capture_index(&self, name: &str) -> Option<u32> {
self.capture_names.get(name).copied()
}
pub fn capture_names(&self) -> Vec<&str> {
let mut names: Vec<_> = self.capture_names.iter().collect();
names.sort_by_key(|&(_, &index)| index);
names.into_iter().map(|(name, _)| name.as_str()).collect()
}
pub fn capture_count(&self) -> u32 {
self.capture_names.len() as u32
}
pub fn pattern_count(&self) -> usize {
self.patterns.len()
}
}
impl PatternNode {
pub fn new(symbol: SymbolId, is_named: bool) -> Self {
PatternNode {
symbol,
children: Vec::new(),
fields: HashMap::new(),
capture: None,
is_named,
quantifier: Quantifier::One,
}
}
pub fn with_capture(mut self, capture: u32) -> Self {
self.capture = Some(capture);
self
}
pub fn with_quantifier(mut self, quantifier: Quantifier) -> Self {
self.quantifier = quantifier;
self
}
pub fn add_child(&mut self, child: PatternChild) {
self.children.push(child);
}
pub fn add_field(&mut self, field_name: String, node: PatternNode) {
self.fields.insert(field_name, node);
}
}
impl Default for Query {
fn default() -> Self {
Self::new()
}
}