schemurai 3.0.1 → 3.0.2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/ext/schemurai_native/Cargo.lock +48 -1
  4. data/ext/schemurai_native/Cargo.toml +3 -1
  5. data/ext/schemurai_native/extconf.rb +1 -1
  6. data/ext/schemurai_native/glue.c +1679 -62
  7. data/ext/schemurai_native/protocol.def +45 -0
  8. data/ext/schemurai_native/src/budget.rs +49 -0
  9. data/ext/schemurai_native/src/container.rs +460 -0
  10. data/ext/schemurai_native/src/content.rs +56 -27
  11. data/ext/schemurai_native/src/diagnostics/array.rs +392 -0
  12. data/ext/schemurai_native/src/diagnostics/object.rs +218 -0
  13. data/ext/schemurai_native/src/diagnostics.rs +1087 -307
  14. data/ext/schemurai_native/src/enumeration.rs +6 -1
  15. data/ext/schemurai_native/src/evaluation.rs +49 -20
  16. data/ext/schemurai_native/src/format.rs +8 -6
  17. data/ext/schemurai_native/src/graph.rs +37 -0
  18. data/ext/schemurai_native/src/instance_graph.rs +90 -0
  19. data/ext/schemurai_native/src/lib.rs +910 -237
  20. data/ext/schemurai_native/src/memo.rs +11 -38
  21. data/ext/schemurai_native/src/number/arbitrary.rs +154 -0
  22. data/ext/schemurai_native/src/number.rs +250 -59
  23. data/ext/schemurai_native/src/pattern.rs +113 -101
  24. data/ext/schemurai_native/src/pointer.rs +97 -0
  25. data/ext/schemurai_native/src/runtime/properties.rs +162 -0
  26. data/ext/schemurai_native/src/runtime/reports.rs +266 -0
  27. data/ext/schemurai_native/src/runtime/scopes.rs +430 -0
  28. data/ext/schemurai_native/src/runtime.rs +1020 -0
  29. data/ext/schemurai_native/src/scope.rs +60 -16
  30. data/ext/schemurai_native/src/string.rs +68 -0
  31. data/ext/schemurai_native/src/tracking.rs +244 -174
  32. data/lib/schemurai/container_checks/array_diagnostics.rb +119 -0
  33. data/lib/schemurai/container_checks/object_diagnostics.rb +152 -0
  34. data/lib/schemurai/container_checks.rb +534 -0
  35. data/lib/schemurai/decimal.rb +11 -0
  36. data/lib/schemurai/dialect.rb +0 -12
  37. data/lib/schemurai/ecma_regexp.rb +46 -0
  38. data/lib/schemurai/evaluation_pool.rb +66 -0
  39. data/lib/schemurai/evaluator.rb +9 -48
  40. data/lib/schemurai/json_pointer.rb +11 -0
  41. data/lib/schemurai/native/diagnostics.rb +4 -3
  42. data/lib/schemurai/native/evaluator.rb +38 -10
  43. data/lib/schemurai/native/null_numeric.rb +23 -0
  44. data/lib/schemurai/number_checks.rb +128 -0
  45. data/lib/schemurai/string_checks.rb +166 -0
  46. data/lib/schemurai/type_checks.rb +59 -0
  47. data/lib/schemurai/value_equality.rb +72 -0
  48. data/lib/schemurai/version.rb +1 -1
  49. data/lib/schemurai/vm/compiler.rb +18 -26
  50. data/lib/schemurai/vm/evaluator.rb +87 -545
  51. data/lib/schemurai/vm/limited_evaluator.rb +7 -22
  52. metadata +24 -2
@@ -92,6 +92,7 @@ mod tests {
92
92
  #[derive(Clone, Copy, Debug)]
93
93
  enum ReferenceKind {
94
94
  Static,
95
+ InvariantDynamic(usize),
95
96
  Recursive,
96
97
  Dynamic(usize),
97
98
  }
@@ -117,11 +118,23 @@ impl Reference {
117
118
  _ => None,
118
119
  }
119
120
  }
121
+ pub(super) fn callback_dynamic_target(self) -> Option<(usize, usize)> {
122
+ match self.kind {
123
+ ReferenceKind::Dynamic(name) | ReferenceKind::InvariantDynamic(name) => {
124
+ Some((name, self.target))
125
+ }
126
+ _ => None,
127
+ }
128
+ }
120
129
  pub(super) fn recursive_target(self) -> Option<usize> {
121
130
  matches!(self.kind, ReferenceKind::Recursive).then_some(self.target)
122
131
  }
123
132
  pub(super) fn static_target(self) -> Option<usize> {
124
- matches!(self.kind, ReferenceKind::Static).then_some(self.target)
133
+ matches!(
134
+ self.kind,
135
+ ReferenceKind::Static | ReferenceKind::InvariantDynamic(_)
136
+ )
137
+ .then_some(self.target)
125
138
  }
126
139
  }
127
140
  impl Engine {
@@ -148,7 +161,7 @@ impl Engine {
148
161
  && let ReferenceKind::Dynamic(name) = reference.kind
149
162
  && invariant[name] == Some(reference.target)
150
163
  {
151
- reference.kind = ReferenceKind::Static;
164
+ reference.kind = ReferenceKind::InvariantDynamic(name);
152
165
  }
153
166
  }
154
167
  }
@@ -386,6 +399,14 @@ impl Engine {
386
399
  active
387
400
  }
388
401
  }
402
+ fn scope_binding(&self, reference: Reference, resource: Value) -> Option<usize> {
403
+ if let Some((name, _)) = reference.callback_dynamic_target() {
404
+ return self.dynamic_bindings.get(&(resource, name)).copied();
405
+ }
406
+ let &root = self.resources.get(&resource)?;
407
+ (reference.recursive_target().is_some() && self.metadata[root].recursive_anchor)
408
+ .then_some(root)
409
+ }
389
410
  pub(super) fn reference_target(&self, reference: Reference, context: Context<'_>) -> usize {
390
411
  if matches!(reference.kind, ReferenceKind::Dynamic(0)) && self.anchor_tables.len() == 1 {
391
412
  return context
@@ -398,23 +419,46 @@ impl Engine {
398
419
  // Linked frames walk inner to outer. Keep replacing a match so the
399
420
  // outermost matching resource wins, just as the VM's scope.each does.
400
421
  while let Some(frame) = current {
401
- match reference.kind {
402
- ReferenceKind::Static => break,
403
- ReferenceKind::Recursive => {
404
- if let Some(&root) = self.resources.get(&frame.resource)
405
- && self.metadata[root].recursive_anchor
406
- {
407
- target = root;
408
- }
409
- }
410
- ReferenceKind::Dynamic(name) => {
411
- if let Some(binding) = self.dynamic_bindings.get(&(frame.resource, name)) {
412
- target = *binding;
413
- }
414
- }
422
+ if reference.static_target().is_some() {
423
+ break;
424
+ }
425
+ if let Some(binding) = self.scope_binding(reference, frame.resource) {
426
+ target = binding;
415
427
  }
416
428
  current = frame.parent;
417
429
  }
418
430
  target
419
431
  }
420
432
  }
433
+
434
+ impl Execution<'_> {
435
+ pub(super) fn resolve_reference(
436
+ &self,
437
+ reference: Reference,
438
+ value: Value,
439
+ active: Context<'_>,
440
+ ) -> Result<usize, Verdict> {
441
+ if !self.caches.scopes_enabled() {
442
+ return Ok(self.engine.reference_target(reference, active));
443
+ }
444
+ let dynamic = reference.callback_dynamic_target();
445
+ let recursive = reference.recursive_target();
446
+ if dynamic.is_none() && recursive.is_none() {
447
+ return Ok(reference.static_target().expect("static reference"));
448
+ }
449
+ let mut index = 0;
450
+ while let Some(resource) = self.caches.scope_at(index) {
451
+ if self.caches.callback_checkpoint(value) != Valid {
452
+ return Err(Unsupported);
453
+ }
454
+ if let Some(target) = self.engine.scope_binding(reference, resource) {
455
+ return Ok(target);
456
+ }
457
+ index += 1;
458
+ }
459
+ Ok(dynamic
460
+ .map(|(_, fallback)| fallback)
461
+ .or(recursive)
462
+ .expect("scoped reference"))
463
+ }
464
+ }
@@ -0,0 +1,68 @@
1
+ //! Staged Ruby string semantics for values without safe native storage views.
2
+ use super::*;
3
+
4
+ impl StringRules {
5
+ pub(super) fn runtime_valid(
6
+ &self,
7
+ caches: &runtime::Caches,
8
+ required: i32,
9
+ value: Value,
10
+ ) -> Verdict {
11
+ caches
12
+ .string(self.source, value, required | self.runtime_flags)
13
+ .map_or(Unsupported, |frame| frame.step(0))
14
+ }
15
+ pub(super) fn runtime_failures(
16
+ &self,
17
+ caches: &runtime::Caches,
18
+ required: i32,
19
+ value: Value,
20
+ mut visit: impl FnMut(&'static str, Value, bool) -> Result<(), Verdict>,
21
+ ) -> Result<(), Verdict> {
22
+ let frame = caches.string(self.source, value, required | self.runtime_flags)?;
23
+ if !frame.predicate(1)? {
24
+ if required != 0 {
25
+ visit("type", frame.ordinal(), false)?;
26
+ }
27
+ return Ok(());
28
+ }
29
+ if !frame.predicate(2)? {
30
+ visit("pattern", frame.ordinal(), true)?;
31
+ return Ok(());
32
+ }
33
+ for (step, active, keyword) in [
34
+ (3, self.runtime_flags & 4 != 0, "maxLength"),
35
+ (4, self.runtime_flags & 8 != 0, "minLength"),
36
+ (5, self.pattern.is_some(), "pattern"),
37
+ (6, self.runtime_format, "format"),
38
+ (
39
+ 7,
40
+ self.content.is_some(),
41
+ if self.content.as_ref().is_some_and(|c| c.base64) {
42
+ "contentEncoding"
43
+ } else {
44
+ "contentMediaType"
45
+ },
46
+ ),
47
+ ] {
48
+ if active && !frame.predicate(step)? {
49
+ let invalid_pattern = frame.predicate(8 + step)?;
50
+ match visit(
51
+ if invalid_pattern { "pattern" } else { keyword },
52
+ frame.ordinal(),
53
+ invalid_pattern,
54
+ ) {
55
+ Err(Invalid) if !invalid_pattern => {
56
+ visit("pattern", frame.ordinal(), true)?;
57
+ return Ok(());
58
+ }
59
+ result => result?,
60
+ }
61
+ if invalid_pattern {
62
+ break;
63
+ }
64
+ }
65
+ }
66
+ Ok(())
67
+ }
68
+ }