use std::hash::{Hash, Hasher};
use std::ops::Deref;
use regress::Regex;
use crate::Span;
#[derive(Debug, Clone)]
pub struct RegexLiteral {
regex: Regex,
pattern: String,
}
impl RegexLiteral {
pub fn new(
pattern: &str,
case_insensitive: bool,
multi_line: bool,
) -> Result<Self, regress::Error> {
let mut flags = String::new();
if case_insensitive {
flags.push('i');
}
if multi_line {
flags.push('m');
}
let regex = Regex::with_flags(pattern, flags.as_str())?;
Ok(Self {
regex,
pattern: pattern.to_string(),
})
}
pub fn is_match(&self, text: &str) -> bool {
self.regex.find(text).is_some()
}
pub fn as_pattern(&self) -> &str {
&self.pattern
}
pub fn get_regex(&self) -> &Regex {
&self.regex
}
}
impl Deref for RegexLiteral {
type Target = Regex;
fn deref(&self) -> &Self::Target {
&self.regex
}
}
impl PartialEq for RegexLiteral {
fn eq(&self, other: &Self) -> bool {
self.pattern == other.pattern
}
}
impl Eq for RegexLiteral {}
impl Hash for RegexLiteral {
fn hash<H: Hasher>(&self, state: &mut H) {
self.pattern.hash(state);
}
}
pub type Object = Vec<(Ast, Ast)>;
pub type SortTerms = Vec<(Ast, bool)>;
#[derive(Debug, Clone)]
pub enum UnaryOp {
Minus(Box<Ast>),
ArrayConstructor(Vec<Ast>),
ObjectConstructor(Object),
}
#[derive(Debug, PartialEq, Clone)]
pub enum BinaryOp {
Add,
Subtract,
Multiply,
Divide,
Modulus,
Equal,
NotEqual,
LessThan,
GreaterThan,
LessThanEqual,
GreaterThanEqual,
Concat,
And,
Or,
In,
Map,
Range,
FocusBind,
IndexBind,
Predicate,
Apply,
Bind,
}
impl std::fmt::Display for BinaryOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match *self {
BinaryOp::Add => "+",
BinaryOp::Subtract => "-",
BinaryOp::Multiply => "*",
BinaryOp::Divide => "/",
BinaryOp::Modulus => "%",
BinaryOp::Equal => "=",
BinaryOp::NotEqual => "!=",
BinaryOp::LessThan => "<",
BinaryOp::GreaterThan => ">",
BinaryOp::LessThanEqual => "<=",
BinaryOp::GreaterThanEqual => ">=",
BinaryOp::Concat => "&",
BinaryOp::And => "and",
BinaryOp::Or => "or",
BinaryOp::In => "in",
BinaryOp::Map => ".",
BinaryOp::Range => "..",
BinaryOp::FocusBind => "@",
BinaryOp::IndexBind => "#",
BinaryOp::Predicate => "[]",
BinaryOp::Apply => "~>",
BinaryOp::Bind => ":=",
})
}
}
#[derive(Debug, Clone)]
pub enum AstKind {
Empty,
Null,
Bool(bool),
String(String),
Number(f64),
Regex(Box<RegexLiteral>),
Name(String),
Var(String),
Unary(UnaryOp),
Binary(BinaryOp, Box<Ast>, Box<Ast>),
GroupBy(Box<Ast>, Object),
OrderBy(Box<Ast>, SortTerms),
Block(Vec<Ast>),
Wildcard,
Descendent,
Parent,
Function {
name: String,
proc: Box<Ast>,
args: Vec<Ast>,
is_partial: bool,
},
PartialArg,
Lambda {
name: String,
args: Vec<Ast>,
body: Box<Ast>,
thunk: bool,
},
Ternary {
cond: Box<Ast>,
truthy: Box<Ast>,
falsy: Option<Box<Ast>>,
},
Transform {
pattern: Box<Ast>,
update: Box<Ast>,
delete: Option<Box<Ast>>,
},
Path(Vec<Ast>),
Filter(Box<Ast>),
Sort(SortTerms),
Index(String),
}
#[derive(Debug, Clone)]
pub struct Ast {
pub kind: AstKind,
pub span: Span,
pub keep_array: bool,
pub cons_array: bool,
pub keep_singleton_array: bool,
pub group_by: Option<(Span, Object)>,
pub predicates: Option<Vec<Ast>>,
pub stages: Option<Vec<Ast>>,
pub tuple: bool,
pub index: Option<String>,
pub focus: Option<String>,
pub seeking_parent: bool,
}
impl Default for Ast {
fn default() -> Ast {
Ast::new(AstKind::Empty, Span::at(0))
}
}
impl Ast {
pub fn new(kind: AstKind, span: Span) -> Self {
Self {
kind,
span,
keep_array: false,
cons_array: false,
keep_singleton_array: false,
group_by: None,
predicates: None,
stages: None,
tuple: false,
index: None,
focus: None,
seeking_parent: false,
}
}
}
pub fn check_balanced_brackets(expr: &str) -> Result<(), String> {
let mut bracket_count: i32 = 0;
let mut i = 0;
let chars: Vec<char> = expr.chars().collect();
while i < chars.len() {
let ch = chars[i];
if ch == '[' {
if i + 1 < chars.len() && chars[i + 1] == '[' {
i += 1; } else {
bracket_count += 1;
}
} else if ch == ']' {
if i + 1 < chars.len() && chars[i + 1] == ']' {
i += 1; } else {
if bracket_count == 0 {
return Err(format!("Unbalanced closing bracket found in: {expr}"));
}
bracket_count -= 1;
}
}
i += 1;
}
if bracket_count != 0 {
return Err(format!(
"No matching closing bracket ']' in expression: {expr}"
));
}
Ok(())
}