1use std::collections::BTreeMap;
8use std::num::NonZeroU16;
9
10use super::effects::{EffectOp, EffectOpcode};
11use super::instructions::{
12 Call, Opcode, Return, StepAddr, StepId, Trampoline, select_match_opcode,
13};
14use super::nav::Nav;
15use crate::analyze::type_check::TypeId;
16
17#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
29pub enum NodeTypeIR {
30 #[default]
32 Any,
33 Named(Option<NonZeroU16>),
37 Anonymous(Option<NonZeroU16>),
41}
42
43impl NodeTypeIR {
44 pub fn to_bytes(self) -> (u8, u16) {
49 match self {
50 Self::Any => (0b00, 0),
51 Self::Named(opt) => (0b01, opt.map(|n| n.get()).unwrap_or(0)),
52 Self::Anonymous(opt) => (0b10, opt.map(|n| n.get()).unwrap_or(0)),
53 }
54 }
55
56 pub fn from_bytes(node_kind: u8, node_type: u16) -> Self {
58 match node_kind {
59 0b00 => Self::Any,
60 0b01 => Self::Named(NonZeroU16::new(node_type)),
61 0b10 => Self::Anonymous(NonZeroU16::new(node_type)),
62 _ => panic!("invalid node_kind: {node_kind}"),
63 }
64 }
65
66 pub fn type_id(&self) -> Option<NonZeroU16> {
68 match self {
69 Self::Any => None,
70 Self::Named(opt) | Self::Anonymous(opt) => *opt,
71 }
72 }
73
74 pub fn is_any(&self) -> bool {
76 matches!(self, Self::Any)
77 }
78
79 pub fn is_named(&self) -> bool {
81 matches!(self, Self::Named(_))
82 }
83
84 pub fn is_anonymous(&self) -> bool {
86 matches!(self, Self::Anonymous(_))
87 }
88}
89
90#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
92pub struct Label(pub u32);
93
94impl Label {
95 #[inline]
97 pub fn resolve(self, map: &BTreeMap<Label, StepAddr>) -> StepAddr {
98 *map.get(&self).expect("label not in layout")
99 }
100}
101
102#[derive(Clone, Copy, Debug)]
111pub enum MemberRef {
112 Absolute(u16),
114 Deferred {
118 field_name: plotnik_core::Symbol,
120 field_type: TypeId,
122 },
123 DeferredByIndex {
126 parent_type: TypeId,
128 relative_index: u16,
130 },
131}
132
133impl MemberRef {
134 pub fn absolute(index: u16) -> Self {
136 Self::Absolute(index)
137 }
138
139 pub fn deferred(field_name: plotnik_core::Symbol, field_type: TypeId) -> Self {
141 Self::Deferred {
142 field_name,
143 field_type,
144 }
145 }
146
147 pub fn deferred_by_index(parent_type: TypeId, relative_index: u16) -> Self {
149 Self::DeferredByIndex {
150 parent_type,
151 relative_index,
152 }
153 }
154
155 pub fn resolve<F, G>(self, lookup_member: F, get_member_base: G) -> u16
160 where
161 F: Fn(plotnik_core::Symbol, TypeId) -> Option<u16>,
162 G: Fn(TypeId) -> Option<u16>,
163 {
164 match self {
165 Self::Absolute(n) => n,
166 Self::Deferred {
167 field_name,
168 field_type,
169 } => lookup_member(field_name, field_type).unwrap_or(0),
170 Self::DeferredByIndex {
171 parent_type,
172 relative_index,
173 } => get_member_base(parent_type).unwrap_or(0) + relative_index,
174 }
175 }
176}
177
178#[derive(Clone, Debug)]
181pub struct EffectIR {
182 pub opcode: EffectOpcode,
183 pub payload: usize,
185 pub member_ref: Option<MemberRef>,
187}
188
189impl EffectIR {
190 pub fn simple(opcode: EffectOpcode, payload: usize) -> Self {
192 Self {
193 opcode,
194 payload,
195 member_ref: None,
196 }
197 }
198
199 pub fn with_member(opcode: EffectOpcode, member_ref: MemberRef) -> Self {
201 Self {
202 opcode,
203 payload: 0,
204 member_ref: Some(member_ref),
205 }
206 }
207
208 pub fn node() -> Self {
210 Self::simple(EffectOpcode::Node, 0)
211 }
212
213 pub fn text() -> Self {
215 Self::simple(EffectOpcode::Text, 0)
216 }
217
218 pub fn null() -> Self {
220 Self::simple(EffectOpcode::Null, 0)
221 }
222
223 pub fn push() -> Self {
225 Self::simple(EffectOpcode::Push, 0)
226 }
227
228 pub fn start_arr() -> Self {
230 Self::simple(EffectOpcode::Arr, 0)
231 }
232
233 pub fn end_arr() -> Self {
235 Self::simple(EffectOpcode::EndArr, 0)
236 }
237
238 pub fn start_obj() -> Self {
240 Self::simple(EffectOpcode::Obj, 0)
241 }
242
243 pub fn end_obj() -> Self {
245 Self::simple(EffectOpcode::EndObj, 0)
246 }
247
248 pub fn start_enum() -> Self {
250 Self::simple(EffectOpcode::Enum, 0)
251 }
252
253 pub fn end_enum() -> Self {
255 Self::simple(EffectOpcode::EndEnum, 0)
256 }
257
258 pub fn suppress_begin() -> Self {
260 Self::simple(EffectOpcode::SuppressBegin, 0)
261 }
262
263 pub fn suppress_end() -> Self {
265 Self::simple(EffectOpcode::SuppressEnd, 0)
266 }
267
268 pub fn resolve<F, G>(&self, lookup_member: F, get_member_base: G) -> EffectOp
273 where
274 F: Fn(plotnik_core::Symbol, TypeId) -> Option<u16>,
275 G: Fn(TypeId) -> Option<u16>,
276 {
277 let payload = if let Some(member_ref) = self.member_ref {
278 member_ref.resolve(&lookup_member, &get_member_base) as usize
279 } else {
280 self.payload
281 };
282 EffectOp::new(self.opcode, payload)
283 }
284}
285
286#[derive(Clone, Debug)]
288pub enum InstructionIR {
289 Match(MatchIR),
290 Call(CallIR),
291 Return(ReturnIR),
292 Trampoline(TrampolineIR),
293}
294
295impl InstructionIR {
296 #[inline]
298 pub fn label(&self) -> Label {
299 match self {
300 Self::Match(m) => m.label,
301 Self::Call(c) => c.label,
302 Self::Return(r) => r.label,
303 Self::Trampoline(t) => t.label,
304 }
305 }
306
307 pub fn size(&self) -> usize {
309 match self {
310 Self::Match(m) => m.size(),
311 Self::Call(_) | Self::Return(_) | Self::Trampoline(_) => 8,
312 }
313 }
314
315 pub fn successors(&self) -> Vec<Label> {
317 match self {
318 Self::Match(m) => m.successors.clone(),
319 Self::Call(c) => vec![c.next],
320 Self::Return(_) => vec![],
321 Self::Trampoline(t) => vec![t.next],
322 }
323 }
324
325 pub fn resolve<F, G>(
330 &self,
331 map: &BTreeMap<Label, StepAddr>,
332 lookup_member: F,
333 get_member_base: G,
334 ) -> Vec<u8>
335 where
336 F: Fn(plotnik_core::Symbol, TypeId) -> Option<u16>,
337 G: Fn(TypeId) -> Option<u16>,
338 {
339 match self {
340 Self::Match(m) => m.resolve(map, lookup_member, get_member_base),
341 Self::Call(c) => c.resolve(map).to_vec(),
342 Self::Return(r) => r.resolve().to_vec(),
343 Self::Trampoline(t) => t.resolve(map).to_vec(),
344 }
345 }
346}
347
348#[derive(Clone, Debug)]
350pub struct MatchIR {
351 pub label: Label,
353 pub nav: Nav,
355 pub node_type: NodeTypeIR,
357 pub node_field: Option<NonZeroU16>,
359 pub pre_effects: Vec<EffectIR>,
361 pub neg_fields: Vec<u16>,
363 pub post_effects: Vec<EffectIR>,
365 pub successors: Vec<Label>,
367}
368
369impl MatchIR {
370 pub fn terminal(label: Label) -> Self {
372 Self {
373 label,
374 nav: Nav::Epsilon,
375 node_type: NodeTypeIR::Any,
376 node_field: None,
377 pre_effects: vec![],
378 neg_fields: vec![],
379 post_effects: vec![],
380 successors: vec![],
381 }
382 }
383
384 pub fn at(label: Label) -> Self {
386 Self::terminal(label)
387 }
388
389 pub fn epsilon(label: Label, next: Label) -> Self {
391 Self::at(label).next(next)
392 }
393
394 pub fn nav(mut self, nav: Nav) -> Self {
396 self.nav = nav;
397 self
398 }
399
400 pub fn node_type(mut self, t: NodeTypeIR) -> Self {
402 self.node_type = t;
403 self
404 }
405
406 pub fn node_field(mut self, f: impl Into<Option<NonZeroU16>>) -> Self {
408 self.node_field = f.into();
409 self
410 }
411
412 pub fn neg_field(mut self, f: u16) -> Self {
414 self.neg_fields.push(f);
415 self
416 }
417
418 pub fn pre_effect(mut self, e: EffectIR) -> Self {
420 self.pre_effects.push(e);
421 self
422 }
423
424 pub fn post_effect(mut self, e: EffectIR) -> Self {
426 self.post_effects.push(e);
427 self
428 }
429
430 pub fn neg_fields(mut self, fields: impl IntoIterator<Item = u16>) -> Self {
432 self.neg_fields.extend(fields);
433 self
434 }
435
436 pub fn pre_effects(mut self, effects: impl IntoIterator<Item = EffectIR>) -> Self {
438 self.pre_effects.extend(effects);
439 self
440 }
441
442 pub fn post_effects(mut self, effects: impl IntoIterator<Item = EffectIR>) -> Self {
444 self.post_effects.extend(effects);
445 self
446 }
447
448 pub fn next(mut self, s: Label) -> Self {
450 self.successors = vec![s];
451 self
452 }
453
454 pub fn next_many(mut self, s: Vec<Label>) -> Self {
456 self.successors = s;
457 self
458 }
459
460 pub fn size(&self) -> usize {
462 let can_use_match8 = self.pre_effects.is_empty()
464 && self.neg_fields.is_empty()
465 && self.post_effects.is_empty()
466 && self.successors.len() <= 1;
467
468 if can_use_match8 {
469 return 8;
470 }
471
472 let slots = self.pre_effects.len()
474 + self.neg_fields.len()
475 + self.post_effects.len()
476 + self.successors.len();
477
478 select_match_opcode(slots).map(|op| op.size()).unwrap_or(64)
479 }
480
481 pub fn resolve<F, G>(
486 &self,
487 map: &BTreeMap<Label, StepAddr>,
488 lookup_member: F,
489 get_member_base: G,
490 ) -> Vec<u8>
491 where
492 F: Fn(plotnik_core::Symbol, TypeId) -> Option<u16>,
493 G: Fn(TypeId) -> Option<u16>,
494 {
495 let can_use_match8 = self.pre_effects.is_empty()
496 && self.neg_fields.is_empty()
497 && self.post_effects.is_empty()
498 && self.successors.len() <= 1;
499
500 let opcode = if can_use_match8 {
501 Opcode::Match8
502 } else {
503 let slots_needed = self.pre_effects.len()
504 + self.neg_fields.len()
505 + self.post_effects.len()
506 + self.successors.len();
507 select_match_opcode(slots_needed).expect("instruction too large")
508 };
509
510 let size = opcode.size();
511 let mut bytes = vec![0u8; size];
512
513 let (node_kind, node_type_val) = self.node_type.to_bytes();
515 bytes[0] = (node_kind << 4) | (opcode as u8); bytes[1] = self.nav.to_byte();
517 bytes[2..4].copy_from_slice(&node_type_val.to_le_bytes());
518 let node_field_val = self.node_field.map(|n| n.get()).unwrap_or(0);
519 bytes[4..6].copy_from_slice(&node_field_val.to_le_bytes());
520
521 if opcode == Opcode::Match8 {
522 let next = self
523 .successors
524 .first()
525 .map(|&l| l.resolve(map))
526 .unwrap_or(0);
527 bytes[6..8].copy_from_slice(&next.to_le_bytes());
528 } else {
529 let pre_count = self.pre_effects.len();
530 let neg_count = self.neg_fields.len();
531 let post_count = self.post_effects.len();
532 let succ_count = self.successors.len();
533
534 assert!(
536 pre_count <= 7,
537 "pre_effects overflow: {pre_count} > 7 (use emit_match_with_cascade)"
538 );
539 assert!(neg_count <= 7, "neg_fields overflow: {neg_count} > 7");
540 assert!(post_count <= 7, "post_effects overflow: {post_count} > 7");
541 assert!(succ_count <= 63, "successors overflow: {succ_count} > 63");
542
543 let counts = ((pre_count as u16) << 13)
544 | ((neg_count as u16) << 10)
545 | ((post_count as u16) << 7)
546 | ((succ_count as u16) << 1);
547 bytes[6..8].copy_from_slice(&counts.to_le_bytes());
548
549 let mut offset = 8;
550 for effect in &self.pre_effects {
551 let resolved = effect.resolve(&lookup_member, &get_member_base);
552 bytes[offset..offset + 2].copy_from_slice(&resolved.to_bytes());
553 offset += 2;
554 }
555 for &field in &self.neg_fields {
556 bytes[offset..offset + 2].copy_from_slice(&field.to_le_bytes());
557 offset += 2;
558 }
559 for effect in &self.post_effects {
560 let resolved = effect.resolve(&lookup_member, &get_member_base);
561 bytes[offset..offset + 2].copy_from_slice(&resolved.to_bytes());
562 offset += 2;
563 }
564 for &label in &self.successors {
565 let addr = label.resolve(map);
566 bytes[offset..offset + 2].copy_from_slice(&addr.to_le_bytes());
567 offset += 2;
568 }
569 }
570
571 bytes
572 }
573
574 #[inline]
576 pub fn is_epsilon(&self) -> bool {
577 self.nav == Nav::Epsilon
578 }
579}
580
581impl From<MatchIR> for InstructionIR {
582 fn from(m: MatchIR) -> Self {
583 Self::Match(m)
584 }
585}
586
587#[derive(Clone, Debug)]
589pub struct CallIR {
590 pub label: Label,
592 pub nav: Nav,
594 pub node_field: Option<NonZeroU16>,
596 pub next: Label,
598 pub target: Label,
600}
601
602impl CallIR {
603 pub fn new(label: Label, target: Label, next: Label) -> Self {
605 Self {
606 label,
607 nav: Nav::Stay,
608 node_field: None,
609 next,
610 target,
611 }
612 }
613
614 pub fn nav(mut self, nav: Nav) -> Self {
616 self.nav = nav;
617 self
618 }
619
620 pub fn node_field(mut self, f: impl Into<Option<NonZeroU16>>) -> Self {
622 self.node_field = f.into();
623 self
624 }
625
626 pub fn resolve(&self, map: &BTreeMap<Label, StepAddr>) -> [u8; 8] {
628 Call::new(
629 self.nav,
630 self.node_field,
631 StepId::new(self.next.resolve(map)),
632 StepId::new(self.target.resolve(map)),
633 )
634 .to_bytes()
635 }
636}
637
638impl From<CallIR> for InstructionIR {
639 fn from(c: CallIR) -> Self {
640 Self::Call(c)
641 }
642}
643
644#[derive(Clone, Debug)]
646pub struct ReturnIR {
647 pub label: Label,
649}
650
651impl ReturnIR {
652 pub fn new(label: Label) -> Self {
654 Self { label }
655 }
656
657 pub fn resolve(&self) -> [u8; 8] {
659 Return::new().to_bytes()
660 }
661}
662
663impl From<ReturnIR> for InstructionIR {
664 fn from(r: ReturnIR) -> Self {
665 Self::Return(r)
666 }
667}
668
669#[derive(Clone, Debug)]
674pub struct TrampolineIR {
675 pub label: Label,
677 pub next: Label,
679}
680
681impl TrampolineIR {
682 pub fn new(label: Label, next: Label) -> Self {
684 Self { label, next }
685 }
686
687 pub fn resolve(&self, map: &BTreeMap<Label, StepAddr>) -> [u8; 8] {
689 Trampoline::new(StepId::new(self.next.resolve(map))).to_bytes()
690 }
691}
692
693impl From<TrampolineIR> for InstructionIR {
694 fn from(t: TrampolineIR) -> Self {
695 Self::Trampoline(t)
696 }
697}
698
699#[derive(Clone, Debug)]
701pub struct LayoutResult {
702 pub(crate) label_to_step: BTreeMap<Label, StepAddr>,
704 pub(crate) total_steps: u16,
706}
707
708impl LayoutResult {
709 pub fn new(label_to_step: BTreeMap<Label, StepAddr>, total_steps: u16) -> Self {
711 Self {
712 label_to_step,
713 total_steps,
714 }
715 }
716
717 pub fn empty() -> Self {
719 Self {
720 label_to_step: BTreeMap::new(),
721 total_steps: 0,
722 }
723 }
724
725 pub fn label_to_step(&self) -> &BTreeMap<Label, StepAddr> {
726 &self.label_to_step
727 }
728 pub fn total_steps(&self) -> u16 {
729 self.total_steps
730 }
731}