Skip to content

Commit 5169069

Browse files
Phase F: triple-quoted strings, fixed-size arrays, imports, +25 stdlib
Pushes canonical .omc compatibility from 4 known-good files to 21/30 in a sampled sweep (70%). Targeted at real-world programs from the Python omnicc tree at Sovereign_Lattice/omninet_package/. ## Lexer / Parser - Triple-quoted """multi-line""" string literals. - Bare-string statement (docstring) at top-of-function position. Optional trailing `;`. Python idiom. - `//` line comments and `/* block */` comments alongside the canonical `#`. - Fixed-size array declaration `h[256] amplitudes;` lowers to `arr_new(256, 0)`. - Parameterized pragmas: `@unroll:16`, `@threads:64`, `@cache:L1` on both the line-prefix `@pragma[name]` and postfix `@name` forms. - `import core;` / `import core as c;` / `load "path";` at the parse level. Module resolution is a no-op for now — this just unblocks parsing of files that lead with import statements. ## Stdlib (~25 new) Math / constants: tau, phi_inv, phi_sq, phi_squared, sqrt_2, sqrt_5, ln_2, pow_int, square, cube, factorial (lenient on negatives), sign, is_prime (6k±1 trial division), even/is_even/odd/is_odd, polymorphic min(a,b) / min(arr) and max. φ-stdlib (matching Phase 6 std/*.omc surface): fib (alias for fibonacci), classify_resonance (returns int 0-3 bucket), filter_by_resonance(arr, threshold), ensure_clean(v) — pass through if not Singularity, else fold, cleanup_array(arr) — drop Singularity elements, collapse(amp, phase), harmonic_interfere(a, b), interfere(a, b) — harmonic mean, measure_coherence(a, b) — resonance-difference, arr_fold_elements(arr) — sum of Fibonacci-snapped elements. Safe arithmetic (Singularity-tolerant): safe_add, safe_sub, safe_mul — fold any Singularity input through Fibonacci snap before operating. ## Compatibility milestone Six canonical files now run end-to-end on Rust OMC: miner_nuclear.omc, test_phase7_features.omc, test_phase8_arrays.omc, test_array.omc, phi_field_llm.omc, hbit_hardware_overlay.omc. A 30-file sweep moved from 16 → 21 passing. Remaining gaps cluster in: - Bitwise ops (& | ^ << >>) — needed by crypto.omc - Block-style calls (parallel_for_threads(n) { ... }) — nuclear_optimization.omc - File I/O (file_write, etc.) — test_file_io.omc - Module-aware imports (resolving `wave` as a callable namespace) All deferred to their own phases. ## Tests 111 still passing. Nothing regressed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 393ad18 commit 5169069

3 files changed

Lines changed: 477 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,25 @@ All notable changes to OMNIcode will be documented in this file.
44

55
## [Unreleased]
66

7+
### Added (Phase F: syntax + stdlib alignment for canonical compat, 2026-05-13)
8+
Pushing the Rust interpreter's compatibility with real-world canonical `.omc` programs from 4/N to **21 of 30 (70%)** in a sampled sweep.
9+
10+
**Syntax / lexer:**
11+
- Triple-quoted `"""multi-line docstring"""` literals.
12+
- Docstring statements: bare string at statement position is a no-op (Python idiom). Semicolon optional.
13+
- C-style `//` line comments and `/* block */` comments (alongside the canonical `#`).
14+
- Fixed-size array declaration `h[256] amplitudes;` lowers to `arr_new(256, 0)`.
15+
- Parameterized pragmas: `@unroll:16`, `@threads:64`, `@cache:L1` etc., on both the line-prefix and postfix forms.
16+
- `import core;` and `import core as c;` statements at the parse level. `load "path";` accepted too. Module resolution is currently a no-op; this just unblocks parsing.
17+
18+
**Stdlib (~25 additions):**
19+
- **Math/constants:** `tau`, `phi_inv`, `phi_sq`, `phi_squared`, `sqrt_2`, `sqrt_5`, `ln_2`, `pow_int`, `square`, `cube`, `factorial`, `sign`, `is_prime`, `even`/`is_even`/`odd`/`is_odd`, polymorphic `min(a,b) / min(arr)` and `max`.
20+
- **φ-stdlib (Phase 6 std/*.omc parity):** `fib` (alias for fibonacci), `classify_resonance`, `filter_by_resonance`, `ensure_clean`, `cleanup_array`, `collapse`, `harmonic_interfere`, `interfere`, `measure_coherence`, `arr_fold_elements`.
21+
- **Safe arithmetic:** `safe_add`, `safe_sub`, `safe_mul` (fold any Singularity input through Fibonacci snap before operating).
22+
23+
**Compatibility milestone:**
24+
6 canonical files now run end-to-end on Rust OMC: `miner_nuclear.omc`, `test_phase7_features.omc`, `test_phase8_arrays.omc`, `test_array.omc`, `phi_field_llm.omc`, `hbit_hardware_overlay.omc`. The 30-file sweep moved from 16 → 21 passing. Remaining gaps cluster in: bitwise ops (`& | ^ << >>`), block-style calls (`parallel_for_threads(n) { block }`), file I/O, and module-aware imports — all roadmap-significant items deferred to their own phases.
25+
726
### Added (Phase D: stdlib expansion to match canonical surface, 2026-05-13)
827
Built out ~35 missing standard-library functions to close the gap with the canonical Python `omnicc/` interpreter at `Sovereign_Lattice/omninet_package/`.
928

omnimcode-core/src/interpreter.rs

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,323 @@ impl Interpreter {
534534
"pi" => Ok(Value::HFloat(std::f64::consts::PI)),
535535
"e" => Ok(Value::HFloat(std::f64::consts::E)),
536536
"phi" => Ok(Value::HFloat(crate::value::PHI)),
537+
"tau" => Ok(Value::HFloat(std::f64::consts::TAU)),
538+
"phi_inv" => Ok(Value::HFloat(crate::value::PHI_INV)),
539+
"phi_sq" => Ok(Value::HFloat(crate::value::PHI_SQ)),
540+
"phi_squared" => Ok(Value::HFloat(crate::value::PHI_SQ)),
541+
"factorial" => {
542+
// Lenient like canonical Python OMC: negative -> 1 (identity).
543+
let n = self.eval_expr(&args[0])?.to_int();
544+
let mut result: i64 = 1;
545+
for i in 1..=n.max(0) {
546+
result = result.wrapping_mul(i);
547+
}
548+
Ok(Value::HInt(HInt::new(result)))
549+
}
550+
"square" => {
551+
let v = self.eval_expr(&args[0])?;
552+
if v.is_float() {
553+
let f = v.to_float();
554+
Ok(Value::HFloat(f * f))
555+
} else {
556+
let n = v.to_int();
557+
Ok(Value::HInt(HInt::new(n.wrapping_mul(n))))
558+
}
559+
}
560+
"cube" => {
561+
let v = self.eval_expr(&args[0])?;
562+
if v.is_float() {
563+
let f = v.to_float();
564+
Ok(Value::HFloat(f * f * f))
565+
} else {
566+
let n = v.to_int();
567+
Ok(Value::HInt(HInt::new(n.wrapping_mul(n).wrapping_mul(n))))
568+
}
569+
}
570+
"sqrt_2" => Ok(Value::HFloat(std::f64::consts::SQRT_2)),
571+
"sqrt_5" => Ok(Value::HFloat(5.0_f64.sqrt())),
572+
"ln_2" => Ok(Value::HFloat(std::f64::consts::LN_2)),
573+
// harmonic_interfere(a, b) — Phase 6 std/wave.omc; harmonic mean of magnitudes.
574+
"harmonic_interfere" => {
575+
let a = self.eval_expr(&args[0])?.to_float();
576+
let b = self.eval_expr(&args[1])?.to_float();
577+
if a + b == 0.0 {
578+
Ok(Value::HFloat(0.0))
579+
} else {
580+
Ok(Value::HFloat(2.0 * a * b / (a + b)))
581+
}
582+
}
583+
// measure_coherence(a, b) — Phase 6 std/wave.omc; resonance-based coherence.
584+
"measure_coherence" => {
585+
let a = self.eval_expr(&args[0])?.to_int();
586+
let b = self.eval_expr(&args[1])?.to_int();
587+
let ra = HInt::compute_resonance(a);
588+
let rb = HInt::compute_resonance(b);
589+
Ok(Value::HFloat((ra - rb).abs()))
590+
}
591+
// Polymorphic min/max — accept either (a, b) or a single array.
592+
"min" => {
593+
if args.is_empty() {
594+
return Err("min requires at least 1 argument".to_string());
595+
}
596+
if args.len() == 1 {
597+
// Array form: forward to arr_min behavior
598+
if let Value::Array(arr) = self.eval_expr(&args[0])? {
599+
if arr.items.is_empty() {
600+
return Err("min: empty array".to_string());
601+
}
602+
return Ok(Value::HInt(HInt::new(
603+
arr.items.iter().map(|v| v.to_int()).min().unwrap(),
604+
)));
605+
}
606+
return Err("min(x): single arg must be an array".to_string());
607+
}
608+
let a = self.eval_expr(&args[0])?;
609+
let b = self.eval_expr(&args[1])?;
610+
if a.is_float() || b.is_float() {
611+
Ok(Value::HFloat(a.to_float().min(b.to_float())))
612+
} else {
613+
Ok(Value::HInt(HInt::new(a.to_int().min(b.to_int()))))
614+
}
615+
}
616+
"max" => {
617+
if args.is_empty() {
618+
return Err("max requires at least 1 argument".to_string());
619+
}
620+
if args.len() == 1 {
621+
if let Value::Array(arr) = self.eval_expr(&args[0])? {
622+
if arr.items.is_empty() {
623+
return Err("max: empty array".to_string());
624+
}
625+
return Ok(Value::HInt(HInt::new(
626+
arr.items.iter().map(|v| v.to_int()).max().unwrap(),
627+
)));
628+
}
629+
return Err("max(x): single arg must be an array".to_string());
630+
}
631+
let a = self.eval_expr(&args[0])?;
632+
let b = self.eval_expr(&args[1])?;
633+
if a.is_float() || b.is_float() {
634+
Ok(Value::HFloat(a.to_float().max(b.to_float())))
635+
} else {
636+
Ok(Value::HInt(HInt::new(a.to_int().max(b.to_int()))))
637+
}
638+
}
639+
// safe_add: addition that folds singularity inputs first.
640+
"safe_add" => {
641+
let a = self.eval_expr(&args[0])?;
642+
let b = self.eval_expr(&args[1])?;
643+
let a_clean = if a.is_singularity() { self.phi_fold_n(a, 1) } else { a };
644+
let b_clean = if b.is_singularity() { self.phi_fold_n(b, 1) } else { b };
645+
Ok(Value::HInt(HInt::new(
646+
a_clean.to_int().wrapping_add(b_clean.to_int()),
647+
)))
648+
}
649+
"safe_sub" => {
650+
let a = self.eval_expr(&args[0])?;
651+
let b = self.eval_expr(&args[1])?;
652+
let a_clean = if a.is_singularity() { self.phi_fold_n(a, 1) } else { a };
653+
let b_clean = if b.is_singularity() { self.phi_fold_n(b, 1) } else { b };
654+
Ok(Value::HInt(HInt::new(
655+
a_clean.to_int().wrapping_sub(b_clean.to_int()),
656+
)))
657+
}
658+
"safe_mul" => {
659+
let a = self.eval_expr(&args[0])?;
660+
let b = self.eval_expr(&args[1])?;
661+
let a_clean = if a.is_singularity() { self.phi_fold_n(a, 1) } else { a };
662+
let b_clean = if b.is_singularity() { self.phi_fold_n(b, 1) } else { b };
663+
Ok(Value::HInt(HInt::new(
664+
a_clean.to_int().wrapping_mul(b_clean.to_int()),
665+
)))
666+
}
667+
// sign(n) -> -1, 0, or 1
668+
"sign" => {
669+
let v = self.eval_expr(&args[0])?;
670+
let s = if v.is_float() {
671+
let f = v.to_float();
672+
if f > 0.0 { 1 } else if f < 0.0 { -1 } else { 0 }
673+
} else {
674+
let n = v.to_int();
675+
if n > 0 { 1 } else if n < 0 { -1 } else { 0 }
676+
};
677+
Ok(Value::HInt(HInt::new(s)))
678+
}
679+
// Primality check using 6k±1 trial division.
680+
"is_prime" => {
681+
let n = self.eval_expr(&args[0])?.to_int();
682+
let prime = if n < 2 {
683+
false
684+
} else if n < 4 {
685+
true
686+
} else if n % 2 == 0 || n % 3 == 0 {
687+
false
688+
} else {
689+
let mut i: i64 = 5;
690+
let mut is_p = true;
691+
while i.saturating_mul(i) <= n {
692+
if n % i == 0 || n % (i + 2) == 0 {
693+
is_p = false;
694+
break;
695+
}
696+
i += 6;
697+
}
698+
is_p
699+
};
700+
Ok(Value::HInt(HInt::new(if prime { 1 } else { 0 })))
701+
}
702+
// From Phase 6 std/core.omc:
703+
// ensure_clean(v) — return v if not a Singularity; else fold to nearest Fibonacci.
704+
"ensure_clean" => {
705+
let v = self.eval_expr(&args[0])?;
706+
if v.is_singularity() {
707+
Ok(self.phi_fold_n(v, 1))
708+
} else {
709+
Ok(v)
710+
}
711+
}
712+
// Drop any Singularity elements from an array (Phase 6 idiom).
713+
"cleanup_array" => {
714+
if let Value::Array(arr) = self.eval_expr(&args[0])? {
715+
let kept: Vec<Value> =
716+
arr.items.into_iter().filter(|v| !v.is_singularity()).collect();
717+
Ok(Value::Array(HArray { items: kept }))
718+
} else {
719+
Err("cleanup_array: requires an array".to_string())
720+
}
721+
}
722+
// collapse(amp, phase) — wave collapse to a scalar magnitude.
723+
"collapse" => {
724+
let amp = self.eval_expr(&args[0])?.to_float();
725+
let phase = if args.len() >= 2 {
726+
self.eval_expr(&args[1])?.to_float()
727+
} else {
728+
0.0
729+
};
730+
Ok(Value::HFloat(amp * phase.cos()))
731+
}
732+
// Integer power (separate from `pow` which returns float).
733+
"pow_int" => {
734+
if args.len() < 2 {
735+
return Err("pow_int requires (base, exp)".to_string());
736+
}
737+
let b = self.eval_expr(&args[0])?.to_int();
738+
let e = self.eval_expr(&args[1])?.to_int();
739+
let mut result: i64 = 1;
740+
let mut base = b;
741+
let mut exp = e.max(0) as u32;
742+
while exp > 0 {
743+
if exp & 1 == 1 {
744+
result = result.wrapping_mul(base);
745+
}
746+
base = base.wrapping_mul(base);
747+
exp >>= 1;
748+
}
749+
Ok(Value::HInt(HInt::new(result)))
750+
}
751+
// is_even / is_odd predicates
752+
"even" => {
753+
let n = self.eval_expr(&args[0])?.to_int();
754+
Ok(Value::HInt(HInt::new(if n % 2 == 0 { 1 } else { 0 })))
755+
}
756+
"is_even" => {
757+
let n = self.eval_expr(&args[0])?.to_int();
758+
Ok(Value::HInt(HInt::new(if n % 2 == 0 { 1 } else { 0 })))
759+
}
760+
"odd" => {
761+
let n = self.eval_expr(&args[0])?.to_int();
762+
Ok(Value::HInt(HInt::new(if n % 2 != 0 { 1 } else { 0 })))
763+
}
764+
"is_odd" => {
765+
let n = self.eval_expr(&args[0])?.to_int();
766+
Ok(Value::HInt(HInt::new(if n % 2 != 0 { 1 } else { 0 })))
767+
}
768+
// Short alias used in Phase 6 stdlib for `fibonacci`.
769+
"fib" => {
770+
if args.is_empty() {
771+
return Err("fib requires 1 argument".to_string());
772+
}
773+
let n = self.eval_expr(&args[0])?.to_int();
774+
Ok(Value::HInt(HInt::new(fibonacci(n))))
775+
}
776+
// From Phase 6 std/core.omc: bucket a value's resonance into a label.
777+
// Returns an int code: 3 = high (>=0.7), 2 = medium (>=0.5), 1 = low (>=0.3), 0 = dissonant.
778+
// (Python returns a string but Rust callers use it numerically in if-cascades.)
779+
"classify_resonance" => {
780+
let n = self.eval_expr(&args[0])?.to_int();
781+
let r = HInt::compute_resonance(n);
782+
let code = if r >= 0.7 {
783+
3
784+
} else if r >= 0.5 {
785+
2
786+
} else if r >= 0.3 {
787+
1
788+
} else {
789+
0
790+
};
791+
Ok(Value::HInt(HInt::new(code)))
792+
}
793+
// From Phase 6 std/core.omc: filter array, keep elements with res >= threshold.
794+
"filter_by_resonance" => {
795+
if args.len() < 2 {
796+
return Err("filter_by_resonance requires (array, threshold)".to_string());
797+
}
798+
let arr_v = self.eval_expr(&args[0])?;
799+
let threshold = self.eval_expr(&args[1])?.to_float();
800+
if let Value::Array(arr) = arr_v {
801+
let kept: Vec<Value> = arr
802+
.items
803+
.into_iter()
804+
.filter(|v| HInt::compute_resonance(v.to_int()) >= threshold)
805+
.collect();
806+
Ok(Value::Array(HArray { items: kept }))
807+
} else {
808+
Err("filter_by_resonance: first argument must be an array".to_string())
809+
}
810+
}
811+
// From Phase 6 std/wave.omc: simple wave interference between two values.
812+
// Returns the harmonic mean of the magnitudes.
813+
"interfere" => {
814+
if args.len() < 2 {
815+
return Err("interfere requires (a, b)".to_string());
816+
}
817+
let a = self.eval_expr(&args[0])?.to_float();
818+
let b = self.eval_expr(&args[1])?.to_float();
819+
if a + b == 0.0 {
820+
Ok(Value::HFloat(0.0))
821+
} else {
822+
Ok(Value::HFloat(2.0 * a * b / (a + b)))
823+
}
824+
}
825+
// Variadic "fold across an array with a mode string". From Phase 6 stdlib.
826+
"arr_fold_elements" => {
827+
if args.is_empty() {
828+
return Err("arr_fold_elements requires (array[, mode])".to_string());
829+
}
830+
let arr_v = self.eval_expr(&args[0])?;
831+
if let Value::Array(arr) = arr_v {
832+
let mut acc = 0i64;
833+
for v in &arr.items {
834+
let n = v.to_int().abs();
835+
let fibs: [i64; 15] = [
836+
0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610,
837+
];
838+
let mut nearest = fibs[0];
839+
let mut min_dist = n;
840+
for &f in &fibs {
841+
let d = (f - n).abs();
842+
if d < min_dist {
843+
min_dist = d;
844+
nearest = f;
845+
}
846+
}
847+
acc = acc.wrapping_add(nearest);
848+
}
849+
Ok(Value::HInt(HInt::new(acc)))
850+
} else {
851+
Err("arr_fold_elements: first argument must be an array".to_string())
852+
}
853+
}
537854
// --- Type coercion ---
538855
"to_int" => Ok(Value::HInt(HInt::new(self.eval_expr(&args[0])?.to_int()))),
539856
"to_float" => Ok(Value::HFloat(self.eval_expr(&args[0])?.to_float())),

0 commit comments

Comments
 (0)