Skip to content

Commit b7196b2

Browse files
The Architectclaude
andcommitted
feat(synth): helper-composition in gen_omc (Phase 4.2) — multi-function programs
gen_omc now optionally emits 1-2 total/pure helper functions that `g` composes (calls), mirroring the proven toolbox-composition pattern. Generated programs go from single-function to multi-function while keeping the correct-by-construction guarantee. - synth.rs: Gen.helpers; helper(name) emits `fn hN(x){ return <guarded int_expr over x>; }` (total + pure → any int arg is run-safe); atom() may call a helper; program() emits helpers before g so they register and are callable. Helpers are non-recursive (generated before being added to scope) → always terminate. - Verified: parse-rate 1.000 / run-rate 1.000 STILL HOLDS over 300 seeds. Full suite 267 tests pass. - Example: seed 1 emits h1(x), h2(x) and g calls both — valid + runs. Version 1.8.6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b2847a6 commit b7196b2

2 files changed

Lines changed: 39 additions & 4 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ exclude = ["omnimcode-python"]
2121
resolver = "2"
2222

2323
[workspace.package]
24-
version = "1.8.5"
24+
version = "1.8.6"
2525
edition = "2021"
2626
authors = ["The Architect <architect@sovereign-lattice.io>"]
2727
license = "MIT"

omnimcode-core/src/synth.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct Gen {
2121
counter: u32,
2222
vars: Vec<String>,
2323
protected: HashSet<String>,
24+
helpers: Vec<String>, // names of emitted top-level helper fns g may compose (Phase 4.2)
2425
}
2526

2627
impl Gen {
@@ -29,7 +30,7 @@ impl Gen {
2930
.wrapping_mul(0x9e37_79b9_7f4a_7c15)
3031
.wrapping_add(0x2545_f491_4f6c_dd1d)
3132
| 1;
32-
Gen { rng: s, counter: 0, vars: Vec::new(), protected: HashSet::new() }
33+
Gen { rng: s, counter: 0, vars: Vec::new(), protected: HashSet::new(), helpers: Vec::new() }
3334
}
3435
fn rand(&mut self) -> u64 {
3536
let mut x = self.rng;
@@ -47,8 +48,21 @@ impl Gen {
4748
format!("{}{}", prefix, self.counter)
4849
}
4950

50-
/// An int-valued atom: a declared variable or a small literal.
51+
/// An int-valued atom: a declared variable, a small literal, or a call to a composed helper.
5152
fn atom(&mut self) -> String {
53+
// toolbox composition: occasionally call a helper fn on a simple arg (helpers are total
54+
// and pure, so any int arg is run-safe).
55+
if !self.helpers.is_empty() && self.pick(4) == 0 {
56+
let hi = self.pick(self.helpers.len());
57+
let h = self.helpers[hi].clone();
58+
let arg = if !self.vars.is_empty() && self.pick(2) == 0 {
59+
let vi = self.pick(self.vars.len());
60+
self.vars[vi].clone()
61+
} else {
62+
format!("{}", self.pick(10))
63+
};
64+
return format!("{}({})", h, arg);
65+
}
5266
if !self.vars.is_empty() && self.pick(2) == 0 {
5367
let i = self.pick(self.vars.len());
5468
self.vars[i].clone()
@@ -57,6 +71,18 @@ impl Gen {
5771
}
5872
}
5973

74+
/// A small TOTAL, pure helper `fn name(x) { return <int_expr over x>; }`. Division/modulo in the
75+
/// body are guarded by int_expr (nonzero literal divisor), so it terminates and never errors —
76+
/// safe to call with any integer argument from g's body.
77+
fn helper(&mut self, name: &str) -> String {
78+
let saved_vars = std::mem::replace(&mut self.vars, vec!["x".to_string()]);
79+
let saved_prot = std::mem::take(&mut self.protected);
80+
let body = self.int_expr(2);
81+
self.vars = saved_vars;
82+
self.protected = saved_prot;
83+
format!("fn {}(x) {{\n return {};\n}}", name, body)
84+
}
85+
6086
/// A run-safe int expression: division/modulo always by a nonzero literal.
6187
fn int_expr(&mut self, depth: u32) -> String {
6288
if depth == 0 || self.pick(2) == 0 {
@@ -152,7 +178,16 @@ impl Gen {
152178
self.vars = vec!["a".to_string(), "b".to_string()];
153179
self.protected.clear();
154180
self.counter = 0;
155-
let mut out = vec!["fn g(a, b) {".to_string()];
181+
self.helpers.clear();
182+
// toolbox composition (Phase 4.2): maybe emit 1-2 total/pure helpers that g can call.
183+
let mut prelude: Vec<String> = Vec::new();
184+
for _ in 0..self.pick(3) {
185+
let hname = self.fresh("h");
186+
prelude.push(self.helper(&hname));
187+
self.helpers.push(hname);
188+
}
189+
let mut out: Vec<String> = prelude;
190+
out.push("fn g(a, b) {".to_string());
156191
// a couple of guaranteed declarations first so later statements have vars to use
157192
for _ in 0..2 {
158193
let v = self.fresh("v");

0 commit comments

Comments
 (0)