1use std::collections::HashSet;
9
10use tree_sitter::{Node, TreeCursor};
11
12use crate::ir::{
13 CompiledQuery, EffectOp, Matcher, Nav, NavKind, NodeFieldId, NodeTypeId, RefTransition,
14 TransitionId,
15};
16
17use super::effect_stream::EffectStream;
18use super::error::RuntimeError;
19use super::materializer::Materializer;
20use super::value::Value;
21
22#[derive(Debug, Clone)]
24struct Checkpoint {
25 cursor_checkpoint: usize,
27 effect_ops_watermark: usize,
29 effect_nodes_watermark: usize,
31 recursion_frame: Option<u32>,
33 prev_max_watermark: Option<u32>,
35 transition_id: TransitionId,
37 next_alt: u32,
39}
40
41#[derive(Debug, Default)]
43struct CheckpointStack {
44 points: Vec<Checkpoint>,
45 max_frame_watermark: Option<u32>,
47}
48
49impl CheckpointStack {
50 fn new() -> Self {
51 Self::default()
52 }
53
54 fn push(&mut self, mut point: Checkpoint) {
55 point.prev_max_watermark = self.max_frame_watermark;
56 if let Some(frame) = point.recursion_frame {
57 self.max_frame_watermark = Some(match self.max_frame_watermark {
58 Some(max) => max.max(frame),
59 None => frame,
60 });
61 }
62 self.points.push(point);
63 }
64
65 fn pop(&mut self) -> Option<Checkpoint> {
66 let point = self.points.pop()?;
67 self.max_frame_watermark = point.prev_max_watermark;
68 Some(point)
69 }
70}
71
72#[derive(Debug, Clone)]
74struct Frame {
75 parent: Option<u32>,
77 ref_id: u16,
79 enter_transition: TransitionId,
81}
82
83#[derive(Debug, Default)]
85struct FrameArena {
86 frames: Vec<Frame>,
87 current: Option<u32>,
89}
90
91impl FrameArena {
92 fn new() -> Self {
93 Self::default()
94 }
95
96 fn push(&mut self, parent: Option<u32>, ref_id: u16, enter_transition: TransitionId) -> u32 {
98 let idx = self.frames.len() as u32;
99 self.frames.push(Frame {
100 parent,
101 ref_id,
102 enter_transition,
103 });
104 self.current = Some(idx);
105 idx
106 }
107
108 fn current_frame(&self) -> Option<&Frame> {
110 self.current.map(|idx| &self.frames[idx as usize])
111 }
112
113 fn exit(&mut self) -> Option<&Frame> {
115 let frame = self.current_frame()?;
116 let parent = frame.parent;
117 let idx = self.current?;
118 self.current = parent;
119 Some(&self.frames[idx as usize])
120 }
121
122 fn prune(&mut self, checkpoints: &CheckpointStack) {
124 let high_water = match (self.current, checkpoints.max_frame_watermark) {
125 (None, None) => return,
126 (Some(c), None) => c,
127 (None, Some(m)) => m,
128 (Some(c), Some(m)) => c.max(m),
129 };
130 self.frames.truncate((high_water + 1) as usize);
131 }
132}
133
134const DEFAULT_EXEC_FUEL: u32 = 1_000_000;
136const DEFAULT_RECURSION_FUEL: u32 = 1024;
138
139pub struct QueryInterpreter<'q, 'tree> {
141 query: &'q CompiledQuery,
142 cursor: TreeCursor<'tree>,
143 source: &'tree str,
144 checkpoints: CheckpointStack,
145 frames: FrameArena,
146 effects: EffectStream<'tree>,
147 trivia_kinds: HashSet<NodeTypeId>,
149 matched_node: Option<Node<'tree>>,
151 exec_fuel: u32,
153 recursion_fuel: u32,
155}
156
157impl<'q, 'tree> QueryInterpreter<'q, 'tree> {
158 pub fn new(query: &'q CompiledQuery, cursor: TreeCursor<'tree>, source: &'tree str) -> Self {
162 let trivia_kinds: HashSet<_> = query.trivia_kinds().iter().copied().collect();
163 Self {
164 query,
165 cursor,
166 source,
167 checkpoints: CheckpointStack::new(),
168 frames: FrameArena::new(),
169 effects: EffectStream::new(),
170 trivia_kinds,
171 matched_node: None,
172 exec_fuel: DEFAULT_EXEC_FUEL,
173 recursion_fuel: DEFAULT_RECURSION_FUEL,
174 }
175 }
176
177 pub fn with_exec_fuel(mut self, fuel: u32) -> Self {
179 self.exec_fuel = fuel;
180 self
181 }
182
183 pub fn with_recursion_fuel(mut self, fuel: u32) -> Self {
185 self.recursion_fuel = fuel;
186 self
187 }
188
189 pub fn run(self) -> Result<Value<'tree>, RuntimeError> {
191 let start_transition = self
193 .query
194 .entrypoints()
195 .last()
196 .map(|ep| ep.target())
197 .unwrap_or(0);
198
199 self.run_from(start_transition)
200 }
201
202 pub fn run_from(mut self, start: TransitionId) -> Result<Value<'tree>, RuntimeError> {
204 match self.execute(start) {
205 Ok(true) => Ok(Materializer::materialize(&self.effects)),
206 Ok(false) => Ok(Value::Null), Err(e) => Err(e),
208 }
209 }
210
211 fn execute(&mut self, start: TransitionId) -> Result<bool, RuntimeError> {
213 let mut current = start;
214
215 loop {
216 if self.exec_fuel == 0 {
218 return Err(RuntimeError::ExecFuelExhausted);
219 }
220 self.exec_fuel -= 1;
221
222 self.matched_node = None;
224
225 let view = self.query.transition_view(current);
226 let nav = view.nav();
227 let matcher = view.matcher();
228 let ref_marker = view.ref_marker();
229 let successors = view.successors();
230
231 let nav_ok = self.execute_nav(nav);
233 if !nav_ok {
234 if let Some(next) = self.backtrack()? {
236 current = next;
237 continue;
238 }
239 return Ok(false);
240 }
241
242 let match_ok = self.execute_matcher(matcher, nav);
244 if !match_ok {
245 if let Some(next) = self.backtrack()? {
247 current = next;
248 continue;
249 }
250 return Ok(false);
251 }
252
253 for &effect in view.effects() {
255 self.execute_effect(effect);
256 }
257
258 match ref_marker {
260 RefTransition::None => {}
261 RefTransition::Enter(ref_id) => {
262 if self.recursion_fuel == 0 {
263 return Err(RuntimeError::RecursionLimitExceeded);
264 }
265 self.recursion_fuel -= 1;
266
267 self.frames.push(self.frames.current, ref_id, current);
269
270 if successors.is_empty() {
272 panic!("Enter transition must have at least one successor");
273 }
274 current = successors[0];
275 continue;
276 }
277 RefTransition::Exit(ref_id) => {
278 let frame = self.frames.current_frame().expect("Exit without frame");
280 assert_eq!(frame.ref_id, ref_id, "Exit ref_id mismatch");
281
282 let enter_trans = frame.enter_transition;
284 let enter_view = self.query.transition_view(enter_trans);
285 let returns = &enter_view.successors()[1..];
286
287 self.frames.exit();
289
290 self.frames.prune(&self.checkpoints);
292
293 if returns.is_empty() {
295 if let Some(next) = self.backtrack()? {
298 current = next;
299 continue;
300 }
301 return Ok(true);
302 }
303
304 if returns.len() > 1 {
306 self.save_checkpoint(enter_trans, 2); }
308
309 current = returns[0];
310 continue;
311 }
312 }
313
314 if successors.is_empty() {
316 return Ok(true);
318 }
319
320 if successors.len() > 1 {
322 self.save_checkpoint(current, 1);
323 }
324
325 current = successors[0];
326 }
327 }
328
329 fn save_checkpoint(&mut self, transition_id: TransitionId, next_alt: u32) {
331 let checkpoint = Checkpoint {
332 cursor_checkpoint: self.cursor.descendant_index(),
333 effect_ops_watermark: self.effects.ops().len(),
334 effect_nodes_watermark: self.effects.nodes().len(),
335 recursion_frame: self.frames.current,
336 prev_max_watermark: None, transition_id,
338 next_alt,
339 };
340 self.checkpoints.push(checkpoint);
341 }
342
343 fn backtrack(&mut self) -> Result<Option<TransitionId>, RuntimeError> {
345 loop {
346 let Some(mut checkpoint) = self.checkpoints.pop() else {
347 return Ok(None);
348 };
349
350 self.cursor.goto_descendant(checkpoint.cursor_checkpoint);
352
353 self.effects.truncate(
355 checkpoint.effect_ops_watermark,
356 checkpoint.effect_nodes_watermark,
357 );
358
359 self.frames.current = checkpoint.recursion_frame;
361
362 let view = self.query.transition_view(checkpoint.transition_id);
364 let successors = view.successors();
365
366 if (checkpoint.next_alt as usize) < successors.len() {
367 let next = successors[checkpoint.next_alt as usize];
368 checkpoint.next_alt += 1;
369
370 if (checkpoint.next_alt as usize) < successors.len() {
372 self.checkpoints.push(checkpoint);
373 }
374
375 return Ok(Some(next));
376 }
377 }
379 }
380
381 fn execute_nav(&mut self, nav: Nav) -> bool {
383 match nav.kind {
384 NavKind::Stay => true,
385
386 NavKind::Next => self.cursor.goto_next_sibling(),
387
388 NavKind::NextSkipTrivia => {
389 while self.cursor.goto_next_sibling() {
390 if !self.is_trivia(self.cursor.node()) {
391 return true;
392 }
393 }
394 false
395 }
396
397 NavKind::NextExact => self.cursor.goto_next_sibling(),
398
399 NavKind::Down => self.cursor.goto_first_child(),
400
401 NavKind::DownSkipTrivia => {
402 if !self.cursor.goto_first_child() {
403 return false;
404 }
405 while self.is_trivia(self.cursor.node()) {
406 if !self.cursor.goto_next_sibling() {
407 return false;
408 }
409 }
410 true
411 }
412
413 NavKind::DownExact => self.cursor.goto_first_child(),
414
415 NavKind::Up => {
416 for _ in 0..nav.level {
417 if !self.cursor.goto_parent() {
418 return false;
419 }
420 }
421 true
422 }
423
424 NavKind::UpSkipTrivia => {
425 let current_id = self.cursor.node().id();
427 if let Some(parent) = self.cursor.node().parent() {
428 let child_count = parent.child_count() as u32;
429 let mut found_current = false;
430 for i in 0..child_count {
431 if let Some(child) = parent.child(i) {
432 if child.id() == current_id {
433 found_current = true;
434 continue;
435 }
436 if found_current && !self.is_trivia(child) {
437 return false;
438 }
439 }
440 }
441 }
442 self.cursor.goto_parent()
443 }
444
445 NavKind::UpExact => {
446 let node = self.cursor.node();
448 if let Some(parent) = node.parent() {
449 let child_count = parent.child_count();
450 if child_count > 0 {
451 let last_child = parent.child((child_count - 1) as u32);
452 if last_child.map(|c| c.id()) != Some(node.id()) {
453 return false;
454 }
455 }
456 }
457 self.cursor.goto_parent()
458 }
459 }
460 }
461
462 fn execute_matcher(&mut self, matcher: &Matcher, nav: Nav) -> bool {
464 match matcher {
465 Matcher::Epsilon => true,
466
467 Matcher::Node {
468 kind,
469 field,
470 negated_fields,
471 } => {
472 let matched = self.try_match_node(*kind, *field, *negated_fields, true, nav);
473 if matched {
474 self.matched_node = Some(self.cursor.node());
475 }
476 matched
477 }
478
479 Matcher::Anonymous {
480 kind,
481 field,
482 negated_fields,
483 } => {
484 let matched = self.try_match_node(*kind, *field, *negated_fields, false, nav);
485 if matched {
486 self.matched_node = Some(self.cursor.node());
487 }
488 matched
489 }
490
491 Matcher::Wildcard => {
492 self.matched_node = Some(self.cursor.node());
493 true
494 }
495 }
496 }
497
498 fn try_match_node(
500 &mut self,
501 kind: NodeTypeId,
502 field: Option<NodeFieldId>,
503 negated_fields: crate::ir::Slice<NodeFieldId>,
504 named: bool,
505 nav: Nav,
506 ) -> bool {
507 let can_skip = match nav.kind {
509 NavKind::Next | NavKind::Down => true,
510 NavKind::NextSkipTrivia | NavKind::DownSkipTrivia => false, _ => false,
512 };
513
514 loop {
515 let node = self.cursor.node();
516
517 if named != node.is_named() {
519 if can_skip && self.cursor.goto_next_sibling() {
520 continue;
521 }
522 return false;
523 }
524
525 if node.kind_id() != kind {
527 if can_skip && self.cursor.goto_next_sibling() {
528 continue;
529 }
530 return false;
531 }
532
533 if let Some(field_id) = field {
535 let actual_field = self.cursor.field_id();
536 if actual_field != Some(field_id) {
537 if can_skip && self.cursor.goto_next_sibling() {
538 continue;
539 }
540 return false;
541 }
542 }
543
544 let neg_fields = self.query.resolve_negated_fields(negated_fields);
546 for &neg_field in neg_fields {
547 if node.child_by_field_id(neg_field.get()).is_some() {
548 if can_skip && self.cursor.goto_next_sibling() {
549 continue;
550 }
551 return false;
552 }
553 }
554
555 return true;
556 }
557 }
558
559 fn execute_effect(&mut self, effect: EffectOp) {
561 self.effects.push_op(effect);
562
563 if matches!(effect, EffectOp::CaptureNode) {
564 let node = self.matched_node.expect("CaptureNode without matched node");
565 self.effects.push_node(node, self.source);
566 }
567 }
568
569 fn is_trivia(&self, node: Node) -> bool {
571 self.trivia_kinds.contains(&node.kind_id())
572 }
573}