use crate::ast::{NodeId, Span};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum ClauseKw {
From,
Where,
ConnectBy,
StartWith,
GroupBy,
Having,
Window,
Qualify,
LateralView,
OrderBy,
Limit,
Offset,
}
const PENDING_OWNER: NodeId = match NodeId::new(u32::MAX) {
Some(id) => id,
None => panic!("u32::MAX is non-zero"),
};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ClauseMark {
owner: NodeId,
kind: ClauseKw,
offset: u32,
}
impl ClauseMark {
pub(super) fn pending(kind: ClauseKw, offset: u32) -> Self {
Self {
owner: PENDING_OWNER,
kind,
offset,
}
}
pub(super) fn owner_is_pending(&self) -> bool {
self.owner == PENDING_OWNER
}
pub(super) fn set_owner(&mut self, owner: NodeId) {
self.owner = owner;
}
pub fn owner(&self) -> NodeId {
self.owner
}
pub fn kind(&self) -> ClauseKw {
self.kind
}
pub fn offset(&self) -> u32 {
self.offset
}
}
#[derive(Clone, Default, Debug)]
pub struct ClauseMarkIndex {
marks: Vec<ClauseMark>,
}
impl ClauseMarkIndex {
pub(super) fn new(marks: Vec<ClauseMark>) -> Self {
debug_assert!(
marks
.windows(2)
.all(|pair| pair[0].offset <= pair[1].offset),
"clause marks must be recorded sorted by offset",
);
debug_assert!(
marks.iter().all(|mark| !mark.owner_is_pending()),
"every clause mark must have its owner patched before finalizing",
);
Self { marks }
}
pub fn all(&self) -> &[ClauseMark] {
&self.marks
}
pub fn len(&self) -> usize {
self.marks.len()
}
pub fn is_empty(&self) -> bool {
self.marks.is_empty()
}
pub fn in_span(&self, span: Span) -> &[ClauseMark] {
if span.is_synthetic() {
return &[];
}
let lo = self
.marks
.partition_point(|mark| mark.offset < span.start());
let hi = self.marks.partition_point(|mark| mark.offset < span.end());
if lo >= hi {
return &[];
}
&self.marks[lo..hi]
}
}
#[cfg(test)]
mod tests {
use super::*;
fn index(marks: &[(ClauseKw, u32)]) -> ClauseMarkIndex {
let marks = marks
.iter()
.enumerate()
.map(|(i, &(kind, offset))| {
let mut mark = ClauseMark::pending(kind, offset);
mark.set_owner(NodeId::new(i as u32 + 1).expect("non-zero owner"));
mark
})
.collect();
ClauseMarkIndex::new(marks)
}
#[test]
fn empty_index_allocates_nothing_and_queries_empty() {
let empty = ClauseMarkIndex::default();
assert!(empty.is_empty());
assert_eq!(empty.len(), 0);
assert_eq!(empty.all(), &[]);
assert!(empty.in_span(Span::new(0, 100)).is_empty());
}
#[test]
fn in_span_returns_only_contained_marks() {
use ClauseKw::{From, GroupBy, Where};
let idx = index(&[(From, 9), (Where, 16), (GroupBy, 24)]);
let inner = idx.in_span(Span::new(16, 24));
assert_eq!(
inner.iter().map(ClauseMark::kind).collect::<Vec<_>>(),
[Where],
);
assert_eq!(idx.in_span(Span::new(0, 33)).len(), 3);
assert!(idx.in_span(Span::SYNTHETIC).is_empty());
assert!(idx.in_span(Span::new(0, 9)).is_empty());
assert_eq!(idx.in_span(Span::new(0, 10)).len(), 1);
}
}