@@ -7,6 +7,7 @@ use std::num::NonZeroU16;
77
88use super :: constants:: { SECTION_ALIGN , STEP_SIZE } ;
99use super :: effects:: EffectOp ;
10+ use super :: ir:: NodeTypeIR ;
1011use super :: nav:: Nav ;
1112
1213/// Step address in bytecode (raw u16).
@@ -129,12 +130,12 @@ impl Opcode {
129130#[ derive( Clone , Copy , Debug ) ]
130131pub struct Match < ' a > {
131132 bytes : & ' a [ u8 ] ,
132- /// Segment index (0-15 , currently only 0 is used).
133+ /// Segment index (0-3 , currently only 0 is used).
133134 pub segment : u8 ,
134- /// Navigation command.
135+ /// Navigation command. `Epsilon` means no cursor movement or node check.
135136 pub nav : Nav ,
136- /// Node type constraint (None = wildcard).
137- pub node_type : Option < NonZeroU16 > ,
137+ /// Node type constraint (Any = wildcard, Named/Anonymous for specific checks ).
138+ pub node_type : NodeTypeIR ,
138139 /// Field constraint (None = wildcard).
139140 pub node_field : Option < NonZeroU16 > ,
140141 /// Whether this is Match8 (no payload) or extended.
@@ -153,18 +154,23 @@ impl<'a> Match<'a> {
153154 ///
154155 /// The slice must start at the instruction and contain at least
155156 /// the full instruction size (determined by opcode).
157+ ///
158+ /// Header byte layout: `segment(2) | node_kind(2) | opcode(4)`
156159 #[ inline]
157160 pub fn from_bytes ( bytes : & ' a [ u8 ] ) -> Self {
158161 debug_assert ! ( bytes. len( ) >= 8 , "Match instruction too short" ) ;
159162
160163 let type_id_byte = bytes[ 0 ] ;
161- let segment = type_id_byte >> 4 ;
162- debug_assert ! ( segment == 0 , "non-zero segment not yet supported" ) ;
164+ // Header byte: segment(2) | node_kind(2) | opcode(4)
165+ let segment = ( type_id_byte >> 6 ) & 0x3 ;
166+ let node_kind = ( type_id_byte >> 4 ) & 0x3 ;
163167 let opcode = Opcode :: from_u8 ( type_id_byte & 0xF ) ;
168+ debug_assert ! ( segment == 0 , "non-zero segment not yet supported" ) ;
164169 debug_assert ! ( opcode. is_match( ) , "expected Match opcode" ) ;
165170
166171 let nav = Nav :: from_byte ( bytes[ 1 ] ) ;
167- let node_type = NonZeroU16 :: new ( u16:: from_le_bytes ( [ bytes[ 2 ] , bytes[ 3 ] ] ) ) ;
172+ let node_type_val = u16:: from_le_bytes ( [ bytes[ 2 ] , bytes[ 3 ] ] ) ;
173+ let node_type = NodeTypeIR :: from_bytes ( node_kind, node_type_val) ;
168174 let node_field = NonZeroU16 :: new ( u16:: from_le_bytes ( [ bytes[ 4 ] , bytes[ 5 ] ] ) ) ;
169175
170176 let ( is_match8, match8_next, pre_count, neg_count, post_count, succ_count) =
@@ -207,7 +213,7 @@ impl<'a> Match<'a> {
207213 /// Check if this is an epsilon transition (no node interaction).
208214 #[ inline]
209215 pub fn is_epsilon ( & self ) -> bool {
210- self . nav == Nav :: Stay && self . node_type . is_none ( ) && self . node_field . is_none ( )
216+ self . nav == Nav :: Epsilon
211217 }
212218
213219 /// Number of successors.
@@ -282,7 +288,7 @@ impl<'a> Match<'a> {
282288/// Call instruction for invoking definitions (recursion).
283289#[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
284290pub struct Call {
285- /// Segment index (0-15 ).
291+ /// Segment index (0-3 ).
286292 pub ( crate ) segment : u8 ,
287293 /// Navigation to apply before jumping to target.
288294 pub ( crate ) nav : Nav ,
@@ -307,14 +313,17 @@ impl Call {
307313 }
308314
309315 /// Decode from 8-byte bytecode.
316+ ///
317+ /// Header byte layout: `segment(2) | node_kind(2) | opcode(4)`
318+ /// For Call, node_kind bits are ignored (always 0).
310319 pub ( crate ) fn from_bytes ( bytes : [ u8 ; 8 ] ) -> Self {
311320 let type_id_byte = bytes[ 0 ] ;
312- let segment = type_id_byte >> 4 ;
321+ let segment = ( type_id_byte >> 6 ) & 0x3 ;
322+ let opcode = Opcode :: from_u8 ( type_id_byte & 0xF ) ;
313323 assert ! (
314324 segment == 0 ,
315325 "non-zero segment not yet supported: {segment}"
316326 ) ;
317- let opcode = Opcode :: from_u8 ( type_id_byte & 0xF ) ;
318327 assert_eq ! ( opcode, Opcode :: Call , "expected Call opcode" ) ;
319328
320329 Self {
@@ -327,9 +336,12 @@ impl Call {
327336 }
328337
329338 /// Encode to 8-byte bytecode.
339+ ///
340+ /// Header byte layout: `segment(2) | node_kind(2) | opcode(4)`
330341 pub fn to_bytes ( & self ) -> [ u8 ; 8 ] {
331342 let mut bytes = [ 0u8 ; 8 ] ;
332- bytes[ 0 ] = ( self . segment << 4 ) | ( Opcode :: Call as u8 ) ;
343+ // node_kind = 0 for Call
344+ bytes[ 0 ] = ( self . segment << 6 ) | ( Opcode :: Call as u8 ) ;
333345 bytes[ 1 ] = self . nav . to_byte ( ) ;
334346 bytes[ 2 ..4 ] . copy_from_slice ( & self . node_field . map_or ( 0 , |v| v. get ( ) ) . to_le_bytes ( ) ) ;
335347 bytes[ 4 ..6 ] . copy_from_slice ( & self . next . get ( ) . to_le_bytes ( ) ) ;
@@ -354,7 +366,7 @@ impl Call {
354366/// Return instruction for returning from definitions.
355367#[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
356368pub struct Return {
357- /// Segment index (0-15 ).
369+ /// Segment index (0-3 ).
358370 pub ( crate ) segment : u8 ,
359371}
360372
@@ -365,23 +377,29 @@ impl Return {
365377 }
366378
367379 /// Decode from 8-byte bytecode.
380+ ///
381+ /// Header byte layout: `segment(2) | node_kind(2) | opcode(4)`
382+ /// For Return, node_kind bits are ignored (always 0).
368383 pub ( crate ) fn from_bytes ( bytes : [ u8 ; 8 ] ) -> Self {
369384 let type_id_byte = bytes[ 0 ] ;
370- let segment = type_id_byte >> 4 ;
385+ let segment = ( type_id_byte >> 6 ) & 0x3 ;
386+ let opcode = Opcode :: from_u8 ( type_id_byte & 0xF ) ;
371387 assert ! (
372388 segment == 0 ,
373389 "non-zero segment not yet supported: {segment}"
374390 ) ;
375- let opcode = Opcode :: from_u8 ( type_id_byte & 0xF ) ;
376391 assert_eq ! ( opcode, Opcode :: Return , "expected Return opcode" ) ;
377392
378393 Self { segment }
379394 }
380395
381396 /// Encode to 8-byte bytecode.
397+ ///
398+ /// Header byte layout: `segment(2) | node_kind(2) | opcode(4)`
382399 pub fn to_bytes ( & self ) -> [ u8 ; 8 ] {
383400 let mut bytes = [ 0u8 ; 8 ] ;
384- bytes[ 0 ] = ( self . segment << 4 ) | ( Opcode :: Return as u8 ) ;
401+ // node_kind = 0 for Return
402+ bytes[ 0 ] = ( self . segment << 6 ) | ( Opcode :: Return as u8 ) ;
385403 // bytes[1..8] are reserved/padding
386404 bytes
387405 }
@@ -400,7 +418,7 @@ impl Default for Return {
400418/// the entry preamble: `Obj → Trampoline → EndObj → Accept`.
401419#[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
402420pub struct Trampoline {
403- /// Segment index (0-15 ).
421+ /// Segment index (0-3 ).
404422 pub ( crate ) segment : u8 ,
405423 /// Return address (where to continue after entrypoint returns).
406424 pub ( crate ) next : StepId ,
@@ -413,14 +431,17 @@ impl Trampoline {
413431 }
414432
415433 /// Decode from 8-byte bytecode.
434+ ///
435+ /// Header byte layout: `segment(2) | node_kind(2) | opcode(4)`
436+ /// For Trampoline, node_kind bits are ignored (always 0).
416437 pub ( crate ) fn from_bytes ( bytes : [ u8 ; 8 ] ) -> Self {
417438 let type_id_byte = bytes[ 0 ] ;
418- let segment = type_id_byte >> 4 ;
439+ let segment = ( type_id_byte >> 6 ) & 0x3 ;
440+ let opcode = Opcode :: from_u8 ( type_id_byte & 0xF ) ;
419441 assert ! (
420442 segment == 0 ,
421443 "non-zero segment not yet supported: {segment}"
422444 ) ;
423- let opcode = Opcode :: from_u8 ( type_id_byte & 0xF ) ;
424445 assert_eq ! ( opcode, Opcode :: Trampoline , "expected Trampoline opcode" ) ;
425446
426447 Self {
@@ -430,9 +451,12 @@ impl Trampoline {
430451 }
431452
432453 /// Encode to 8-byte bytecode.
454+ ///
455+ /// Header byte layout: `segment(2) | node_kind(2) | opcode(4)`
433456 pub fn to_bytes ( & self ) -> [ u8 ; 8 ] {
434457 let mut bytes = [ 0u8 ; 8 ] ;
435- bytes[ 0 ] = ( self . segment << 4 ) | ( Opcode :: Trampoline as u8 ) ;
458+ // node_kind = 0 for Trampoline
459+ bytes[ 0 ] = ( self . segment << 6 ) | ( Opcode :: Trampoline as u8 ) ;
436460 // bytes[1] is padding
437461 bytes[ 2 ..4 ] . copy_from_slice ( & self . next . get ( ) . to_le_bytes ( ) ) ;
438462 // bytes[4..8] are reserved/padding
0 commit comments