1use std::collections::HashMap;
9use std::ptr;
10
11use super::compiled::{CompiledQuery, CompiledQueryBuffer, align_up};
12use super::ids::{NodeFieldId, NodeTypeId, RefId, StringId, TYPE_NODE, TransitionId};
13use super::strings::StringInterner;
14use super::{
15 EffectOp, Entrypoint, MAX_INLINE_SUCCESSORS, Matcher, RefTransition, Slice, StringRef,
16 Transition, TypeDef, TypeMember,
17};
18
19use crate::query::graph::{BuildEffect, BuildGraph, BuildMatcher, BuildNode, RefMarker};
20use crate::query::infer::TypeInferenceResult;
21
22pub trait NodeKindResolver {
24 fn resolve_kind(&self, name: &str) -> Option<NodeTypeId>;
26
27 fn resolve_field(&self, name: &str) -> Option<NodeFieldId>;
29}
30
31pub struct NullResolver;
33
34impl NodeKindResolver for NullResolver {
35 fn resolve_kind(&self, _name: &str) -> Option<NodeTypeId> {
36 None
37 }
38 fn resolve_field(&self, _name: &str) -> Option<NodeFieldId> {
39 None
40 }
41}
42
43pub struct MapResolver {
45 kinds: HashMap<String, NodeTypeId>,
46 fields: HashMap<String, NodeFieldId>,
47}
48
49impl MapResolver {
50 pub fn new() -> Self {
51 Self {
52 kinds: HashMap::new(),
53 fields: HashMap::new(),
54 }
55 }
56
57 pub fn add_kind(&mut self, name: impl Into<String>, id: NodeTypeId) {
58 self.kinds.insert(name.into(), id);
59 }
60
61 pub fn add_field(&mut self, name: impl Into<String>, id: NodeFieldId) {
62 self.fields.insert(name.into(), id);
63 }
64}
65
66impl Default for MapResolver {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72impl NodeKindResolver for MapResolver {
73 fn resolve_kind(&self, name: &str) -> Option<NodeTypeId> {
74 self.kinds.get(name).copied()
75 }
76
77 fn resolve_field(&self, name: &str) -> Option<NodeFieldId> {
78 self.fields.get(name).copied()
79 }
80}
81
82#[derive(Debug, Clone)]
84pub enum EmitError {
85 UnknownNodeKind(String),
87 UnknownField(String),
89 TooManyTransitions,
91 TooManySuccessors,
93 TooManyEffects,
95 InternalError(String),
97}
98
99impl std::fmt::Display for EmitError {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 match self {
102 EmitError::UnknownNodeKind(s) => write!(f, "unknown node kind: {}", s),
103 EmitError::UnknownField(s) => write!(f, "unknown field: {}", s),
104 EmitError::TooManyTransitions => write!(f, "too many transitions"),
105 EmitError::TooManySuccessors => write!(f, "too many successors"),
106 EmitError::TooManyEffects => write!(f, "too many effects"),
107 EmitError::InternalError(s) => write!(f, "internal error: {}", s),
108 }
109 }
110}
111
112impl std::error::Error for EmitError {}
113
114pub type EmitResult<T> = Result<T, EmitError>;
116
117struct EmitContext<'src, 'g> {
119 graph: &'g BuildGraph<'src>,
120 type_info: &'g TypeInferenceResult<'src>,
121 strings: StringInterner<'src>,
122
123 effects: Vec<EffectOp>,
125 negated_fields: Vec<NodeFieldId>,
126 spilled_successors: Vec<TransitionId>,
128
129 transition_effects: Vec<Slice<EffectOp>>,
132 transition_negated_fields: Vec<Slice<NodeFieldId>>,
134 transition_spilled: Vec<Option<(u32, u32)>>,
136}
137
138impl<'src, 'g> EmitContext<'src, 'g> {
139 fn new(graph: &'g BuildGraph<'src>, type_info: &'g TypeInferenceResult<'src>) -> Self {
140 let node_count = graph.len();
141 Self {
142 graph,
143 type_info,
144 strings: StringInterner::new(),
145 effects: Vec::new(),
146 negated_fields: Vec::new(),
147 spilled_successors: Vec::new(),
148 transition_effects: Vec::with_capacity(node_count),
149 transition_negated_fields: Vec::with_capacity(node_count),
150 transition_spilled: Vec::with_capacity(node_count),
151 }
152 }
153
154 fn intern(&mut self, s: &'src str) -> StringId {
155 self.strings.intern(s)
156 }
157}
158
159struct LayoutInfo {
161 buffer_len: usize,
162 successors_offset: u32,
163 effects_offset: u32,
164 negated_fields_offset: u32,
165 string_refs_offset: u32,
166 string_bytes_offset: u32,
167 type_defs_offset: u32,
168 type_members_offset: u32,
169 entrypoints_offset: u32,
170 trivia_kinds_offset: u32,
171
172 transition_count: u32,
174 successor_count: u32,
175 effect_count: u32,
176 negated_field_count: u16,
177 string_ref_count: u16,
178 type_def_count: u16,
179 type_member_count: u16,
180 entrypoint_count: u16,
181 trivia_kind_count: u16,
182}
183
184pub struct QueryEmitter<'src, 'g, R> {
186 ctx: EmitContext<'src, 'g>,
187 resolver: R,
188 trivia_kinds: Vec<NodeTypeId>,
189}
190
191impl<'src, 'g, R: NodeKindResolver> QueryEmitter<'src, 'g, R> {
192 pub fn new(
194 graph: &'g BuildGraph<'src>,
195 type_info: &'g TypeInferenceResult<'src>,
196 resolver: R,
197 ) -> Self {
198 Self {
199 ctx: EmitContext::new(graph, type_info),
200 resolver,
201 trivia_kinds: Vec::new(),
202 }
203 }
204
205 pub fn with_trivia_kinds(mut self, kinds: Vec<NodeTypeId>) -> Self {
207 self.trivia_kinds = kinds;
208 self
209 }
210
211 pub fn emit(mut self) -> EmitResult<CompiledQuery> {
213 self.analyze()?;
215
216 let layout = self.compute_layout()?;
218
219 self.emit_buffer(layout)
221 }
222
223 fn analyze(&mut self) -> EmitResult<()> {
224 for (name, _) in self.ctx.graph.definitions() {
226 self.ctx.intern(name);
227 }
228
229 for type_def in &self.ctx.type_info.type_defs {
231 if let Some(name) = type_def.name {
232 self.ctx.intern(name);
233 }
234 for member in &type_def.members {
235 self.ctx.intern(member.name);
236 }
237 }
238
239 for (_, node) in self.ctx.graph.iter() {
241 self.analyze_node(node)?;
242 }
243
244 Ok(())
245 }
246
247 fn analyze_node(&mut self, node: &BuildNode<'src>) -> EmitResult<()> {
248 let effects_start = self.ctx.effects.len() as u32;
250 for effect in &node.effects {
251 let ir_effect = self.convert_effect(effect)?;
252 self.ctx.effects.push(ir_effect);
253 }
254 let effects_len = (self.ctx.effects.len() as u32 - effects_start) as u16;
255 self.ctx
256 .transition_effects
257 .push(Slice::new(effects_start, effects_len));
258
259 let negated_start = self.ctx.negated_fields.len() as u32;
261 if let BuildMatcher::Node { negated_fields, .. } = &node.matcher {
262 for field_name in negated_fields {
263 let field_id = self
264 .resolver
265 .resolve_field(field_name)
266 .ok_or_else(|| EmitError::UnknownField((*field_name).to_string()))?;
267 self.ctx.negated_fields.push(field_id);
268 }
269 }
270 let negated_len = (self.ctx.negated_fields.len() as u32 - negated_start) as u16;
271 self.ctx
272 .transition_negated_fields
273 .push(Slice::new(negated_start, negated_len));
274
275 if node.successors.len() > MAX_INLINE_SUCCESSORS {
277 let start = self.ctx.spilled_successors.len() as u32;
278 for &succ in &node.successors {
279 self.ctx.spilled_successors.push(succ);
280 }
281 self.ctx
282 .transition_spilled
283 .push(Some((start, node.successors.len() as u32)));
284 } else {
285 self.ctx.transition_spilled.push(None);
286 }
287
288 Ok(())
289 }
290
291 fn convert_effect(&mut self, effect: &BuildEffect<'src>) -> EmitResult<EffectOp> {
292 Ok(match effect {
293 BuildEffect::CaptureNode => EffectOp::CaptureNode,
294 BuildEffect::ClearCurrent => EffectOp::ClearCurrent,
295 BuildEffect::StartArray { .. } => EffectOp::StartArray,
296 BuildEffect::PushElement => EffectOp::PushElement,
297 BuildEffect::EndArray => EffectOp::EndArray,
298 BuildEffect::StartObject { .. } => EffectOp::StartObject,
299 BuildEffect::EndObject => EffectOp::EndObject,
300 BuildEffect::Field { name, .. } => {
301 let id = self.ctx.intern(name);
302 EffectOp::Field(id)
303 }
304 BuildEffect::StartVariant(tag) => {
305 let id = self.ctx.intern(tag);
306 EffectOp::StartVariant(id)
307 }
308 BuildEffect::EndVariant => EffectOp::EndVariant,
309 BuildEffect::ToString => EffectOp::ToString,
310 })
311 }
312
313 fn compute_layout(&self) -> EmitResult<LayoutInfo> {
314 let transition_count = self.ctx.graph.len() as u32;
315 let successor_count = self.ctx.spilled_successors.len() as u32;
316 let effect_count = self.ctx.effects.len() as u32;
317 let negated_field_count = self.ctx.negated_fields.len() as u16;
318 let string_ref_count = self.ctx.strings.len() as u16;
319 let type_def_count = self.ctx.type_info.type_defs.len() as u16;
320 let type_member_count: u16 = self
321 .ctx
322 .type_info
323 .type_defs
324 .iter()
325 .map(|td| td.members.len() as u16)
326 .sum();
327 let entrypoint_count = self.ctx.graph.definitions().count() as u16;
328 let trivia_kind_count = self.trivia_kinds.len() as u16;
329
330 let mut offset: u32 = 0;
332
333 offset += transition_count * 64;
335
336 let successors_offset = align_up(offset, 4);
338 offset = successors_offset + successor_count * 4;
339
340 let effects_offset = align_up(offset, 4);
342 offset = effects_offset + effect_count * 4;
343
344 let negated_fields_offset = align_up(offset, 2);
346 offset = negated_fields_offset + (negated_field_count as u32) * 2;
347
348 let string_refs_offset = align_up(offset, 4);
350 offset = string_refs_offset + (string_ref_count as u32) * 8;
351
352 let string_bytes_offset = offset;
354 offset += self.ctx.strings.total_bytes() as u32;
355
356 let type_defs_offset = align_up(offset, 4);
358 offset = type_defs_offset + (type_def_count as u32) * 12;
359
360 let type_members_offset = align_up(offset, 2);
362 offset = type_members_offset + (type_member_count as u32) * 4;
363
364 let entrypoints_offset = align_up(offset, 4);
366 offset = entrypoints_offset + (entrypoint_count as u32) * 12;
367
368 let trivia_kinds_offset = if trivia_kind_count > 0 {
370 let aligned = align_up(offset, 2);
371 offset = aligned + (trivia_kind_count as u32) * 2;
372 aligned
373 } else {
374 0
375 };
376
377 let buffer_len = align_up(offset, 64) as usize;
379
380 Ok(LayoutInfo {
381 buffer_len,
382 successors_offset,
383 effects_offset,
384 negated_fields_offset,
385 string_refs_offset,
386 string_bytes_offset,
387 type_defs_offset,
388 type_members_offset,
389 entrypoints_offset,
390 trivia_kinds_offset,
391 transition_count,
392 successor_count,
393 effect_count,
394 negated_field_count,
395 string_ref_count,
396 type_def_count,
397 type_member_count,
398 entrypoint_count,
399 trivia_kind_count,
400 })
401 }
402
403 fn emit_buffer(self, layout: LayoutInfo) -> EmitResult<CompiledQuery> {
404 let mut buffer = CompiledQueryBuffer::allocate(layout.buffer_len);
405 let base = buffer.as_mut_ptr();
406
407 self.emit_transitions(base, &layout)?;
409
410 self.emit_successors(base, &layout);
412
413 self.emit_effects(base, &layout);
415
416 self.emit_negated_fields(base, &layout);
418
419 self.emit_strings(base, &layout);
421
422 self.emit_types(base, &layout);
424
425 self.emit_entrypoints(base, &layout)?;
427
428 self.emit_trivia_kinds(base, &layout);
430
431 Ok(CompiledQuery::new(
432 buffer,
433 layout.successors_offset,
434 layout.effects_offset,
435 layout.negated_fields_offset,
436 layout.string_refs_offset,
437 layout.string_bytes_offset,
438 layout.type_defs_offset,
439 layout.type_members_offset,
440 layout.entrypoints_offset,
441 layout.trivia_kinds_offset,
442 layout.transition_count,
443 layout.successor_count,
444 layout.effect_count,
445 layout.negated_field_count,
446 layout.string_ref_count,
447 layout.type_def_count,
448 layout.type_member_count,
449 layout.entrypoint_count,
450 layout.trivia_kind_count,
451 ))
452 }
453
454 fn emit_transitions(&self, base: *mut u8, _layout: &LayoutInfo) -> EmitResult<()> {
455 let transitions_ptr = base as *mut Transition;
456
457 for (idx, (_, node)) in self.ctx.graph.iter().enumerate() {
458 let transition = self.build_transition(node, idx)?;
459 unsafe {
461 ptr::write(transitions_ptr.add(idx), transition);
462 }
463 }
464
465 Ok(())
466 }
467
468 fn build_transition(&self, node: &BuildNode<'src>, idx: usize) -> EmitResult<Transition> {
469 let matcher = self.convert_matcher(&node.matcher)?;
470 let ref_marker = self.convert_ref_marker(&node.ref_marker);
471 let effects = self.ctx.transition_effects[idx];
472 let negated_fields_slice = self.ctx.transition_negated_fields[idx];
473
474 let (successor_count, successor_data) =
476 if let Some((start, count)) = self.ctx.transition_spilled[idx] {
477 let mut data = [0u32; MAX_INLINE_SUCCESSORS];
479 data[0] = start;
480 (count, data)
481 } else {
482 let mut data = [0u32; MAX_INLINE_SUCCESSORS];
484 for (i, &succ) in node.successors.iter().enumerate() {
485 data[i] = succ;
486 }
487 (node.successors.len() as u32, data)
488 };
489
490 let matcher = match matcher {
492 Matcher::Node { kind, field, .. } => Matcher::Node {
493 kind,
494 field,
495 negated_fields: negated_fields_slice,
496 },
497 Matcher::Anonymous { kind, field, .. } => Matcher::Anonymous {
498 kind,
499 field,
500 negated_fields: Slice::empty(),
501 },
502 other => other,
503 };
504
505 let transition = Transition::new(
506 matcher,
507 ref_marker,
508 node.nav,
509 effects,
510 successor_count,
511 successor_data,
512 );
513
514 Ok(transition)
515 }
516
517 fn convert_matcher(&self, matcher: &BuildMatcher<'src>) -> EmitResult<Matcher> {
518 Ok(match matcher {
519 BuildMatcher::Epsilon => Matcher::Epsilon,
520 BuildMatcher::Node { kind, field, .. } => {
521 let kind_id = self
522 .resolver
523 .resolve_kind(kind)
524 .ok_or_else(|| EmitError::UnknownNodeKind((*kind).to_string()))?;
525 let field_id = match field {
526 Some(f) => self.resolver.resolve_field(f),
527 None => None,
528 };
529 Matcher::Node {
530 kind: kind_id,
531 field: field_id,
532 negated_fields: Slice::empty(), }
534 }
535 BuildMatcher::Anonymous { literal, field } => {
536 let kind_id = self.resolver.resolve_kind(literal).unwrap_or(0);
539 let field_id = match field {
540 Some(f) => self.resolver.resolve_field(f),
541 None => None,
542 };
543 Matcher::Anonymous {
544 kind: kind_id,
545 field: field_id,
546 negated_fields: Slice::empty(),
547 }
548 }
549 BuildMatcher::Wildcard { field } => {
550 let _ = field;
552 Matcher::Wildcard
553 }
554 })
555 }
556
557 fn convert_ref_marker(&self, marker: &RefMarker) -> RefTransition {
558 match marker {
559 RefMarker::None => RefTransition::None,
560 RefMarker::Enter { ref_id } => RefTransition::Enter(*ref_id as RefId),
561 RefMarker::Exit { ref_id } => RefTransition::Exit(*ref_id as RefId),
562 }
563 }
564
565 fn emit_successors(&self, base: *mut u8, layout: &LayoutInfo) {
566 if self.ctx.spilled_successors.is_empty() {
567 return;
568 }
569
570 let ptr = unsafe { base.add(layout.successors_offset as usize) } as *mut TransitionId;
571 for (i, &succ) in self.ctx.spilled_successors.iter().enumerate() {
572 unsafe {
573 ptr::write(ptr.add(i), succ);
574 }
575 }
576 }
577
578 fn emit_effects(&self, base: *mut u8, layout: &LayoutInfo) {
579 if self.ctx.effects.is_empty() {
580 return;
581 }
582
583 let ptr = unsafe { base.add(layout.effects_offset as usize) } as *mut EffectOp;
584 for (i, effect) in self.ctx.effects.iter().enumerate() {
585 unsafe {
586 ptr::write(ptr.add(i), *effect);
587 }
588 }
589 }
590
591 fn emit_negated_fields(&self, base: *mut u8, layout: &LayoutInfo) {
592 if self.ctx.negated_fields.is_empty() {
593 return;
594 }
595
596 let ptr = unsafe { base.add(layout.negated_fields_offset as usize) } as *mut NodeFieldId;
597 for (i, &field) in self.ctx.negated_fields.iter().enumerate() {
598 unsafe {
599 ptr::write(ptr.add(i), field);
600 }
601 }
602 }
603
604 fn emit_strings(&self, base: *mut u8, layout: &LayoutInfo) {
605 let refs_ptr = unsafe { base.add(layout.string_refs_offset as usize) } as *mut StringRef;
607 let bytes_ptr = unsafe { base.add(layout.string_bytes_offset as usize) };
608
609 let mut byte_offset: u32 = 0;
610 for (i, (_, s)) in self.ctx.strings.iter().enumerate() {
611 let string_ref = StringRef::new(byte_offset, s.len() as u16);
613 unsafe {
614 ptr::write(refs_ptr.add(i), string_ref);
615 }
616
617 unsafe {
619 ptr::copy_nonoverlapping(s.as_ptr(), bytes_ptr.add(byte_offset as usize), s.len());
620 }
621
622 byte_offset += s.len() as u32;
623 }
624 }
625
626 fn emit_types(&self, base: *mut u8, layout: &LayoutInfo) {
627 let defs_ptr = unsafe { base.add(layout.type_defs_offset as usize) } as *mut TypeDef;
628 let members_ptr =
629 unsafe { base.add(layout.type_members_offset as usize) } as *mut TypeMember;
630
631 let mut member_idx: u32 = 0;
632
633 for (i, type_def) in self.ctx.type_info.type_defs.iter().enumerate() {
634 let name_id = type_def
635 .name
636 .and_then(|n| self.ctx.strings.get(n))
637 .unwrap_or(super::ids::STRING_NONE);
638
639 let ir_def = if let Some(inner) = type_def.inner_type {
640 TypeDef::wrapper(type_def.kind, inner)
641 } else {
642 let members_start = member_idx;
643 let members_len = type_def.members.len() as u16;
644
645 for member in &type_def.members {
647 let member_name_id = self
648 .ctx
649 .strings
650 .get(member.name)
651 .expect("member name should be interned");
652 let ir_member = TypeMember::new(member_name_id, member.ty);
653 unsafe {
654 ptr::write(members_ptr.add(member_idx as usize), ir_member);
655 }
656 member_idx += 1;
657 }
658
659 TypeDef::composite(
660 type_def.kind,
661 name_id,
662 Slice::new(members_start, members_len),
663 )
664 };
665
666 unsafe {
667 ptr::write(defs_ptr.add(i), ir_def);
668 }
669 }
670 }
671
672 fn emit_entrypoints(&self, base: *mut u8, layout: &LayoutInfo) -> EmitResult<()> {
673 let ptr = unsafe { base.add(layout.entrypoints_offset as usize) } as *mut Entrypoint;
674
675 for (i, (name, entry_node)) in self.ctx.graph.definitions().enumerate() {
676 let name_id = self
677 .ctx
678 .strings
679 .get(name)
680 .expect("definition name should be interned");
681
682 let result_type = self
684 .ctx
685 .type_info
686 .entrypoint_types
687 .get(name)
688 .copied()
689 .unwrap_or(TYPE_NODE);
690
691 let entrypoint = Entrypoint::new(name_id, entry_node, result_type);
692 unsafe {
693 ptr::write(ptr.add(i), entrypoint);
694 }
695 }
696
697 Ok(())
698 }
699
700 fn emit_trivia_kinds(&self, base: *mut u8, layout: &LayoutInfo) {
701 if self.trivia_kinds.is_empty() {
702 return;
703 }
704
705 let ptr = unsafe { base.add(layout.trivia_kinds_offset as usize) } as *mut NodeTypeId;
706 for (i, &kind) in self.trivia_kinds.iter().enumerate() {
707 unsafe {
708 ptr::write(ptr.add(i), kind);
709 }
710 }
711 }
712}
713
714#[cfg(test)]
715mod tests {
716 use super::*;
717 use crate::query::graph::{BuildEffect, BuildGraph, BuildMatcher, BuildNode};
718 use crate::query::infer::TypeInferenceResult;
719 use std::num::NonZeroU16;
720
721 fn make_resolver() -> MapResolver {
722 let mut r = MapResolver::new();
723 r.add_kind("identifier", 1);
724 r.add_kind("function_declaration", 2);
725 r.add_field("name", NonZeroU16::new(1).unwrap());
726 r.add_field("body", NonZeroU16::new(2).unwrap());
727 r
728 }
729
730 #[test]
731 fn emit_simple_query() {
732 let mut graph = BuildGraph::new();
733
734 let node = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
736 graph.node_mut(node).add_effect(BuildEffect::CaptureNode);
737 graph.add_definition("Main", node);
738
739 let type_info = TypeInferenceResult::default();
740 let resolver = make_resolver();
741
742 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
743 let compiled = emitter.emit().expect("emit should succeed");
744
745 assert_eq!(compiled.transition_count(), 1);
746 assert_eq!(compiled.entrypoint_count(), 1);
747
748 let t = compiled.transition(0);
749 assert!(matches!(t.matcher, Matcher::Node { kind: 1, .. }));
750 }
751
752 #[test]
753 fn emit_with_effects() {
754 let mut graph = BuildGraph::new();
755
756 let node = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
757 graph.node_mut(node).add_effect(BuildEffect::CaptureNode);
758 graph.node_mut(node).add_effect(BuildEffect::Field {
759 name: "name",
760 span: Default::default(),
761 });
762 graph.add_definition("Main", node);
763
764 let type_info = TypeInferenceResult::default();
765 let resolver = make_resolver();
766
767 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
768 let compiled = emitter.emit().expect("emit should succeed");
769
770 let view = compiled.transition_view(0);
771 let effects = view.effects();
772 assert_eq!(effects.len(), 2);
773 assert!(matches!(effects[0], EffectOp::CaptureNode));
774 assert!(matches!(effects[1], EffectOp::Field(_)));
775
776 if let EffectOp::Field(id) = effects[1] {
778 assert_eq!(compiled.string(id), "name");
779 }
780 }
781
782 #[test]
783 fn emit_with_successors() {
784 let mut graph = BuildGraph::new();
785
786 let entry = graph.add_epsilon();
788 let a = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
789 let b = graph.add_node(BuildNode::with_matcher(BuildMatcher::node(
790 "function_declaration",
791 )));
792 graph.connect(entry, a);
793 graph.connect(entry, b);
794 graph.add_definition("Main", entry);
795
796 let type_info = TypeInferenceResult::default();
797 let resolver = make_resolver();
798
799 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
800 let compiled = emitter.emit().expect("emit should succeed");
801
802 assert_eq!(compiled.transition_count(), 3);
803
804 let view = compiled.transition_view(0);
805 let successors = view.successors();
806 assert_eq!(successors.len(), 2);
807 assert_eq!(successors[0], 1);
808 assert_eq!(successors[1], 2);
809 }
810
811 #[test]
812 fn emit_many_successors_spills() {
813 let mut graph = BuildGraph::new();
814
815 let entry = graph.add_epsilon();
817 for _ in 0..10 {
818 let node = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
819 graph.connect(entry, node);
820 }
821 graph.add_definition("Main", entry);
822
823 let type_info = TypeInferenceResult::default();
824 let resolver = make_resolver();
825
826 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
827 let compiled = emitter.emit().expect("emit should succeed");
828
829 let t = compiled.transition(0);
830 assert!(!t.has_inline_successors());
831 assert_eq!(t.successor_count, 10);
832
833 let view = compiled.transition_view(0);
834 let successors = view.successors();
835 assert_eq!(successors.len(), 10);
836 }
837
838 #[test]
839 fn string_interning_deduplicates() {
840 let mut graph = BuildGraph::new();
841
842 let n1 = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
844 graph.node_mut(n1).add_effect(BuildEffect::Field {
845 name: "value",
846 span: Default::default(),
847 });
848
849 let n2 = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
850 graph.node_mut(n2).add_effect(BuildEffect::Field {
851 name: "value",
852 span: Default::default(),
853 });
854 graph.connect(n1, n2);
855
856 graph.add_definition("Main", n1);
857
858 let type_info = TypeInferenceResult::default();
859 let resolver = make_resolver();
860
861 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
862 let compiled = emitter.emit().expect("emit should succeed");
863
864 let e1 = compiled.transition_view(0).effects();
866 let e2 = compiled.transition_view(1).effects();
867
868 let id1 = match e1[0] {
869 EffectOp::Field(id) => id,
870 _ => panic!(),
871 };
872 let id2 = match e2[0] {
873 EffectOp::Field(id) => id,
874 _ => panic!(),
875 };
876
877 assert_eq!(id1, id2);
878 assert_eq!(compiled.string(id1), "value");
879 }
880
881 #[test]
882 fn unknown_node_kind_errors() {
883 let mut graph = BuildGraph::new();
884 let node = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("unknown_kind")));
885 graph.add_definition("Main", node);
886
887 let type_info = TypeInferenceResult::default();
888 let resolver = make_resolver();
889
890 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
891 let result = emitter.emit();
892
893 assert!(matches!(result, Err(EmitError::UnknownNodeKind(_))));
894 }
895
896 #[test]
897 fn serialize_deserialize_roundtrip() {
898 let mut graph = BuildGraph::new();
899
900 let n1 = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
902 graph.node_mut(n1).add_effect(BuildEffect::CaptureNode);
903 graph.node_mut(n1).add_effect(BuildEffect::Field {
904 name: "id",
905 span: Default::default(),
906 });
907
908 let n2 = graph.add_node(BuildNode::with_matcher(BuildMatcher::node(
909 "function_declaration",
910 )));
911 graph.node_mut(n2).add_effect(BuildEffect::CaptureNode);
912 graph.connect(n1, n2);
913
914 graph.add_definition("Main", n1);
915
916 let type_info = TypeInferenceResult::default();
917 let resolver = make_resolver();
918
919 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
921 let compiled = emitter.emit().expect("emit should succeed");
922
923 let bytes = crate::ir::to_bytes(&compiled).expect("serialize should succeed");
925
926 let restored = crate::ir::from_bytes(&bytes).expect("deserialize should succeed");
928
929 assert_eq!(restored.transition_count(), compiled.transition_count());
931 assert_eq!(restored.entrypoint_count(), compiled.entrypoint_count());
932
933 for i in 0..compiled.transition_count() {
935 let orig = compiled.transition_view(i);
936 let rest = restored.transition_view(i);
937
938 assert_eq!(orig.successors(), rest.successors());
939 assert_eq!(orig.effects().len(), rest.effects().len());
940 }
941
942 let ep = restored.entrypoints()[0];
944 assert_eq!(restored.string(ep.name_id()), "Main");
945 }
946
947 #[test]
948 fn dump_produces_output() {
949 let mut graph = BuildGraph::new();
950 let node = graph.add_node(BuildNode::with_matcher(BuildMatcher::node("identifier")));
951 graph.node_mut(node).add_effect(BuildEffect::CaptureNode);
952 graph.add_definition("Test", node);
953
954 let type_info = TypeInferenceResult::default();
955 let resolver = make_resolver();
956
957 let emitter = QueryEmitter::new(&graph, &type_info, resolver);
958 let compiled = emitter.emit().expect("emit should succeed");
959
960 let dump = compiled.dump();
961
962 assert!(dump.contains("CompiledQuery"));
963 assert!(dump.contains("Test"));
964 assert!(dump.contains("Capture"));
965 assert!(dump.contains("Node(1)"));
966 }
967}