use std::sync::Arc;
use serde::Serialize;
use crate::annotation::Annotation;
use crate::error::{Diagnostic, Error, Severity};
use crate::signature::Signature;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, serde::Deserialize)]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl Span {
pub const fn new(start: usize, end: usize) -> Self {
Span { start, end }
}
pub fn to(self, other: Span) -> Span {
Span::new(self.start.min(other.start), self.end.max(other.end))
}
pub fn contains(self, offset: usize) -> bool {
self.start <= offset && offset <= self.end
}
}
pub type NodeId = u32;
pub type SlotId = usize;
#[derive(Debug, Clone, Serialize)]
pub struct Ast {
pub root: Node,
pub slots: Vec<Slot>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub diagnostics: Vec<Diagnostic>,
#[serde(skip)]
pub source: String,
}
impl Ast {
pub fn has_errors(&self) -> bool {
self.diagnostics
.iter()
.any(|d| d.severity == Severity::Error)
}
pub fn slot_label(&self, slot: SlotId) -> &str {
&self.slots[slot].label
}
}
#[derive(Debug, Clone, Serialize)]
pub struct Slot {
pub label: String,
#[serde(skip)]
pub(crate) level: i32,
}
#[derive(Debug, Clone, Serialize)]
pub struct Node {
pub id: NodeId,
#[serde(flatten)]
pub kind: NodeKind,
pub span: Span,
#[serde(skip)]
pub pos: usize,
#[serde(skip)]
pub position: usize,
#[serde(flatten)]
pub attrs: Attrs,
#[serde(skip_serializing_if = "Option::is_none")]
pub annotation: Option<Box<Annotation>>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum NodeKind {
Path {
steps: Vec<Node>,
#[serde(skip_serializing_if = "is_false")]
keep_singleton_array: bool,
},
Binary {
op: BinaryOp,
lhs: Box<Node>,
rhs: Box<Node>,
},
Negate {
expr: Box<Node>,
},
Array {
items: Vec<Node>,
},
Object {
pairs: Vec<(Node, Node)>,
},
Name {
name: String,
},
Variable {
name: String,
},
String {
value: String,
},
Number {
value: f64,
},
Bool {
value: bool,
},
Null,
Regex {
pattern: String,
flags: String,
},
Wildcard,
Descendant,
Parent {
slot: SlotId,
label: String,
},
Condition {
condition: Box<Node>,
then: Box<Node>,
#[serde(rename = "else", skip_serializing_if = "Option::is_none")]
otherwise: Option<Box<Node>>,
},
Block {
exprs: Vec<Node>,
},
Bind {
lhs: Box<Node>,
rhs: Box<Node>,
},
Apply {
lhs: Box<Node>,
rhs: Box<Node>,
},
Function {
procedure: Box<Node>,
args: Vec<Node>,
},
Partial {
procedure: Box<Node>,
args: Vec<Node>,
},
Placeholder,
Lambda(Arc<LambdaDef>),
Transform(Arc<TransformDef>),
Sort {
terms: Vec<SortTerm>,
},
Error {
error: Box<Error>,
},
}
#[derive(Debug, Clone, Serialize)]
pub struct LambdaDef {
pub params: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub signature: Option<Signature>,
pub body: Node,
#[serde(skip_serializing_if = "is_false")]
pub thunk: bool,
}
#[derive(Debug, Clone, Serialize)]
pub struct TransformDef {
pub pattern: Node,
pub update: Node,
#[serde(skip_serializing_if = "Option::is_none")]
pub delete: Option<Node>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum BinaryOp {
#[serde(rename = "+")]
Add,
#[serde(rename = "-")]
Sub,
#[serde(rename = "*")]
Mul,
#[serde(rename = "/")]
Div,
#[serde(rename = "%")]
Mod,
#[serde(rename = "=")]
Eq,
#[serde(rename = "!=")]
Ne,
#[serde(rename = "<")]
Lt,
#[serde(rename = "<=")]
Le,
#[serde(rename = ">")]
Gt,
#[serde(rename = ">=")]
Ge,
#[serde(rename = "&")]
Concat,
#[serde(rename = "and")]
And,
#[serde(rename = "or")]
Or,
#[serde(rename = "in")]
In,
#[serde(rename = "..")]
Range,
}
impl BinaryOp {
pub(crate) fn from_symbol(symbol: &str) -> Option<Self> {
Some(match symbol {
"+" => BinaryOp::Add,
"-" => BinaryOp::Sub,
"*" => BinaryOp::Mul,
"/" => BinaryOp::Div,
"%" => BinaryOp::Mod,
"=" => BinaryOp::Eq,
"!=" => BinaryOp::Ne,
"<" => BinaryOp::Lt,
"<=" => BinaryOp::Le,
">" => BinaryOp::Gt,
">=" => BinaryOp::Ge,
"&" => BinaryOp::Concat,
"and" => BinaryOp::And,
"or" => BinaryOp::Or,
"in" => BinaryOp::In,
".." => BinaryOp::Range,
_ => return None,
})
}
pub fn symbol(self) -> &'static str {
match self {
BinaryOp::Add => "+",
BinaryOp::Sub => "-",
BinaryOp::Mul => "*",
BinaryOp::Div => "/",
BinaryOp::Mod => "%",
BinaryOp::Eq => "=",
BinaryOp::Ne => "!=",
BinaryOp::Lt => "<",
BinaryOp::Le => "<=",
BinaryOp::Gt => ">",
BinaryOp::Ge => ">=",
BinaryOp::Concat => "&",
BinaryOp::And => "and",
BinaryOp::Or => "or",
BinaryOp::In => "in",
BinaryOp::Range => "..",
}
}
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Attrs {
#[serde(skip_serializing_if = "is_false")]
pub keep_array: bool,
#[serde(skip_serializing_if = "is_false")]
pub cons_array: bool,
#[serde(skip_serializing_if = "is_false")]
pub tuple: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub focus: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub index: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub stages: Vec<Stage>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub predicate: Vec<Stage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<Box<Group>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ancestor: Option<SlotId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ancestor_label: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub seeking_parent: Vec<SlotId>,
}
fn is_false(b: &bool) -> bool {
!*b
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum Stage {
Filter {
expr: Box<Node>,
span: Span,
},
Index {
var: String,
span: Span,
},
}
#[derive(Debug, Clone, Serialize)]
pub struct Group {
pub pairs: Vec<(Node, Node)>,
pub span: Span,
}
#[derive(Debug, Clone, Serialize)]
pub struct SortTerm {
pub descending: bool,
pub expr: Node,
}
impl Node {
pub(crate) fn new(kind: NodeKind, span: Span, pos: usize) -> Self {
Node {
id: 0,
kind,
span,
pos,
position: 0,
attrs: Attrs::default(),
annotation: None,
}
}
pub(crate) fn path(steps: Vec<Node>) -> Self {
let span = match (steps.first(), steps.last()) {
(Some(first), Some(last)) => first.span.to(last.span),
_ => Span::default(),
};
let pos = steps.first().map_or(0, |s| s.pos);
Node::new(
NodeKind::Path {
steps,
keep_singleton_array: false,
},
span,
pos,
)
}
pub fn type_name(&self) -> &'static str {
match &self.kind {
NodeKind::Path { .. } => "path",
NodeKind::Binary { .. } => "binary",
NodeKind::Negate { .. } | NodeKind::Array { .. } | NodeKind::Object { .. } => "unary",
NodeKind::Name { .. } => "name",
NodeKind::Variable { .. } => "variable",
NodeKind::String { .. } => "string",
NodeKind::Number { .. } => "number",
NodeKind::Bool { .. } | NodeKind::Null => "value",
NodeKind::Regex { .. } => "regex",
NodeKind::Wildcard => "wildcard",
NodeKind::Descendant => "descendant",
NodeKind::Parent { .. } => "parent",
NodeKind::Condition { .. } => "condition",
NodeKind::Block { .. } => "block",
NodeKind::Bind { .. } => "bind",
NodeKind::Apply { .. } => "apply",
NodeKind::Function { .. } => "function",
NodeKind::Partial { .. } => "partial",
NodeKind::Placeholder => "operator",
NodeKind::Lambda { .. } => "lambda",
NodeKind::Transform { .. } => "transform",
NodeKind::Sort { .. } => "sort",
NodeKind::Error { .. } => "error",
}
}
pub(crate) fn steps_mut(&mut self) -> Option<&mut Vec<Node>> {
match &mut self.kind {
NodeKind::Path { steps, .. } => Some(steps),
_ => None,
}
}
pub fn walk<'a>(&'a self, f: &mut impl FnMut(&'a Node)) {
f(self);
self.for_each_child(|c| c.walk(f));
}
pub(crate) fn walk_mut(&mut self, f: &mut impl FnMut(&mut Node)) {
f(self);
self.for_each_child_mut(&mut |c| c.walk_mut(f));
}
pub fn for_each_child<'a>(&'a self, mut f: impl FnMut(&'a Node)) {
match &self.kind {
NodeKind::Path { steps, .. } => steps.iter().for_each(&mut f),
NodeKind::Binary { lhs, rhs, .. }
| NodeKind::Bind { lhs, rhs }
| NodeKind::Apply { lhs, rhs } => {
f(lhs);
f(rhs);
}
NodeKind::Negate { expr } => f(expr),
NodeKind::Array { items } => items.iter().for_each(&mut f),
NodeKind::Object { pairs } => pairs.iter().for_each(|(k, v)| {
f(k);
f(v);
}),
NodeKind::Condition {
condition,
then,
otherwise,
} => {
f(condition);
f(then);
if let Some(e) = otherwise {
f(e);
}
}
NodeKind::Block { exprs } => exprs.iter().for_each(&mut f),
NodeKind::Function { procedure, args } | NodeKind::Partial { procedure, args } => {
f(procedure);
args.iter().for_each(&mut f);
}
NodeKind::Lambda(def) => f(&def.body),
NodeKind::Transform(def) => {
f(&def.pattern);
f(&def.update);
if let Some(d) = &def.delete {
f(d);
}
}
NodeKind::Sort { terms } => terms.iter().for_each(|t| f(&t.expr)),
_ => {}
}
for stage in self.attrs.stages.iter().chain(&self.attrs.predicate) {
if let Stage::Filter { expr, .. } = stage {
f(expr);
}
}
if let Some(group) = &self.attrs.group {
group.pairs.iter().for_each(|(k, v)| {
f(k);
f(v);
});
}
}
fn for_each_child_mut(&mut self, f: &mut impl FnMut(&mut Node)) {
match &mut self.kind {
NodeKind::Path { steps, .. } => steps.iter_mut().for_each(&mut *f),
NodeKind::Binary { lhs, rhs, .. }
| NodeKind::Bind { lhs, rhs }
| NodeKind::Apply { lhs, rhs } => {
f(lhs);
f(rhs);
}
NodeKind::Negate { expr } => f(expr),
NodeKind::Array { items } => items.iter_mut().for_each(&mut *f),
NodeKind::Object { pairs } => pairs.iter_mut().for_each(|(k, v)| {
f(k);
f(v);
}),
NodeKind::Condition {
condition,
then,
otherwise,
} => {
f(condition);
f(then);
if let Some(e) = otherwise {
f(e);
}
}
NodeKind::Block { exprs } => exprs.iter_mut().for_each(&mut *f),
NodeKind::Function { procedure, args } | NodeKind::Partial { procedure, args } => {
f(procedure);
args.iter_mut().for_each(&mut *f);
}
NodeKind::Lambda(def) => {
if let Some(def) = Arc::get_mut(def) {
f(&mut def.body);
}
}
NodeKind::Transform(def) => {
if let Some(def) = Arc::get_mut(def) {
f(&mut def.pattern);
f(&mut def.update);
if let Some(d) = &mut def.delete {
f(d);
}
}
}
NodeKind::Sort { terms } => terms.iter_mut().for_each(|t| f(&mut t.expr)),
_ => {}
}
for stage in self
.attrs
.stages
.iter_mut()
.chain(&mut self.attrs.predicate)
{
if let Stage::Filter { expr, .. } = stage {
f(expr);
}
}
if let Some(group) = &mut self.attrs.group {
group.pairs.iter_mut().for_each(|(k, v)| {
f(k);
f(v);
});
}
}
}