packcr 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/packcr/generated/context.rb +8 -13
  4. data/lib/packcr/generated/node/action_node.rb +4 -6
  5. data/lib/packcr/generated/node/alternate_node.rb +11 -17
  6. data/lib/packcr/generated/node/capture_node.rb +1 -1
  7. data/lib/packcr/generated/node/charclass_node.rb +8 -8
  8. data/lib/packcr/generated/node/eof_node.rb +1 -1
  9. data/lib/packcr/generated/node/error_node.rb +1 -1
  10. data/lib/packcr/generated/node/expand_node.rb +1 -1
  11. data/lib/packcr/generated/node/predicate_node.rb +9 -7
  12. data/lib/packcr/generated/node/quantity_node.rb +16 -16
  13. data/lib/packcr/generated/node/reference_node.rb +3 -8
  14. data/lib/packcr/generated/node/rule_node.rb +6 -6
  15. data/lib/packcr/generated/node/sequence_node.rb +1 -1
  16. data/lib/packcr/generated/node/string_node.rb +28 -4
  17. data/lib/packcr/generator.rb +4 -3
  18. data/lib/packcr/node/action_node.rb +2 -2
  19. data/lib/packcr/node/alternate_node.rb +2 -2
  20. data/lib/packcr/node/capture_node.rb +2 -2
  21. data/lib/packcr/node/charclass_node.rb +15 -15
  22. data/lib/packcr/node/eof_node.rb +2 -2
  23. data/lib/packcr/node/error_node.rb +2 -2
  24. data/lib/packcr/node/expand_node.rb +2 -2
  25. data/lib/packcr/node/predicate_node.rb +3 -3
  26. data/lib/packcr/node/quantity_node.rb +4 -4
  27. data/lib/packcr/node/reference_node.rb +4 -4
  28. data/lib/packcr/node/rule_node.rb +2 -2
  29. data/lib/packcr/node/sequence_node.rb +2 -2
  30. data/lib/packcr/node/string_node.rb +17 -3
  31. data/lib/packcr/parser.rb +1 -1
  32. data/lib/packcr/templates/context/source.rs.erb +93 -91
  33. data/lib/packcr/templates/node/action.rs.erb +5 -5
  34. data/lib/packcr/templates/node/alternate.rs.erb +28 -29
  35. data/lib/packcr/templates/node/charclass_utf8.rs.erb +3 -3
  36. data/lib/packcr/templates/node/predicate_neg.rs.erb +6 -6
  37. data/lib/packcr/templates/node/quantity_many.rs.erb +55 -28
  38. data/lib/packcr/templates/node/reference.rs.erb +2 -2
  39. data/lib/packcr/templates/node/rule.rs.erb +20 -11
  40. data/lib/packcr/templates/node/string_many.rs.erb +4 -4
  41. data/lib/packcr/templates/node/string_many_reverse.rs.erb +7 -0
  42. data/lib/packcr/templates/node/string_one.rs.erb +3 -3
  43. data/lib/packcr/templates/node/string_one_reverse.rs.erb +6 -0
  44. data/lib/packcr/version.rb +1 -1
  45. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1797f847b90f8c53e2745592691b7f7ae12a5e18a1861f25b7e84825278529d
4
- data.tar.gz: f593a9234386b345f4af1de58467c31640ad2233918f3149f00d53c8df70c379
3
+ metadata.gz: ec849cdb4d638eb308cdefaf4a2e743ec49e71b46b7343265f8f8b78f5508c5a
4
+ data.tar.gz: d9c7e0db4c53e247edfb28ca9a6266364e0647152a202c92ca94bdf60ed0e5e0
5
5
  SHA512:
6
- metadata.gz: ba48fc2f71db11977fd9c1f12f520d639d9618383f08fcbe5b7e71930084f29f32e3fed2baac800ccedd8f3e50f026daf530636ebabd31e9bc682a4798e17b8e
7
- data.tar.gz: 1cad26bb87e543e4404df9f5e491398655e3fdc36dbe50452a6805229c06db196ba7c2c2878e461e595321376f00c65110ccba78dad3474f8039991cdff0fd9b
6
+ metadata.gz: d7b5ec64eb5ea1a407efb518ee0a169f7d0a24294e9d0924fbd7c9bf7a95fd20de13f0ccda290e8deea34b4745d08e07022576fa120dc58f2d81cb4c0e12ee4e
7
+ data.tar.gz: aa881736505df4e86e9a511b48941781e89a3618445e71a88034097624750e902edaa986ea0d875e537933034c4e0e12b5e8a971206732f2084f0b06d2db2b90
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- PackCR is a parser generator for C or Ruby.
5
+ PackCR is a parser generator for C, Ruby, and Rust.
6
6
  This library is a port of PackCC rewritten in ruby.
7
7
  The Original PackCC is https://github.com/arithy/packcc.
8
8
 
@@ -486,7 +486,7 @@ class Packcr
486
486
  erbout
487
487
  when :rs
488
488
  erbout = +""
489
- erbout << "/* A packrat parser generated by PackCR #{Packcr::VERSION} */\n\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet};\nuse std::io::Read;\nuse std::rc::Rc;\n\n".freeze
489
+ erbout << "/* A packrat parser generated by PackCR #{Packcr::VERSION} */\n\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet};\nuse std::io::Read;\nuse std::rc::Rc;\n".freeze
490
490
 
491
491
  if !code(:esource).empty?
492
492
  erbout << "\n".freeze
@@ -496,32 +496,27 @@ class Packcr
496
496
  end
497
497
  end
498
498
  use_value = @root.rules.map { |r| r.vars.size }.max > 0
499
- erbout << "\nstruct LrMemoTable {\n memos: HashMap<usize, LrMemoMap>,\n}\nimpl LrMemoTable {\n fn new() -> Self {\n Self {\n memos: HashMap::new(),\n }\n }\n\n fn clear(&mut self) {\n self.memos.clear();\n }\n\n fn set(&mut self, index: usize, rule: Rule, memo: LrMemo) {\n let memo_map = self.memos.entry(index).or_default();\n memo_map.insert(rule, memo);\n }\n\n fn get(&mut self, index: usize, rule: Rule) -> &mut LrMemo {\n self.memos.get_mut(&index).unwrap().get_mut(&rule).unwrap()\n }\n fn has(&mut self, index: usize, rule: Rule) -> bool {\n let memo_opt = self.memos.get_mut(&index);\n if memo_opt.is_none() {\n return false;\n }\n memo_opt.unwrap().contains_key(&rule)\n }\n}\n\nstruct LrMemo {\n offset: usize,\n answer: Option<Rc<RefCell<ThunkChunk>>>,\n grow: bool,\n}\n\nimpl LrMemo {\n fn new(offset: usize) -> Self {\n Self {\n offset,\n answer: None,\n grow: false,\n }\n }\n\n fn start_grow(&mut self) -> bool {\n if self.grow || self.answer.is_some() {\n return false;\n }\n self.answer = None;\n self.grow = true;\n true\n }\n\n fn start_match(&mut self, answer: Option<ThunkChunk>, offset: usize) {\n self.answer = answer.map(|c| Rc::new(RefCell::new(c)));\n self.offset = offset;\n }\n\n fn answer_as_deref_mut(&mut self) -> Option<Rc<RefCell<ThunkChunk>>> {\n self.answer.as_ref()?;\n self.answer.as_ref().map(Rc::clone)\n }\n}\n\nstruct ThunkChunk {\n thunks: Rc<RefCell<Vec<Thunk>>>,\n capts: CaptureTable,\n pos: usize,\n values: ValueTable,\n}\n\nimpl ThunkChunk {\n fn new(pos: usize) -> Self {\n Self {\n values: ValueTable::new(),\n capts: CaptureTable::new(),\n thunks: Rc::new(RefCell::new(Vec::new())),\n pos,\n }\n }\n\n fn push_leaf(\n &self,\n action: Action,\n end: usize,\n value_indices: &[usize],\n capt_indices: &[usize],\n ) {\n {\n let start = self.pos;\n let mut value_refs = HashMap::new();\n for &index in value_indices {\n value_refs.insert(index, ValueRef::new(index, self.values.clone()));\n }\n let mut capts = HashMap::new();\n for &index in capt_indices {\n capts.insert(index, self.capts[index].clone());\n }\n let leaf = Thunk::Leaf(ThunkLeaf::new(action, start, end, value_refs, capts));\n self.thunks.borrow_mut().push(leaf);\n }\n }\n\n fn value_ref(&self, index: usize) -> ValueRef {\n ValueRef::new(index, self.values.clone())\n }\n}\n\nenum Thunk {\n Leaf(ThunkLeaf),\n Node(ThunkNode),\n}\nimpl Thunk {\n fn do_action(&self, processor: &ThunkProcessor, value: ValueRef) {\n match self {\n Thunk::Leaf(leaf) => leaf.do_action(processor, value),\n Thunk::Node(node) => node.do_action(processor),\n }\n }\n}\n\n#[allow(dead_code)]\nstruct ThunkLeaf {\n value_refs: HashMap<usize, ValueRef>,\n capts: HashMap<usize, Capture>,\n capt0: Capture,\n action: Action,\n}\nimpl ThunkLeaf {\n fn new(\n action: Action,\n start: usize,\n end: usize,\n value_refs: HashMap<usize, ValueRef>,\n capts: HashMap<usize, Capture>,\n ) -> Self {\n Self {\n value_refs,\n capts,\n capt0: Capture { start, end },\n action,\n }\n }\n\n fn do_action(&self, processor: &ThunkProcessor, mut value: ValueRef) {\n value.with_mut(|v| {\n processor.call_action(self.action, self, v);\n });\n }\n".freeze
499
+ erbout << "\nstruct LrMemoTable {\n memos: HashMap<usize, LrMemoMap>,\n}\nimpl LrMemoTable {\n fn new() -> Self {\n Self {\n memos: HashMap::new(),\n }\n }\n\n fn clear(&mut self) {\n self.memos.clear();\n }\n\n fn set(&mut self, index: usize, rule: Rule, memo: LrMemo) {\n let memo_map = self.memos.entry(index).or_default();\n memo_map.insert(rule, memo);\n }\n\n fn get(&mut self, index: usize, rule: Rule) -> &mut LrMemo {\n self.memos.get_mut(&index).unwrap().get_mut(&rule).unwrap()\n }\n fn has(&self, index: usize, rule: Rule) -> bool {\n self.memos\n .get(&index)\n .is_some_and(|memo_map| memo_map.contains_key(&rule))\n }\n}\n\nstruct LrMemo {\n offset: usize,\n answer: Option<Rc<RefCell<ThunkChunk>>>,\n grow: bool,\n}\n\nimpl LrMemo {\n fn new(offset: usize) -> Self {\n Self {\n offset,\n answer: None,\n grow: false,\n }\n }\n\n fn start_grow(&mut self) -> bool {\n if !self.grow && self.answer.is_none() {\n self.grow = true;\n true\n } else {\n false\n }\n }\n\n fn update(&mut self, answer: Option<ThunkChunk>, offset: usize) {\n self.answer = answer.map(|c| Rc::new(RefCell::new(c)));\n self.offset = offset;\n }\n\n fn clone_answer(&mut self) -> Option<Rc<RefCell<ThunkChunk>>> {\n self.answer.as_ref().map(Rc::clone)\n }\n}\n\nstruct ThunkChunk {\n thunks: Rc<RefCell<Vec<Thunk>>>,\n capts: CaptureTable,\n pos: usize,\n values: ValueTable,\n}\n\nimpl ThunkChunk {\n fn new(pos: usize) -> Self {\n Self {\n values: ValueTable::new(),\n capts: CaptureTable::new(),\n thunks: Rc::new(RefCell::new(Vec::new())),\n pos,\n }\n }\n\n fn push_leaf(\n &self,\n action: Action,\n end: usize,\n value_indices: &[usize],\n capt_indices: &[usize],\n ) {\n {\n let start = self.pos;\n let mut value_refs = HashMap::new();\n for &index in value_indices {\n value_refs.insert(index, ValueRef::new(index, self.values.clone()));\n }\n let mut capts = HashMap::new();\n for &index in capt_indices {\n capts.insert(index, self.capts[index].clone());\n }\n let leaf = Thunk::Leaf(ThunkLeaf::new(action, start, end, value_refs, capts));\n self.thunks.borrow_mut().push(leaf);\n }\n }\n\n fn value_ref(&self, index: usize) -> ValueRef {\n ValueRef::new(index, self.values.clone())\n }\n}\n\nenum Thunk {\n Leaf(ThunkLeaf),\n Node(ThunkNode),\n}\nimpl Thunk {\n fn do_action(&self, processor: &ThunkProcessor, value: ValueRef) -> Value {\n match self {\n Thunk::Leaf(leaf) => leaf.do_action(processor, value),\n Thunk::Node(node) => node.do_action(processor),\n }\n }\n}\n\n#[allow(dead_code)]\nstruct ThunkLeaf {\n value_refs: HashMap<usize, ValueRef>,\n capts: HashMap<usize, Capture>,\n capt0: Capture,\n action: Action,\n}\nimpl ThunkLeaf {\n fn new(\n action: Action,\n start: usize,\n end: usize,\n value_refs: HashMap<usize, ValueRef>,\n capts: HashMap<usize, Capture>,\n ) -> Self {\n Self {\n value_refs,\n capts,\n capt0: Capture { start, end },\n action,\n }\n }\n\n fn do_action(&self, processor: &ThunkProcessor, mut value: ValueRef) -> Value {\n value.with_mut(|v| {\n processor.call_action(self.action, self, v);\n });\n value.get()\n }\n".freeze
500
500
 
501
501
  if use_value
502
502
  erbout << "\n fn values(&self) -> HashMap<usize, Value> {\n self.value_refs.iter().map(|(k, v)| (*k, v.get())).collect()\n }\n".freeze
503
503
  end
504
- erbout << "}\n\nstruct ThunkNode {\n thunks: Rc<RefCell<Vec<Thunk>>>,\n value: ValueRef,\n}\nimpl ThunkNode {\n fn do_action(&self, processor: &ThunkProcessor) {\n for thunk in self.thunks.borrow().iter() {\n thunk.do_action(processor, self.value.clone());\n }\n }\n}\n\n#[derive(Clone)]\nstruct Capture {\n start: usize,\n end: usize,\n}\n\ntype Value = i32;\n\nstruct ValueTable {\n table: Rc<RefCell<HashMap<usize, Value>>>,\n}\nimpl ValueTable {\n fn new() -> Self {\n Self {\n table: Rc::new(RefCell::new(HashMap::new())),\n }\n }\n".freeze
504
+ erbout << "}\n\nstruct ThunkNode {\n thunks: Rc<RefCell<Vec<Thunk>>>,\n value: ValueRef,\n}\nimpl ThunkNode {\n fn do_action(&self, processor: &ThunkProcessor) -> Value {\n let mut v = 0;\n for thunk in self.thunks.borrow_mut().iter_mut() {\n v = thunk.do_action(processor, self.value.clone());\n }\n v\n }\n}\n\n#[derive(Clone)]\nstruct Capture {\n start: usize,\n end: usize,\n}\n\ntype Value = i32;\n\nstruct ValueTable {\n table: Rc<RefCell<HashMap<usize, Value>>>,\n}\nimpl ValueTable {\n fn new() -> Self {\n Self {\n table: Rc::new(RefCell::new(HashMap::new())),\n }\n }\n".freeze
505
505
 
506
506
  if use_value
507
507
  erbout << "\n fn clear(&mut self) {\n self.table.borrow_mut().clear();\n }\n".freeze
508
508
  end
509
- erbout << "\n fn with_mut<F>(&mut self, index: usize, f: F)\n where\n F: FnOnce(&mut Value),\n {\n let mut table = self.table.borrow_mut();\n let value = table.entry(index).or_insert(0);\n f(value);\n }\n}\nimpl Clone for ValueTable {\n fn clone(&self) -> Self {\n Self {\n table: self.table.clone(),\n }\n }\n}\n\nstruct ValueRef {\n values: ValueTable,\n index: usize,\n}\nimpl ValueRef {\n fn new(index: usize, values: ValueTable) -> Self {\n Self { index, values }\n }\n\n fn with_mut<F>(&mut self, f: F)\n where\n F: FnOnce(&mut i32),\n {\n self.values.with_mut(self.index, f);\n }\n\n".freeze
510
-
511
- if use_value
512
- erbout << " fn get(&self) -> i32 {\n *self.values.table.borrow().get(&self.index).unwrap_or(&0)\n }\n".freeze
513
- end
514
- erbout << "}\nimpl Clone for ValueRef {\n fn clone(&self) -> Self {\n Self {\n index: self.index,\n values: self.values.clone(),\n }\n }\n}\n\nstruct CaptureTable {\n table: HashMap<usize, Capture>,\n len: usize,\n}\n\ntype RuleSet = HashSet<Rule>;\n\ntype LrMemoMap = HashMap<Rule, LrMemo>;\n\nimpl CaptureTable {\n fn new() -> Self {\n Self {\n table: HashMap::new(),\n len: 0,\n }\n }\n\n fn resize(&mut self, len: usize) {\n let current_len = self.len;\n if len > current_len {\n for i in current_len..len {\n self.table.insert(i, Capture { start: 0, end: 0 });\n }\n } else if len < current_len {\n for i in len..current_len {\n self.table.remove(&i);\n }\n }\n self.len = len;\n }\n}\nimpl std::ops::Index<usize> for CaptureTable {\n type Output = Capture;\n\n fn index(&self, index: usize) -> &Self::Output {\n &self.table[&index]\n }\n}\nimpl std::ops::IndexMut<usize> for CaptureTable {\n fn index_mut(&mut self, index: usize) -> &mut Self::Output {\n if self.len <= index {\n self.resize(index + 1);\n }\n self.table.get_mut(&index).unwrap()\n }\n}\n\nstruct Input {\n input: Box<dyn std::io::Read>,\n start_position: usize,\n position_offset: usize,\n buffer: String,\n}\n\nimpl Input {\n fn new(input: impl std::io::Read + 'static) -> Self {\n Self {\n input: Box::new(input),\n start_position: 0,\n position_offset: 0,\n buffer: String::new(),\n }\n }\n\n fn refill_buffer(&mut self, num: usize) -> usize {\n let mut len = self.buffer.len();\n if len >= self.position_offset + num {\n return len - self.position_offset;\n }\n\n let mut input_buffer = [0u8; 1024];\n\n while len < self.position_offset + num {\n match self.input.read(&mut input_buffer) {\n Ok(0) => break,\n Ok(bytes_read) => {\n let s = std::string::String::from_utf8_lossy(&input_buffer[..bytes_read]);\n self.buffer.push_str(&s);\n }\n Err(_) => break,\n }\n len = self.buffer.len();\n }\n\n len - self.position_offset\n }\n\n fn commit_buffer(&mut self) {\n let position_offset = self.position_offset;\n\n self.buffer.drain(..position_offset);\n\n self.start_position += position_offset;\n self.position_offset = 0;\n }\n\n #[allow(dead_code)]\n fn get_char_as_utf32(&mut self) -> (i32, usize) {\n if self.refill_buffer(1) < 1 {\n return (0, 0);\n }\n\n let current_position = self.position_offset;\n let remaining_chars: &str = &self.buffer[current_position..];\n\n if let Some(ch) = remaining_chars.chars().next() {\n let bytes_used = ch.len_utf8();\n\n if self.refill_buffer(bytes_used) < bytes_used {\n return (0, 0);\n }\n\n let utf32_value = ch as u32 as i32;\n\n return (utf32_value, bytes_used);\n }\n\n (0, 0)\n }\n\n fn back_to(&mut self, memo: &mut LrMemo) -> Option<Rc<RefCell<ThunkChunk>>> {\n self.position_offset = memo.offset;\n memo.answer_as_deref_mut()\n }\n}\n\nstruct #{class_name} {\n level: usize,\n memos: LrMemoTable,\n input: Input,\n}\n\nimpl #{class_name} {\n fn new(input: impl std::io::Read + 'static) -> Self {\n Self {\n level: 0,\n memos: LrMemoTable::new(),\n input: Input::new(input),\n }\n }\n\n fn error(&self) -> ! {\n eprintln!(\"Syntax error\");\n std::process::exit(1);\n }\n\n fn refill_buffer(&mut self, num: usize) -> usize {\n self.input.refill_buffer(num)\n }\n\n fn commit_buffer(&mut self) {\n self.input.commit_buffer();\n self.memos.clear();\n }\n\n fn parse(&mut self) -> bool {\n let mut answer = ThunkChunk::new(0);\n let pos = self.input.start_position;\n\n".freeze
509
+ erbout << "\n fn with_mut<F>(&mut self, index: usize, f: F)\n where\n F: FnOnce(&mut Value),\n {\n let mut table = self.table.borrow_mut();\n let value = table.entry(index).or_insert(0);\n f(value);\n }\n}\nimpl Clone for ValueTable {\n fn clone(&self) -> Self {\n Self {\n table: self.table.clone(),\n }\n }\n}\n\nstruct ValueRef {\n values: ValueTable,\n index: usize,\n}\nimpl ValueRef {\n fn new(index: usize, values: ValueTable) -> Self {\n Self { index, values }\n }\n\n fn with_mut<F>(&mut self, f: F)\n where\n F: FnOnce(&mut i32),\n {\n self.values.with_mut(self.index, f);\n }\n\n fn get(&self) -> i32 {\n *self.values.table.borrow().get(&self.index).unwrap_or(&0)\n }\n}\nimpl Clone for ValueRef {\n fn clone(&self) -> Self {\n Self {\n index: self.index,\n values: self.values.clone(),\n }\n }\n}\n\nstruct CaptureTable {\n table: HashMap<usize, Capture>,\n len: usize,\n}\n\ntype RuleSet = HashSet<Rule>;\ntype RuleLimit = Option<RuleSet>;\n\ntype LrMemoMap = HashMap<Rule, LrMemo>;\n\nimpl CaptureTable {\n fn new() -> Self {\n Self {\n table: HashMap::new(),\n len: 0,\n }\n }\n\n fn resize(&mut self, len: usize) {\n let current_len = self.len;\n if len > current_len {\n for i in current_len..len {\n self.table.insert(i, Capture { start: 0, end: 0 });\n }\n } else if len < current_len {\n for i in len..current_len {\n self.table.remove(&i);\n }\n }\n self.len = len;\n }\n}\nimpl std::ops::Index<usize> for CaptureTable {\n type Output = Capture;\n\n fn index(&self, index: usize) -> &Self::Output {\n &self.table[&index]\n }\n}\nimpl std::ops::IndexMut<usize> for CaptureTable {\n fn index_mut(&mut self, index: usize) -> &mut Self::Output {\n if self.len <= index {\n self.resize(index + 1);\n }\n self.table.get_mut(&index).unwrap()\n }\n}\n\nstruct Input {\n input: Box<dyn std::io::Read>,\n start_position: usize,\n position_offset: usize,\n buffer: String,\n closed: bool,\n}\n\nimpl Input {\n fn new(input: impl std::io::Read + 'static) -> Self {\n Self {\n input: Box::new(input),\n start_position: 0,\n position_offset: 0,\n buffer: String::new(),\n closed: false,\n }\n }\n\n fn refill_buffer(&mut self, num: usize) -> usize {\n let mut len = self.buffer.len();\n if len >= self.position_offset + num {\n return len - self.position_offset;\n }\n\n let mut input_buffer = [0u8; 1024];\n\n while len < self.position_offset + num {\n match self.input.read(&mut input_buffer) {\n Ok(0) => break,\n Ok(bytes_read) => {\n let s = std::string::String::from_utf8_lossy(&input_buffer[..bytes_read]);\n self.buffer.push_str(&s);\n }\n Err(_) => break,\n }\n len = self.buffer.len();\n }\n\n len - self.position_offset\n }\n\n fn commit_buffer(&mut self) {\n let position_offset = self.position_offset;\n\n self.buffer.drain(..position_offset);\n\n self.start_position += position_offset;\n self.position_offset = 0;\n }\n\n #[allow(dead_code)]\n fn get_char_as_utf32(&mut self) -> (i32, usize) {\n if self.refill_buffer(1) < 1 {\n return (0, 0);\n }\n\n let current_position = self.position_offset;\n let remaining_chars: &str = &self.buffer[current_position..];\n\n if let Some(ch) = remaining_chars.chars().next() {\n let bytes_used = ch.len_utf8();\n\n if self.refill_buffer(bytes_used) < bytes_used {\n return (0, 0);\n }\n\n let utf32_value = ch as u32 as i32;\n\n return (utf32_value, bytes_used);\n }\n\n (0, 0)\n }\n\n fn back_to(&mut self, memo: &mut LrMemo) -> Option<Rc<RefCell<ThunkChunk>>> {\n self.position_offset = memo.offset;\n memo.clone_answer()\n }\n}\n\nconst NOP: Result<usize, usize> = Ok(0);\nconst fn throw(label: usize) -> Result<usize, usize> {\n Err(label)\n}\n\nfn catch(label: usize, f: impl FnOnce() -> Result<usize, usize>) -> Result<usize, usize> {\n match f() {\n Ok(_) => NOP,\n Err(e) if e == label => NOP,\n Err(e) => throw(e),\n }\n}\n\nstruct #{class_name} {\n level: usize,\n memos: LrMemoTable,\n input: Input,\n}\n\nimpl #{class_name} {\n fn new(input: impl std::io::Read + 'static) -> Self {\n Self {\n level: 0,\n memos: LrMemoTable::new(),\n input: Input::new(input),\n }\n }\n\n fn parse(&mut self) -> Option<Value> {\n if self.input.closed {\n return None;\n }\n\n let mut answer = ThunkChunk::new(0);\n let pos = self.input.start_position;\n".freeze
515
510
 
516
511
  if !@root.rules.empty?
517
- erbout << " let apply_result = self.apply_rule(\n Rule::#{Packcr.camelize(@root.rules[0].name)},\n &mut answer,\n 0,\n self.input.position_offset,\n None,\n );\n\n if apply_result {\n if let Thunk::Node(node) = answer.thunks.borrow_mut().last().unwrap() {\n node.do_action(&ThunkProcessor::new(&self.input.buffer));\n }\n } else {\n self.error();\n }\n\n".freeze
512
+ erbout << "\n let value = {\n let node = self.rule_thunk_node(\n Rule::#{Packcr.camelize(@root.rules[0].name)},\n &mut answer,\n 0,\n self.input.position_offset,\n &None,\n );\n self.memos.clear();\n node.map(|node| node.do_action(&ThunkProcessor::new(&self.input.buffer)))\n };\n self.input.commit_buffer();\n if pos == self.input.start_position || self.input.refill_buffer(1) < 1 {\n self.input.closed = true;\n }\n value\n".freeze
518
513
  end
519
- erbout << " self.commit_buffer();\n pos != self.input.start_position && self.refill_buffer(1) >= 1\n }\n\n #[allow(dead_code)]\n fn get_char_as_utf32(&mut self) -> (i32, usize) {\n self.input.get_char_as_utf32()\n }\n\n fn grow_lr(&mut self, rule: Rule, offset: usize) {\n loop {\n let old_offset = self.input.position_offset;\n self.input.position_offset = offset;\n\n let answer = self.call_rule(rule, offset, Some(RuleSet::new()));\n if answer.is_none() || self.input.position_offset <= old_offset {\n return;\n }\n\n let memo = self.memos.get(offset, rule);\n memo.start_match(answer, self.input.position_offset);\n }\n }\n\n fn rule_answer(&mut self, rule: Rule) -> Option<Rc<RefCell<ThunkChunk>>> {\n let offset = self.input.position_offset;\n if !self.memos.has(offset, rule) {\n let memo = LrMemo::new(offset);\n self.memos.set(offset, rule, memo);\n let answer = self.call_rule(rule, offset, None);\n\n let memo = self.memos.get(offset, rule);\n memo.start_match(answer, self.input.position_offset);\n if !memo.grow {\n return self.input.back_to(memo);\n }\n self.grow_lr(rule, offset);\n\n let memo = self.memos.get(offset, rule);\n memo.grow = false;\n return self.input.back_to(memo);\n }\n\n let memo = self.memos.get(offset, rule);\n if memo.start_grow() {\n return None;\n }\n self.input.back_to(memo)\n }\n\n fn rule_answer_with_limits(\n &mut self,\n rule: Rule,\n limits: RuleSet,\n ) -> Option<Rc<RefCell<ThunkChunk>>> {\n let offset = self.input.position_offset;\n let answer = self.call_rule(rule, offset, Some(limits));\n if !self.memos.has(offset, rule) {\n answer.as_ref()?;\n return Some(Rc::new(RefCell::new(answer.unwrap())));\n }\n let memo = self.memos.get(offset, rule);\n\n if self.input.position_offset > memo.offset {\n memo.start_match(answer, self.input.position_offset);\n return memo.answer_as_deref_mut();\n }\n\n self.input.back_to(memo)\n }\n\n fn apply_rule(\n &mut self,\n rule: Rule,\n parent: &mut ThunkChunk,\n value_index: usize,\n offset: usize,\n limits: Option<RuleSet>,\n ) -> bool {\n let answer = match &limits {\n Some(limit_set)\n if self.input.position_offset == offset && !limit_set.contains(&rule) =>\n {\n self.rule_answer_with_limits(rule, limits.unwrap())\n }\n _ => self.rule_answer(rule),\n };\n\n let Some(answer) = answer else {\n return false;\n };\n\n let new_node = Thunk::Node(ThunkNode {\n thunks: answer.borrow().thunks.clone(),\n value: parent.value_ref(value_index),\n });\n parent.thunks.borrow_mut().push(new_node);\n\n true\n }\n\n fn call_rule(\n &mut self,\n rule: Rule,\n offset: usize,\n mut limits: Option<RuleSet>,\n ) -> Option<ThunkChunk> {\n if let Some(ref mut limits) = limits {\n limits.insert(rule);\n }\n match rule {\n".freeze
514
+ erbout << " }\n\n fn grow_lr(&mut self, rule: Rule, offset: usize) {\n loop {\n let old_offset = self.input.position_offset;\n self.input.position_offset = offset;\n\n let answer = self.call_rule(rule, offset, Some(RuleSet::new()));\n match answer {\n Some(answer) if self.input.position_offset > old_offset => {\n let memo = self.memos.get(offset, rule);\n memo.update(Some(answer), self.input.position_offset);\n }\n _ => {\n return;\n }\n }\n }\n }\n\n fn rule_answer_without_limits(&mut self, rule: Rule) -> Option<Rc<RefCell<ThunkChunk>>> {\n let offset = self.input.position_offset;\n if !self.memos.has(offset, rule) {\n let memo = LrMemo::new(offset);\n self.memos.set(offset, rule, memo);\n let answer = self.call_rule(rule, offset, None);\n\n let memo = self.memos.get(offset, rule);\n memo.update(answer, self.input.position_offset);\n if !memo.grow {\n return self.input.back_to(memo);\n }\n self.grow_lr(rule, offset);\n\n let memo = self.memos.get(offset, rule);\n memo.grow = false;\n return self.input.back_to(memo);\n }\n\n let memo = self.memos.get(offset, rule);\n if memo.start_grow() {\n return None;\n }\n self.input.back_to(memo)\n }\n\n fn rule_answer_with_limits(\n &mut self,\n rule: Rule,\n limits: RuleSet,\n ) -> Option<Rc<RefCell<ThunkChunk>>> {\n let offset = self.input.position_offset;\n let answer = self.call_rule(rule, offset, Some(limits));\n if !self.memos.has(offset, rule) {\n return answer.map(|answer| Rc::new(RefCell::new(answer)));\n }\n\n let memo = self.memos.get(offset, rule);\n if self.input.position_offset > memo.offset {\n memo.update(answer, self.input.position_offset);\n }\n self.input.back_to(memo)\n }\n\n fn apply_rule(\n &mut self,\n rule: Rule,\n parent: &mut ThunkChunk,\n value_index: usize,\n offset: usize,\n limits: &RuleLimit,\n ) -> bool {\n let node = self.rule_thunk_node(rule, parent, value_index, offset, limits);\n node.is_some_and(|node| {\n parent.thunks.borrow_mut().push(Thunk::Node(node));\n true\n })\n }\n\n fn rule_thunk_node(\n &mut self,\n rule: Rule,\n parent: &ThunkChunk,\n value_index: usize,\n offset: usize,\n limits: &RuleLimit,\n ) -> Option<ThunkNode> {\n match limits {\n Some(limit_set)\n if self.input.position_offset == offset && !limit_set.contains(&rule) =>\n {\n self.rule_answer_with_limits(rule, limits.clone().unwrap())\n }\n _ => self.rule_answer_without_limits(rule),\n }\n .map(|answer| ThunkNode {\n thunks: answer.borrow().thunks.clone(),\n value: parent.value_ref(value_index),\n })\n }\n\n fn call_rule(\n &mut self,\n rule: Rule,\n offset: usize,\n mut limits: RuleLimit,\n ) -> Option<ThunkChunk> {\n if let Some(ref mut limits) = limits {\n limits.insert(rule);\n }\n match rule {\n".freeze
520
515
 
521
516
  @root.rules.each do |rule|
522
517
  erbout << " Rule::#{Packcr.camelize(rule.name)} => self.evaluate_rule_#{rule.name}(offset, limits),\n".freeze
523
518
  end
524
- erbout << " }\n }\n\n".freeze
519
+ erbout << " }\n }\n".freeze
525
520
 
526
521
  @root.rules.each do |rule|
527
522
  erbout << "\n".freeze
@@ -541,7 +536,7 @@ class Packcr
541
536
 
542
537
  @root.rules.each do |rule|
543
538
  rule.codes.each do |code|
544
- erbout << "\n #[allow(unused_variables,non_snake_case)]\n fn action_#{rule.name}_#{code.index}(&self, leaf: &ThunkLeaf, out: &mut i32) {\n".freeze
539
+ erbout << "\n #[allow(unused_variables, non_snake_case)]\n fn action_#{rule.name}_#{code.index}(&self, leaf: &ThunkLeaf, out: &mut i32) {\n".freeze
545
540
 
546
541
  code.vars.each_with_index do |ref, i|
547
542
  if i == 0
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class ActionNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -55,17 +55,15 @@ class Packcr
55
55
  erbout
56
56
  when :rs
57
57
  erbout = +""
58
- erbout << "answer.push_leaf(\n Action::#{Packcr.camelize(gen.rule.name)}#{index},\n self.input.position_offset,\n &[".freeze
59
-
58
+ erbout << "answer.push_leaf(Action::#{Packcr.camelize(gen.rule.name)}#{index}, self.input.position_offset, &[".freeze
60
59
  vars.each_with_index do |var, i|
61
60
  erbout << "#{", " if i > 0}#{var.index}".freeze
62
61
  end
63
- erbout << "],\n &[".freeze
64
-
62
+ erbout << "], &[".freeze
65
63
  capts.each_with_index do |capt, i|
66
64
  erbout << "#{", " if i > 0}#{capt.index}".freeze
67
65
  end
68
- erbout << "],\n);\n".freeze
66
+ erbout << "]);\n".freeze
69
67
 
70
68
  erbout
71
69
  else
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class AlternateNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -92,47 +92,41 @@ class Packcr
92
92
  when :rs
93
93
  erbout = +""
94
94
  m = gen.next_label
95
- erbout << "'L#{format("%04d", m)}: {\n let p = self.input.position_offset;\n".freeze
95
+ erbout << "catch(#{m}, || {\n let p = self.input.position_offset;\n".freeze
96
96
 
97
97
  if gen.location
98
98
  erbout << " TODO\n".freeze
99
99
  end
100
100
  nodes.each_with_index do |expr, i|
101
- erbout << " {\n".freeze
102
-
103
101
  c = i + 1 < nodes.length
104
102
  if expr.reversible?(gen)
105
103
 
106
- erbout << "#{gen.generate_code(expr, m, 8, false, reverse: true, oncut: onfail)}".freeze
104
+ erbout << "#{gen.generate_code(expr, m, 4, false, reverse: true, oncut: onfail)}".freeze
107
105
  else
108
106
  l = gen.next_label
109
- erbout << " 'L#{format("%04d", l)}: {\n".freeze
110
-
111
107
  r = expr.reachability
112
-
113
- erbout << "#{gen.generate_code(expr, l, 12, false, oncut: onfail)}".freeze
114
108
  if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
109
+ erbout << " catch(#{l}, || {\n#{gen.generate_code(expr, l, 8, false, oncut: onfail)}".freeze
115
110
  if c
116
- erbout << " // unreachable codes omitted\n".freeze
111
+ erbout << " // unreachable codes omitted\n".freeze
117
112
  end
118
- erbout << " }\n".freeze
113
+ erbout << " NOP\n })?\n".freeze
119
114
 
120
115
  break
121
- elsif r == Packcr::CODE_REACH__BOTH
122
- erbout << " break 'L#{format("%04d", m)};\n".freeze
116
+ else
117
+ erbout << " catch(#{l}, || {\n#{gen.generate_code(expr, l, 8, false, oncut: onfail)} throw(#{m})\n })?;\n".freeze
123
118
  end
124
- erbout << " }\n".freeze
125
119
  end
126
- erbout << " }\n self.input.position_offset = p;\n".freeze
120
+ erbout << " self.input.position_offset = p;\n".freeze
127
121
 
128
122
  if gen.location
129
123
  erbout << " TODO\n".freeze
130
124
  end
131
125
  next if c
132
126
 
133
- erbout << " break 'L#{format("%04d", onfail)};\n".freeze
127
+ erbout << " throw(#{onfail})\n".freeze
134
128
  end
135
- erbout << "} // 'L#{format("%04d", m)}\n".freeze
129
+ erbout << "})?;\n".freeze
136
130
 
137
131
  erbout
138
132
  else
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class CaptureNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class CharclassNode
4
- def get_code(gen, onfail, indent, bare, charclass, n, a)
4
+ def get_code(gen, onfail, indent, unwrap, charclass, n, a)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -97,7 +97,7 @@ class Packcr
97
97
  end
98
98
  end
99
99
 
100
- def get_any_code(gen, onfail, indent, bare, charclass)
100
+ def get_any_code(gen, onfail, indent, unwrap, charclass)
101
101
  case gen.lang
102
102
  when :c
103
103
  erbout = +""
@@ -124,7 +124,7 @@ class Packcr
124
124
  end
125
125
  end
126
126
 
127
- def get_fail_code(gen, onfail, indent, bare)
127
+ def get_fail_code(gen, onfail, indent, unwrap)
128
128
  case gen.lang
129
129
  when :c
130
130
  erbout = +""
@@ -141,7 +141,7 @@ class Packcr
141
141
  end
142
142
  end
143
143
 
144
- def get_one_code(gen, onfail, indent, bare, charclass, n, a)
144
+ def get_one_code(gen, onfail, indent, unwrap, charclass, n, a)
145
145
  case gen.lang
146
146
  when :c
147
147
  erbout = +""
@@ -176,7 +176,7 @@ class Packcr
176
176
  end
177
177
  end
178
178
 
179
- def get_utf8_code(gen, onfail, indent, bare, charclass, n)
179
+ def get_utf8_code(gen, onfail, indent, unwrap, charclass, n)
180
180
  case gen.lang
181
181
  when :c
182
182
  erbout = +""
@@ -308,7 +308,7 @@ class Packcr
308
308
  a = charclass && charclass[0] == "^"
309
309
  i = a ? 1 : 0
310
310
  any_code = !charclass || (a && n == 1)
311
- erbout << "let (#{any_code ? "_" : ""}u, n) = self.get_char_as_utf32();\nif n == 0 {\n break 'L#{format("%04d", onfail)};\n}\n".freeze
311
+ erbout << "let (#{any_code ? "_" : ""}u, n) = self.input.get_char_as_utf32();\nif n == 0 {\n return throw(#{onfail});\n}\n".freeze
312
312
 
313
313
  unless any_code
314
314
  erbout << "if ".freeze
@@ -353,7 +353,7 @@ class Packcr
353
353
  erbout << ") ".freeze
354
354
  end
355
355
 
356
- erbout << "{\n break 'L#{format("%04d", onfail)};\n}\n".freeze
356
+ erbout << "{\n return throw(#{onfail});\n}\n".freeze
357
357
  end
358
358
  erbout << "self.input.position_offset += n;\n".freeze
359
359
 
@@ -363,7 +363,7 @@ class Packcr
363
363
  end
364
364
  end
365
365
 
366
- def get_utf8_reverse_code(gen, onsuccess, indent, bare, charclass, n)
366
+ def get_utf8_reverse_code(gen, onsuccess, indent, unwrap, charclass, n)
367
367
  case gen.lang
368
368
  when :rb
369
369
  erbout = +""
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class EofNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class ErrorNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class ExpandNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class PredicateNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -77,7 +77,7 @@ class Packcr
77
77
  end
78
78
  end
79
79
 
80
- def get_neg_code(gen, onfail, indent, bare, oncut)
80
+ def get_neg_code(gen, onfail, indent, unwrap, oncut)
81
81
  case gen.lang
82
82
  when :c
83
83
  erbout = +""
@@ -144,17 +144,19 @@ class Packcr
144
144
  if gen.location
145
145
  erbout << "TODO\n".freeze
146
146
  end
147
- erbout << "'L#{format("%04d", l)}: {\n {\n#{gen.generate_code(expr, l, 4, false)} }\n".freeze
148
-
149
- if r != Packcr::CODE_REACH__ALWAYS_FAIL
147
+ erbout << "catch(#{l}, || {\n#{gen.generate_code(expr, l, 4, false)}".freeze
148
+ if r == Packcr::CODE_REACH__ALWAYS_FAIL
149
+ erbout << " NOP\n".freeze
150
+ else
150
151
  erbout << " self.input.position_offset = p;\n".freeze
151
152
 
152
153
  if gen.location
153
154
  erbout << " TODO\n".freeze
154
155
  end
155
- erbout << " break 'L#{format("%04d", onfail)};\n".freeze
156
+ erbout << " throw(#{onfail})\n".freeze
157
+
156
158
  end
157
- erbout << "}\n".freeze
159
+ erbout << "})?;\n".freeze
158
160
 
159
161
  if r != Packcr::CODE_REACH__ALWAYS_SUCCEED
160
162
  erbout << "self.input.position_offset = p;\n".freeze
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class QuantityNode
4
- def get_many_code(gen, onfail, indent, bare, oncut)
4
+ def get_many_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -120,32 +120,32 @@ class Packcr
120
120
  erbout << "let mut i = -1;\n".freeze
121
121
  end
122
122
  m = gen.next_label
123
- erbout << "'L#{format("%04d", m)}: loop {\n".freeze
123
+ erbout << "catch(#{m}, || {\n loop {\n".freeze
124
124
 
125
125
  if use_count
126
- erbout << " i += 1;\n".freeze
126
+ erbout << " i += 1;\n".freeze
127
127
  end
128
128
  if max >= 0
129
- erbout << " if i >= #{max} { break; }\n".freeze
129
+ erbout << " if i >= #{max} {\n return NOP;\n }\n".freeze
130
130
  end
131
- erbout << " let p = self.input.position_offset;\n".freeze
131
+ erbout << " let p = self.input.position_offset;\n".freeze
132
132
 
133
133
  if (r != Packcr::CODE_REACH__ALWAYS_SUCCEED) && gen.location
134
- erbout << " TODO\n".freeze
134
+ erbout << " TODO\n".freeze
135
135
  end
136
136
  l = gen.next_label
137
137
  r = expr.reachability
138
- erbout << " 'L#{format("%04d", l)}: {\n#{gen.generate_code(expr, l, 8, false)} if self.input.position_offset == p {\n break 'L#{format("%04d", m)};\n }\n".freeze
138
+ if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
139
+ erbout << " TODO\n match (|| {\n#{gen.generate_code(expr, l, 12, false)} if self.input.position_offset == p {\n return throw(#{m});\n }\n })() {\n NOP => continue,\n Err(label) if label != #{l} => return throw(label),\n _ => {\n self.input.position_offset = p;\n".freeze
139
140
 
140
- if r != Packcr::CODE_REACH__ALWAYS_SUCCEED
141
- erbout << " continue 'L#{format("%04d", m)};\n }\n self.input.position_offset = p;\n".freeze
141
+ else
142
+ erbout << " match (|| {\n#{gen.generate_code(expr, l, 12, false)} if self.input.position_offset == p {\n return throw(#{m});\n }\n NOP\n })() {\n NOP => continue,\n Err(label) if label != #{l} => return throw(label),\n _ => {\n self.input.position_offset = p;\n".freeze
142
143
 
143
- if gen.location
144
- erbout << " TODO\n".freeze
145
- end
146
- erbout << " break 'L#{format("%04d", m)};\n".freeze
147
144
  end
148
- erbout << "}\n".freeze
145
+ if gen.location
146
+ erbout << " TODO\n".freeze
147
+ end
148
+ erbout << " return throw(#{m});\n }\n }\n }\n})?;\n".freeze
149
149
 
150
150
  if min > 0
151
151
  erbout << "if i < #{min} {\n self.input.position_offset = p0;\n".freeze
@@ -153,7 +153,7 @@ class Packcr
153
153
  if gen.location
154
154
  erbout << " TODO\n".freeze
155
155
  end
156
- erbout << " break 'L#{format("%04d", onfail)};\n}\n".freeze
156
+ erbout << " return throw(#{onfail});\n}\n".freeze
157
157
  end
158
158
  erbout
159
159
  else
@@ -161,7 +161,7 @@ class Packcr
161
161
  end
162
162
  end
163
163
 
164
- def get_one_code(gen, onfail, indent, bare, oncut)
164
+ def get_one_code(gen, onfail, indent, unwrap, oncut)
165
165
  case gen.lang
166
166
  when :c
167
167
  erbout = +""
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class ReferenceNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -39,7 +39,7 @@ class Packcr
39
39
  erbout
40
40
  when :rs
41
41
  erbout = +""
42
- erbout << "if !self.apply_rule(Rule::#{Packcr.camelize(name)}, &mut answer, #{index || 0}, offset, limits.clone()) {\n break 'L#{format("%04d", onfail)};\n}\n".freeze
42
+ erbout << "if !self.apply_rule(Rule::#{Packcr.camelize(name)}, &mut answer, #{index || 0}, offset, &limits) {\n return throw(#{onfail});\n}\n".freeze
43
43
 
44
44
  erbout
45
45
  else
@@ -47,7 +47,7 @@ class Packcr
47
47
  end
48
48
  end
49
49
 
50
- def get_reverse_code(gen, onsuccess, indent, bare, oncut)
50
+ def get_reverse_code(gen, onsuccess, indent, unwrap, oncut)
51
51
  case gen.lang
52
52
  when :rb
53
53
  erbout = +""
@@ -69,11 +69,6 @@ class Packcr
69
69
  erbout << ", offset_loc".freeze
70
70
  end
71
71
  erbout << ")\n throw(#{onsuccess})\n end\nend\n".freeze
72
- erbout
73
- when :rs
74
- erbout = +""
75
- erbout << "/* lib/packcr/templates/node/reference_reverse.rs.erb */\n\n".freeze
76
-
77
72
  erbout
78
73
  else
79
74
  raise "unknown lang #{gen.lang}"
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class RuleNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -59,12 +59,13 @@ class Packcr
59
59
  when :rs
60
60
  erbout = +""
61
61
  for_ref = has_ref ? "" : "_"
62
- erbout << "#[allow(non_snake_case)]\nfn evaluate_rule_#{name}(\n &mut self,\n #{for_ref}offset: usize,\n".freeze
62
+ erbout << "#[allow(non_snake_case)]\nfn evaluate_rule_#{name}(&mut self, #{for_ref}offset: usize, ".freeze
63
63
 
64
64
  if gen.location
65
65
  erbout << " TODO\n".freeze
66
66
  end
67
- erbout << " #{for_ref}limits: Option<RuleSet>,\n) -> Option<ThunkChunk> {\n let mut answer = ThunkChunk::new(self.input.position_offset);\n".freeze
67
+
68
+ erbout << "#{for_ref}limits: RuleLimit) -> Option<ThunkChunk> {\n let mut answer = ThunkChunk::new(self.input.position_offset);\n".freeze
68
69
 
69
70
  if gen.location
70
71
  erbout << " TODO\n".freeze
@@ -76,11 +77,10 @@ class Packcr
76
77
  end
77
78
  r = expr.reachability
78
79
  if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
79
-
80
- erbout << "#{gen.generate_code(expr, 0, 4, false)} self.level -= 1;\n return Some(answer);\n".freeze
80
+ erbout << " let _ = (|| {\n#{gen.generate_code(expr, 0, 8, false)} NOP\n })();\n self.level -= 1;\n Some(answer)\n".freeze
81
81
 
82
82
  else
83
- erbout << " 'L0000: {\n#{gen.generate_code(expr, 0, 8, false)} self.level -= 1;\n return Some(answer);\n }\n self.level -= 1;\n return None;\n".freeze
83
+ erbout << " match (|| {\n#{gen.generate_code(expr, 0, 8, false)} NOP\n })() {\n NOP => {\n self.level -= 1;\n Some(answer)\n }\n _ => {\n self.level -= 1;\n None\n }\n }\n".freeze
84
84
  end
85
85
  erbout << "}\n".freeze
86
86
 
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class SequenceNode
4
- def get_code(gen, onfail, indent, bare, oncut)
4
+ def get_code(gen, onfail, indent, unwrap, oncut)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class StringNode
4
- def get_many_code(gen, onfail, indent, bare, oncut, n)
4
+ def get_many_code(gen, onfail, indent, unwrap, oncut, n)
5
5
  case gen.lang
6
6
  when :c
7
7
  erbout = +""
@@ -30,7 +30,7 @@ class Packcr
30
30
  erbout
31
31
  when :rs
32
32
  erbout = +""
33
- erbout << "if self.refill_buffer(#{n}) < #{n}\n || self.input.buffer.as_bytes()[self.input.position_offset..(self.input.position_offset + #{n})] != [#{value[0, n].each_char.map { |c| "b'#{Packcr.escape_character(c)}'" }.join(", ")}]\n{\n break 'L#{format("%04d", onfail)};\n}\n".freeze
33
+ erbout << "if self.input.refill_buffer(#{n}) < #{n}\n || !self.input.buffer[self.input.position_offset..] .starts_with(\"#{value[0, n].each_char.map { |c| "#{Packcr.escape_character(c)}" }.join}\")\n{\n return throw(#{onfail});\n}\n".freeze
34
34
 
35
35
  if gen.location
36
36
  erbout << "TODO\n".freeze
@@ -43,7 +43,19 @@ class Packcr
43
43
  end
44
44
  end
45
45
 
46
- def get_one_code(gen, onfail, indent, bare, oncut, n)
46
+ def get_many_reverse_code(gen, onsuccess, indent, unwrap, oncut, n)
47
+ case gen.lang
48
+ when :rs
49
+ erbout = +""
50
+ erbout << "if self.input.refill_buffer(#{n}) >= #{n}\n && self.input.buffer[self.input.position_offset..].starts_with(\"#{value[0, n].each_char.map { |c| "#{Packcr.escape_character(c)}" }.join}\")\n{\n self.input.position_offset += #{n};\n return throw(#{onsuccess});\n}\n".freeze
51
+
52
+ erbout
53
+ else
54
+ raise "unknown lang #{gen.lang}"
55
+ end
56
+ end
57
+
58
+ def get_one_code(gen, onfail, indent, unwrap, oncut, n)
47
59
  case gen.lang
48
60
  when :c
49
61
  erbout = +""
@@ -67,7 +79,7 @@ class Packcr
67
79
  erbout
68
80
  when :rs
69
81
  erbout = +""
70
- erbout << "if self.refill_buffer(1) < 1\n || self.input.buffer.as_bytes()[self.input.position_offset] != b'#{Packcr.escape_character(value[0])}'\n{\n break 'L#{format("%04d", onfail)};\n}\n".freeze
82
+ erbout << "if self.input.refill_buffer(1) < 1\n || !self.input.buffer[self.input.position_offset..].starts_with(\"#{Packcr.escape_character(value[0])}\")\n{\n return throw(#{onfail});\n}\n".freeze
71
83
 
72
84
  if gen.location
73
85
  erbout << "TODO\n".freeze
@@ -79,6 +91,18 @@ class Packcr
79
91
  raise "unknown lang #{gen.lang}"
80
92
  end
81
93
  end
94
+
95
+ def get_one_reverse_code(gen, onsuccess, indent, unwrap, oncut, n)
96
+ case gen.lang
97
+ when :rs
98
+ erbout = +""
99
+ erbout << "if self.input.refill_buffer(1) >= 1\n && self.input.buffer[self.input.position_offset..].starts_with(\"#{Packcr.escape_character(value[0])}\")\n{\n self.input.position_offset += 1;\n return throw(#{onsuccess});\n}\n".freeze
100
+
101
+ erbout
102
+ else
103
+ raise "unknown lang #{gen.lang}"
104
+ end
105
+ end
82
106
  end
83
107
  end
84
108
  end
@@ -15,16 +15,17 @@ class Packcr
15
15
  @label += 1
16
16
  end
17
17
 
18
- def generate_code(node, onescape, indent, bare, reverse: false, oncut: nil)
18
+ def generate_code(node, onescape, indent, unwrap, reverse: false, oncut: nil)
19
19
  stream = @stream
20
20
  @stream = +""
21
21
  @level += 1
22
22
  begin
23
23
  if reverse
24
- node.generate_reverse_code(self, onescape, indent, bare, oncut: oncut)
24
+ code = node.generate_reverse_code(self, onescape, indent, unwrap, oncut: oncut)
25
25
  else
26
- node.generate_code(self, onescape, indent, bare, oncut: oncut)
26
+ code = node.generate_code(self, onescape, indent, unwrap, oncut: oncut)
27
27
  end
28
+ write Packcr.format_code(code, indent: indent, unwrap: unwrap)
28
29
  @stream
29
30
  ensure
30
31
  @level -= 1