efrog 0.4.0__tar.gz
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.
- efrog-0.4.0/PKG-INFO +192 -0
- efrog-0.4.0/README.md +164 -0
- efrog-0.4.0/efrog/__init__.py +46 -0
- efrog-0.4.0/efrog/cli.py +232 -0
- efrog-0.4.0/efrog/decompilers/__init__.py +1 -0
- efrog-0.4.0/efrog/decompilers/c.py +339 -0
- efrog-0.4.0/efrog/decompilers/javascript.py +472 -0
- efrog-0.4.0/efrog/decompilers/matlab.py +526 -0
- efrog-0.4.0/efrog/decompilers/python.py +737 -0
- efrog-0.4.0/efrog/decompilers/rust.py +659 -0
- efrog-0.4.0/efrog/genome.py +340 -0
- efrog-0.4.0/efrog/lean.py +302 -0
- efrog-0.4.0/efrog/mic.py +188 -0
- efrog-0.4.0/efrog/optimize.py +386 -0
- efrog-0.4.0/efrog/profile.py +146 -0
- efrog-0.4.0/efrog/verify.py +384 -0
- efrog-0.4.0/efrog.egg-info/PKG-INFO +192 -0
- efrog-0.4.0/efrog.egg-info/SOURCES.txt +34 -0
- efrog-0.4.0/efrog.egg-info/dependency_links.txt +1 -0
- efrog-0.4.0/efrog.egg-info/entry_points.txt +2 -0
- efrog-0.4.0/efrog.egg-info/requires.txt +9 -0
- efrog-0.4.0/efrog.egg-info/top_level.txt +1 -0
- efrog-0.4.0/pyproject.toml +51 -0
- efrog-0.4.0/setup.cfg +4 -0
- efrog-0.4.0/tests/test_c_decompiler.py +149 -0
- efrog-0.4.0/tests/test_genome.py +100 -0
- efrog-0.4.0/tests/test_javascript_decompiler.py +185 -0
- efrog-0.4.0/tests/test_lean.py +95 -0
- efrog-0.4.0/tests/test_matlab_decompiler.py +178 -0
- efrog-0.4.0/tests/test_mic.py +55 -0
- efrog-0.4.0/tests/test_optimize.py +169 -0
- efrog-0.4.0/tests/test_profile.py +68 -0
- efrog-0.4.0/tests/test_python_decompiler.py +216 -0
- efrog-0.4.0/tests/test_python_e2.py +146 -0
- efrog-0.4.0/tests/test_rust_decompiler.py +166 -0
- efrog-0.4.0/tests/test_verify.py +116 -0
efrog-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: efrog
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Universal decompiler for the EML substrate — Forge spelled backwards. Anything → EML.
|
|
5
|
+
Author-email: "Arturo R. Almaguer" <almaguer1986@gmail.com>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://monogateforge.com
|
|
8
|
+
Project-URL: Source, https://github.com/agent-maestro/efrog
|
|
9
|
+
Keywords: eml,decompiler,monogate,forge,symbolic,ast
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: pycparser>=2.21
|
|
22
|
+
Requires-Dist: esprima>=4.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
25
|
+
Provides-Extra: mic
|
|
26
|
+
Requires-Dist: numpy>=1.21; extra == "mic"
|
|
27
|
+
Requires-Dist: sounddevice>=0.4; extra == "mic"
|
|
28
|
+
|
|
29
|
+
# eFrog — universal decompiler for the EML substrate
|
|
30
|
+
|
|
31
|
+
> *Forge compiles math into everything. eFrog compiles everything into math.*
|
|
32
|
+
|
|
33
|
+
`pip install efrog` *(pre-release)*
|
|
34
|
+
|
|
35
|
+
eFrog reads source files (and eventually sound, sensors, and shaders)
|
|
36
|
+
and extracts the underlying mathematical structure as
|
|
37
|
+
[EML](https://monogateforge.com) — the same intermediate language
|
|
38
|
+
[Monogate Forge](https://github.com/agent-maestro/monogate-forge)
|
|
39
|
+
emits *into*. eFrog is the reverse direction: every input becomes an
|
|
40
|
+
EML tree you can profile, classify against a corpus of canonical
|
|
41
|
+
math patterns, optimize, and re-compile to any of Forge's targets.
|
|
42
|
+
|
|
43
|
+
## What's shipped (E1 + E2 + E2.5 + early E3 + E4 scaffolding)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
efrog gaussian.py # Python AST → EML
|
|
47
|
+
efrog gaussian.c # C (math.h) → EML, via pycparser
|
|
48
|
+
efrog gaussian.js # JavaScript / TypeScript → EML, via esprima
|
|
49
|
+
efrog gaussian.rs # Rust → EML, hand-rolled parser
|
|
50
|
+
efrog gaussian.m # MATLAB / Octave → EML, hand-rolled parser
|
|
51
|
+
|
|
52
|
+
efrog --profile gaussian.py # per-fn chain order, drift risk, node count
|
|
53
|
+
efrog --verify gaussian.py # round-trip the EML, sample N inputs, prove
|
|
54
|
+
# bit-exact agreement with the original
|
|
55
|
+
efrog --genome gaussian.py # classify each fn against a small corpus
|
|
56
|
+
# (gaussian / sigmoid / softplus / polynomial …)
|
|
57
|
+
efrog --lean gaussian.py # emit Lean 4 theorem skeletons
|
|
58
|
+
efrog --optimize gaussian.py # conservative algebraic simplifier
|
|
59
|
+
# (x+0, x*1, exp(0), x**2 → x*x, …)
|
|
60
|
+
efrog --mic # capture audio, FFT, emit single-sine EML
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
A typical extraction looks like this:
|
|
64
|
+
|
|
65
|
+
```eml
|
|
66
|
+
module gaussian;
|
|
67
|
+
|
|
68
|
+
fn gaussian(mu: Real, sigma: Real, x: Real) -> Real
|
|
69
|
+
where chain_order <= 1
|
|
70
|
+
{
|
|
71
|
+
let dx = x - mu;
|
|
72
|
+
exp(-dx * dx / (2.0 * sigma * sigma)) / sigma
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### E1 — Python pure math
|
|
77
|
+
|
|
78
|
+
- `math.exp/log/sqrt/sin/cos/tan/asin/acos/atan/sinh/cosh/tanh/pow/fabs`
|
|
79
|
+
→ EML builtins
|
|
80
|
+
- `math.pi`, `math.e`, `math.tau` → exact-repr numeric literals
|
|
81
|
+
- `**` (power), `+`, `-`, `*`, `/`, unary `-` → EML operators
|
|
82
|
+
- `def f(x: float, ...) -> float` → `fn f(x: Real, ...) -> Real`
|
|
83
|
+
- `let` bindings via local `name = expr` lines, then `return expr`
|
|
84
|
+
- Top-level `MODULE_NAME = "..."` overrides the inferred module name
|
|
85
|
+
|
|
86
|
+
### E2 — Loops, conditionals, NumPy, C
|
|
87
|
+
|
|
88
|
+
- **Fixed-iteration loop unrolling** — `for i in range(N):` with
|
|
89
|
+
literal N (≤ 64) expands to a flat let-chain
|
|
90
|
+
- **Augmented assigns** — `x *= y`, `x += y` etc. lower to
|
|
91
|
+
`let x = x * y;`
|
|
92
|
+
- **Conditional flattening** — `if cond: A else B` and ternary
|
|
93
|
+
`A if cond else B` become `lerp(B, A, step01(cond))`. Since EML has
|
|
94
|
+
no native conditional, eFrog emits a `step01` shim into the module
|
|
95
|
+
preamble (`clamp(x * 1e30, 0, 1)`). Boolean composition: `and` →
|
|
96
|
+
product of selectors, `or` → 1 − product of complements, `not` →
|
|
97
|
+
`1 - sel`.
|
|
98
|
+
- **NumPy element-wise** — `np.exp/sin/...` map to the same EML
|
|
99
|
+
builtins as `math.*`; aliases like `np.maximum/minimum/arcsin/...`
|
|
100
|
+
resolve to `max/min/asin/...`; `np.pi/np.e/np.tau` inlined
|
|
101
|
+
- **C decompiler** — `double f(double x) { ... }` style; `math.h`
|
|
102
|
+
calls; `M_PI`/`M_E`/`M_SQRT2`/etc. constants; compound assigns
|
|
103
|
+
(`y *= x`); cast strip (`(double) n`); `f(void)` parameter lists.
|
|
104
|
+
Uses pycparser; no preprocessor required (we strip `#`-lines and
|
|
105
|
+
comments)
|
|
106
|
+
|
|
107
|
+
### E2.5 — JavaScript, Rust, MATLAB
|
|
108
|
+
|
|
109
|
+
- **JavaScript / TypeScript** — `function f(x) { ... }` and arrow
|
|
110
|
+
forms `const f = (x) => …`. `Math.exp/sin/...` calls strip the
|
|
111
|
+
`Math.` namespace; `Math.PI`/`E`/`SQRT2`/... inlined; ternaries
|
|
112
|
+
flatten branch-free. Pure-Python esprima parser, no native deps.
|
|
113
|
+
- **Rust** — `fn f(x: f64) -> f64 { … }` with explicit `return` or
|
|
114
|
+
trailing tail expression; `let` (incl. `let mut`) bindings;
|
|
115
|
+
compound assigns; method-call lowering (`x.exp()` → `exp(x)`,
|
|
116
|
+
`x.powf(2.0)` → `pow(x, 2.0)`); associated-function form
|
|
117
|
+
(`f64::sqrt(x)`); path constants (`std::f64::consts::PI`).
|
|
118
|
+
- **MATLAB / Octave** — `function y = f(x) ... end`; output-var
|
|
119
|
+
binding becomes the function's tail expression; `pi`/`e` inlined;
|
|
120
|
+
`.*`/`.^` treated as scalar; `%` and `#` comments; `...` line
|
|
121
|
+
continuation.
|
|
122
|
+
|
|
123
|
+
### E3 partial — Numerical round-trip + Lean scaffolding + per-fn profile
|
|
124
|
+
|
|
125
|
+
- `--profile` — per-fn chain order, transcendental count, node
|
|
126
|
+
count, drift-risk hint (`low/medium/high`), and flags for
|
|
127
|
+
`div`/`sub` (the two ops most commonly responsible for fp64
|
|
128
|
+
cancellation).
|
|
129
|
+
- `--verify` — re-emits the decompiled EML as runnable Python via
|
|
130
|
+
a self-contained primitive shim (no Forge install needed), samples
|
|
131
|
+
`--samples N` random inputs per parameter using sane per-name
|
|
132
|
+
domains (sigma → positive, omega → \[0, 2π], ...), runs both the
|
|
133
|
+
original and the round-trip on every sample, and reports max
|
|
134
|
+
relative error. PASS if every sample agrees to within 1e-9
|
|
135
|
+
relative. The NumPy-using examples work without numpy installed
|
|
136
|
+
thanks to a `sys.modules['numpy']` shim.
|
|
137
|
+
- `--lean` — emits a Lean 4 module per source: a `def` translating
|
|
138
|
+
the EML body into `Real.exp/sin/...` calls (Mathlib-style), plus
|
|
139
|
+
two `theorem` skeletons per function (`<name>_chain_order`,
|
|
140
|
+
`<name>_eml_consistent`). Bodies are deliberately `sorry` /
|
|
141
|
+
`trivial` — these are the scaffolds the MonogateEML proof sprint
|
|
142
|
+
discharges.
|
|
143
|
+
- `--genome` — classifies every decompiled function against a small
|
|
144
|
+
curated corpus of canonical math landmarks (gaussian, sigmoid,
|
|
145
|
+
softplus, ReLU, sinusoid, polynomial, …) with a structural
|
|
146
|
+
similarity score (Jaccard over transcendentals + helpers + binops,
|
|
147
|
+
weighted with a chain-order penalty). The full SuperBEST corpus
|
|
148
|
+
ships separately.
|
|
149
|
+
|
|
150
|
+
### E5 partial — Algebraic simplifier
|
|
151
|
+
|
|
152
|
+
- `--optimize` — conservative bottom-up rewriter with fixed-point
|
|
153
|
+
iteration. Safe identities only: `x + 0 → x`, `x * 1 → x`,
|
|
154
|
+
`x * 0 → 0`, `-(-x) → x`, `x + x → 2*x`, `pow(x, 2) → x*x`,
|
|
155
|
+
`exp(0) → 1`, `log(1) → 0`, `sin(0) → 0`, `cos(0) → 1`,
|
|
156
|
+
`sqrt(0/1) → 0/1`, plus constant folding for two-literal binops.
|
|
157
|
+
Pair with `--verify` to confirm the rewrite preserved every value.
|
|
158
|
+
|
|
159
|
+
### E4 scaffolding — The math microphone
|
|
160
|
+
|
|
161
|
+
- `--mic` — captures `--mic-duration` seconds from the default input
|
|
162
|
+
device, runs an FFT, picks the dominant non-DC bin, and emits a
|
|
163
|
+
single-sine EML fit `mic_signal(t) = A * sin(2π f t + φ)` plus
|
|
164
|
+
amplitude / phase / SNR diagnostics. Multi-tone, harmonic, and
|
|
165
|
+
envelope decomposition land in full E4. `pip install efrog[mic]`
|
|
166
|
+
pulls in `numpy` + `sounddevice`.
|
|
167
|
+
|
|
168
|
+
### Coming
|
|
169
|
+
|
|
170
|
+
| Phase | What | When |
|
|
171
|
+
|-------|------|------|
|
|
172
|
+
| E3-full | Lean theorem generation (BFS proof attacks) | month 4–6 |
|
|
173
|
+
| E4-full | Multi-tone / harmonic / envelope decomposition | month 6–8 |
|
|
174
|
+
| E5-full | Universal optimizer pipe (CSE, trig identities) | month 6–8 |
|
|
175
|
+
| E6 | Sensor expansion (camera / stethoscope / ...) | month 8+ |
|
|
176
|
+
|
|
177
|
+
Full roadmap: `monogate-research/products/software/efrog/ROADMAP.md`.
|
|
178
|
+
|
|
179
|
+
## Status
|
|
180
|
+
|
|
181
|
+
174 tests green. Five source languages (Python, C, JavaScript, Rust,
|
|
182
|
+
MATLAB). Loops, ternaries, branch-free conditionals, NumPy aliases,
|
|
183
|
+
per-function profiling, bit-exact numerical round-trip, Lean 4
|
|
184
|
+
scaffolding, genome classification, algebraic simplification, and
|
|
185
|
+
single-sine audio fit all working. `while` loops, comprehensions,
|
|
186
|
+
classes, real vector operations, pointers, arrays, structs, and
|
|
187
|
+
multi-output MATLAB functions still raise honest "not supported,
|
|
188
|
+
see ROADMAP.md" errors.
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
Apache 2.0.
|
efrog-0.4.0/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# eFrog — universal decompiler for the EML substrate
|
|
2
|
+
|
|
3
|
+
> *Forge compiles math into everything. eFrog compiles everything into math.*
|
|
4
|
+
|
|
5
|
+
`pip install efrog` *(pre-release)*
|
|
6
|
+
|
|
7
|
+
eFrog reads source files (and eventually sound, sensors, and shaders)
|
|
8
|
+
and extracts the underlying mathematical structure as
|
|
9
|
+
[EML](https://monogateforge.com) — the same intermediate language
|
|
10
|
+
[Monogate Forge](https://github.com/agent-maestro/monogate-forge)
|
|
11
|
+
emits *into*. eFrog is the reverse direction: every input becomes an
|
|
12
|
+
EML tree you can profile, classify against a corpus of canonical
|
|
13
|
+
math patterns, optimize, and re-compile to any of Forge's targets.
|
|
14
|
+
|
|
15
|
+
## What's shipped (E1 + E2 + E2.5 + early E3 + E4 scaffolding)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
efrog gaussian.py # Python AST → EML
|
|
19
|
+
efrog gaussian.c # C (math.h) → EML, via pycparser
|
|
20
|
+
efrog gaussian.js # JavaScript / TypeScript → EML, via esprima
|
|
21
|
+
efrog gaussian.rs # Rust → EML, hand-rolled parser
|
|
22
|
+
efrog gaussian.m # MATLAB / Octave → EML, hand-rolled parser
|
|
23
|
+
|
|
24
|
+
efrog --profile gaussian.py # per-fn chain order, drift risk, node count
|
|
25
|
+
efrog --verify gaussian.py # round-trip the EML, sample N inputs, prove
|
|
26
|
+
# bit-exact agreement with the original
|
|
27
|
+
efrog --genome gaussian.py # classify each fn against a small corpus
|
|
28
|
+
# (gaussian / sigmoid / softplus / polynomial …)
|
|
29
|
+
efrog --lean gaussian.py # emit Lean 4 theorem skeletons
|
|
30
|
+
efrog --optimize gaussian.py # conservative algebraic simplifier
|
|
31
|
+
# (x+0, x*1, exp(0), x**2 → x*x, …)
|
|
32
|
+
efrog --mic # capture audio, FFT, emit single-sine EML
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
A typical extraction looks like this:
|
|
36
|
+
|
|
37
|
+
```eml
|
|
38
|
+
module gaussian;
|
|
39
|
+
|
|
40
|
+
fn gaussian(mu: Real, sigma: Real, x: Real) -> Real
|
|
41
|
+
where chain_order <= 1
|
|
42
|
+
{
|
|
43
|
+
let dx = x - mu;
|
|
44
|
+
exp(-dx * dx / (2.0 * sigma * sigma)) / sigma
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### E1 — Python pure math
|
|
49
|
+
|
|
50
|
+
- `math.exp/log/sqrt/sin/cos/tan/asin/acos/atan/sinh/cosh/tanh/pow/fabs`
|
|
51
|
+
→ EML builtins
|
|
52
|
+
- `math.pi`, `math.e`, `math.tau` → exact-repr numeric literals
|
|
53
|
+
- `**` (power), `+`, `-`, `*`, `/`, unary `-` → EML operators
|
|
54
|
+
- `def f(x: float, ...) -> float` → `fn f(x: Real, ...) -> Real`
|
|
55
|
+
- `let` bindings via local `name = expr` lines, then `return expr`
|
|
56
|
+
- Top-level `MODULE_NAME = "..."` overrides the inferred module name
|
|
57
|
+
|
|
58
|
+
### E2 — Loops, conditionals, NumPy, C
|
|
59
|
+
|
|
60
|
+
- **Fixed-iteration loop unrolling** — `for i in range(N):` with
|
|
61
|
+
literal N (≤ 64) expands to a flat let-chain
|
|
62
|
+
- **Augmented assigns** — `x *= y`, `x += y` etc. lower to
|
|
63
|
+
`let x = x * y;`
|
|
64
|
+
- **Conditional flattening** — `if cond: A else B` and ternary
|
|
65
|
+
`A if cond else B` become `lerp(B, A, step01(cond))`. Since EML has
|
|
66
|
+
no native conditional, eFrog emits a `step01` shim into the module
|
|
67
|
+
preamble (`clamp(x * 1e30, 0, 1)`). Boolean composition: `and` →
|
|
68
|
+
product of selectors, `or` → 1 − product of complements, `not` →
|
|
69
|
+
`1 - sel`.
|
|
70
|
+
- **NumPy element-wise** — `np.exp/sin/...` map to the same EML
|
|
71
|
+
builtins as `math.*`; aliases like `np.maximum/minimum/arcsin/...`
|
|
72
|
+
resolve to `max/min/asin/...`; `np.pi/np.e/np.tau` inlined
|
|
73
|
+
- **C decompiler** — `double f(double x) { ... }` style; `math.h`
|
|
74
|
+
calls; `M_PI`/`M_E`/`M_SQRT2`/etc. constants; compound assigns
|
|
75
|
+
(`y *= x`); cast strip (`(double) n`); `f(void)` parameter lists.
|
|
76
|
+
Uses pycparser; no preprocessor required (we strip `#`-lines and
|
|
77
|
+
comments)
|
|
78
|
+
|
|
79
|
+
### E2.5 — JavaScript, Rust, MATLAB
|
|
80
|
+
|
|
81
|
+
- **JavaScript / TypeScript** — `function f(x) { ... }` and arrow
|
|
82
|
+
forms `const f = (x) => …`. `Math.exp/sin/...` calls strip the
|
|
83
|
+
`Math.` namespace; `Math.PI`/`E`/`SQRT2`/... inlined; ternaries
|
|
84
|
+
flatten branch-free. Pure-Python esprima parser, no native deps.
|
|
85
|
+
- **Rust** — `fn f(x: f64) -> f64 { … }` with explicit `return` or
|
|
86
|
+
trailing tail expression; `let` (incl. `let mut`) bindings;
|
|
87
|
+
compound assigns; method-call lowering (`x.exp()` → `exp(x)`,
|
|
88
|
+
`x.powf(2.0)` → `pow(x, 2.0)`); associated-function form
|
|
89
|
+
(`f64::sqrt(x)`); path constants (`std::f64::consts::PI`).
|
|
90
|
+
- **MATLAB / Octave** — `function y = f(x) ... end`; output-var
|
|
91
|
+
binding becomes the function's tail expression; `pi`/`e` inlined;
|
|
92
|
+
`.*`/`.^` treated as scalar; `%` and `#` comments; `...` line
|
|
93
|
+
continuation.
|
|
94
|
+
|
|
95
|
+
### E3 partial — Numerical round-trip + Lean scaffolding + per-fn profile
|
|
96
|
+
|
|
97
|
+
- `--profile` — per-fn chain order, transcendental count, node
|
|
98
|
+
count, drift-risk hint (`low/medium/high`), and flags for
|
|
99
|
+
`div`/`sub` (the two ops most commonly responsible for fp64
|
|
100
|
+
cancellation).
|
|
101
|
+
- `--verify` — re-emits the decompiled EML as runnable Python via
|
|
102
|
+
a self-contained primitive shim (no Forge install needed), samples
|
|
103
|
+
`--samples N` random inputs per parameter using sane per-name
|
|
104
|
+
domains (sigma → positive, omega → \[0, 2π], ...), runs both the
|
|
105
|
+
original and the round-trip on every sample, and reports max
|
|
106
|
+
relative error. PASS if every sample agrees to within 1e-9
|
|
107
|
+
relative. The NumPy-using examples work without numpy installed
|
|
108
|
+
thanks to a `sys.modules['numpy']` shim.
|
|
109
|
+
- `--lean` — emits a Lean 4 module per source: a `def` translating
|
|
110
|
+
the EML body into `Real.exp/sin/...` calls (Mathlib-style), plus
|
|
111
|
+
two `theorem` skeletons per function (`<name>_chain_order`,
|
|
112
|
+
`<name>_eml_consistent`). Bodies are deliberately `sorry` /
|
|
113
|
+
`trivial` — these are the scaffolds the MonogateEML proof sprint
|
|
114
|
+
discharges.
|
|
115
|
+
- `--genome` — classifies every decompiled function against a small
|
|
116
|
+
curated corpus of canonical math landmarks (gaussian, sigmoid,
|
|
117
|
+
softplus, ReLU, sinusoid, polynomial, …) with a structural
|
|
118
|
+
similarity score (Jaccard over transcendentals + helpers + binops,
|
|
119
|
+
weighted with a chain-order penalty). The full SuperBEST corpus
|
|
120
|
+
ships separately.
|
|
121
|
+
|
|
122
|
+
### E5 partial — Algebraic simplifier
|
|
123
|
+
|
|
124
|
+
- `--optimize` — conservative bottom-up rewriter with fixed-point
|
|
125
|
+
iteration. Safe identities only: `x + 0 → x`, `x * 1 → x`,
|
|
126
|
+
`x * 0 → 0`, `-(-x) → x`, `x + x → 2*x`, `pow(x, 2) → x*x`,
|
|
127
|
+
`exp(0) → 1`, `log(1) → 0`, `sin(0) → 0`, `cos(0) → 1`,
|
|
128
|
+
`sqrt(0/1) → 0/1`, plus constant folding for two-literal binops.
|
|
129
|
+
Pair with `--verify` to confirm the rewrite preserved every value.
|
|
130
|
+
|
|
131
|
+
### E4 scaffolding — The math microphone
|
|
132
|
+
|
|
133
|
+
- `--mic` — captures `--mic-duration` seconds from the default input
|
|
134
|
+
device, runs an FFT, picks the dominant non-DC bin, and emits a
|
|
135
|
+
single-sine EML fit `mic_signal(t) = A * sin(2π f t + φ)` plus
|
|
136
|
+
amplitude / phase / SNR diagnostics. Multi-tone, harmonic, and
|
|
137
|
+
envelope decomposition land in full E4. `pip install efrog[mic]`
|
|
138
|
+
pulls in `numpy` + `sounddevice`.
|
|
139
|
+
|
|
140
|
+
### Coming
|
|
141
|
+
|
|
142
|
+
| Phase | What | When |
|
|
143
|
+
|-------|------|------|
|
|
144
|
+
| E3-full | Lean theorem generation (BFS proof attacks) | month 4–6 |
|
|
145
|
+
| E4-full | Multi-tone / harmonic / envelope decomposition | month 6–8 |
|
|
146
|
+
| E5-full | Universal optimizer pipe (CSE, trig identities) | month 6–8 |
|
|
147
|
+
| E6 | Sensor expansion (camera / stethoscope / ...) | month 8+ |
|
|
148
|
+
|
|
149
|
+
Full roadmap: `monogate-research/products/software/efrog/ROADMAP.md`.
|
|
150
|
+
|
|
151
|
+
## Status
|
|
152
|
+
|
|
153
|
+
174 tests green. Five source languages (Python, C, JavaScript, Rust,
|
|
154
|
+
MATLAB). Loops, ternaries, branch-free conditionals, NumPy aliases,
|
|
155
|
+
per-function profiling, bit-exact numerical round-trip, Lean 4
|
|
156
|
+
scaffolding, genome classification, algebraic simplification, and
|
|
157
|
+
single-sine audio fit all working. `while` loops, comprehensions,
|
|
158
|
+
classes, real vector operations, pointers, arrays, structs, and
|
|
159
|
+
multi-output MATLAB functions still raise honest "not supported,
|
|
160
|
+
see ROADMAP.md" errors.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
Apache 2.0.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""eFrog — universal decompiler for the EML substrate.
|
|
2
|
+
|
|
3
|
+
Forge compiles math into everything.
|
|
4
|
+
eFrog compiles everything into math.
|
|
5
|
+
|
|
6
|
+
Phase E1 ships the Python AST decompiler. Later phases add C / Rust /
|
|
7
|
+
JS / MATLAB / CUDA / shaders / Verilog / Solidity, then symbolic
|
|
8
|
+
extraction with loops + conditionals, then live-audio decomposition.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__version__ = "0.4.0a0"
|
|
12
|
+
|
|
13
|
+
from .decompilers.c import decompile_c_source
|
|
14
|
+
from .decompilers.javascript import decompile_javascript_source
|
|
15
|
+
from .decompilers.matlab import decompile_matlab_source
|
|
16
|
+
from .decompilers.python import decompile_python_source
|
|
17
|
+
from .decompilers.rust import decompile_rust_source
|
|
18
|
+
from .genome import classify_function, classify_module, render_genome
|
|
19
|
+
from .lean import render_lean
|
|
20
|
+
from .mic import decompose_buffer, decompose_microphone, render_mic
|
|
21
|
+
from .optimize import optimize_function, optimize_module, render_optimize
|
|
22
|
+
from .profile import profile_module, render_profile
|
|
23
|
+
from .verify import render_verify, verify_python_file
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"__version__",
|
|
27
|
+
"decompile_python_source",
|
|
28
|
+
"decompile_c_source",
|
|
29
|
+
"decompile_javascript_source",
|
|
30
|
+
"decompile_matlab_source",
|
|
31
|
+
"decompile_rust_source",
|
|
32
|
+
"profile_module",
|
|
33
|
+
"render_profile",
|
|
34
|
+
"verify_python_file",
|
|
35
|
+
"render_verify",
|
|
36
|
+
"classify_module",
|
|
37
|
+
"classify_function",
|
|
38
|
+
"render_genome",
|
|
39
|
+
"render_lean",
|
|
40
|
+
"optimize_module",
|
|
41
|
+
"optimize_function",
|
|
42
|
+
"render_optimize",
|
|
43
|
+
"decompose_microphone",
|
|
44
|
+
"decompose_buffer",
|
|
45
|
+
"render_mic",
|
|
46
|
+
]
|
efrog-0.4.0/efrog/cli.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""eFrog CLI entry point. E1: Python. E2: + C, --profile, --verify."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Sequence
|
|
9
|
+
|
|
10
|
+
from . import __version__
|
|
11
|
+
from .decompilers.c import decompile_c_file
|
|
12
|
+
from .decompilers.javascript import decompile_javascript_file
|
|
13
|
+
from .decompilers.matlab import decompile_matlab_file
|
|
14
|
+
from .decompilers.python import EFrogError, decompile_python_file
|
|
15
|
+
from .decompilers.rust import decompile_rust_file
|
|
16
|
+
from .genome import render_genome
|
|
17
|
+
from .lean import render_lean
|
|
18
|
+
from .mic import decompose_microphone, render_mic
|
|
19
|
+
from .optimize import optimize_module, render_optimize
|
|
20
|
+
from .profile import render_profile
|
|
21
|
+
from .verify import render_verify, verify_python_file
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_LANG_BY_EXT = {
|
|
25
|
+
".py": "python",
|
|
26
|
+
".c": "c",
|
|
27
|
+
".js": "javascript",
|
|
28
|
+
".mjs": "javascript",
|
|
29
|
+
".ts": "javascript", # TS is parsed as JS — annotations not yet handled
|
|
30
|
+
".rs": "rust",
|
|
31
|
+
".m": "matlab",
|
|
32
|
+
# Future-phase stubs — the dispatcher knows the language but the
|
|
33
|
+
# decompiler isn't shipped yet. They get a clear error message
|
|
34
|
+
# instead of silently falling back to Python.
|
|
35
|
+
".cpp": "cpp",
|
|
36
|
+
".cu": "cuda",
|
|
37
|
+
".m": "matlab",
|
|
38
|
+
".hlsl": "hlsl",
|
|
39
|
+
".glsl": "glsl",
|
|
40
|
+
".v": "verilog",
|
|
41
|
+
".sv": "systemverilog",
|
|
42
|
+
".sol": "solidity",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _detect_language(path: str, override: str | None) -> str:
|
|
47
|
+
if override:
|
|
48
|
+
return override
|
|
49
|
+
ext = os.path.splitext(path)[1].lower()
|
|
50
|
+
return _LANG_BY_EXT.get(ext, "")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
54
|
+
parser = argparse.ArgumentParser(
|
|
55
|
+
prog="efrog",
|
|
56
|
+
description=(
|
|
57
|
+
"eFrog — extract EML from any source. "
|
|
58
|
+
"E2.5 supports Python / C / JavaScript / Rust / MATLAB; "
|
|
59
|
+
"E3+ adds shaders / Verilog / Solidity."
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument("input", nargs="?", help="source file (omit when using --mic)")
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"-o", "--output",
|
|
65
|
+
help="write EML to this path (default: stdout)",
|
|
66
|
+
)
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--lang",
|
|
69
|
+
help="force a language instead of inferring from extension",
|
|
70
|
+
)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--module",
|
|
73
|
+
help="override the emitted `module name;` (default: filename stem)",
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"--version",
|
|
77
|
+
action="version",
|
|
78
|
+
version=f"efrog {__version__}",
|
|
79
|
+
)
|
|
80
|
+
# Hidden-for-now flags that point at future phases. Surfaced so
|
|
81
|
+
# `--help` is honest about what's coming, but they error politely.
|
|
82
|
+
parser.add_argument("--profile", action="store_true",
|
|
83
|
+
help="print per-function chain order, transcendental "
|
|
84
|
+
"count, node count, drift risk")
|
|
85
|
+
parser.add_argument("--verify", action="store_true",
|
|
86
|
+
help="round-trip the extracted EML through a Python "
|
|
87
|
+
"shim and compare numerically against the original "
|
|
88
|
+
"(E3 partial — Lean proofs land in full E3)")
|
|
89
|
+
parser.add_argument("--samples", type=int, default=100,
|
|
90
|
+
help="number of random input samples for --verify "
|
|
91
|
+
"(default 100)")
|
|
92
|
+
parser.add_argument("--seed", type=int, default=42,
|
|
93
|
+
help="RNG seed for --verify sampling (default 42)")
|
|
94
|
+
parser.add_argument("--mic", action="store_true",
|
|
95
|
+
help="capture a short audio buffer from the default "
|
|
96
|
+
"input device and emit a single-sine EML fit "
|
|
97
|
+
"(E4 scaffolding — multi-tone + envelope land later)")
|
|
98
|
+
parser.add_argument("--mic-duration", type=float, default=0.5,
|
|
99
|
+
help="seconds of audio to capture (default 0.5)")
|
|
100
|
+
parser.add_argument("--mic-rate", type=int, default=44_100,
|
|
101
|
+
help="sample rate in Hz (default 44100)")
|
|
102
|
+
parser.add_argument("--genome", action="store_true",
|
|
103
|
+
help="classify each decompiled function against a small "
|
|
104
|
+
"bundled corpus of canonical math patterns "
|
|
105
|
+
"(gaussian, sigmoid, softplus, polynomial, …)")
|
|
106
|
+
parser.add_argument("--genome-top", type=int, default=5,
|
|
107
|
+
help="how many genome matches to print per function "
|
|
108
|
+
"(default 5)")
|
|
109
|
+
parser.add_argument("--lean", action="store_true",
|
|
110
|
+
help="emit a Lean 4 theorem skeleton for each "
|
|
111
|
+
"decompiled function (Mathlib-style; bodies "
|
|
112
|
+
"are sorry-bodied scaffolds)")
|
|
113
|
+
parser.add_argument("--optimize", action="store_true",
|
|
114
|
+
help="run a conservative algebraic simplifier "
|
|
115
|
+
"(x+0, x*1, exp(0), x**2 → x*x, …) before "
|
|
116
|
+
"emitting EML")
|
|
117
|
+
parser.add_argument("--optimize-report", action="store_true",
|
|
118
|
+
help="print the per-function rewrite count "
|
|
119
|
+
"alongside --optimize output")
|
|
120
|
+
|
|
121
|
+
args = parser.parse_args(argv)
|
|
122
|
+
|
|
123
|
+
if args.mic:
|
|
124
|
+
try:
|
|
125
|
+
result = decompose_microphone(
|
|
126
|
+
duration=args.mic_duration,
|
|
127
|
+
sample_rate=args.mic_rate,
|
|
128
|
+
)
|
|
129
|
+
except RuntimeError as exc:
|
|
130
|
+
print(f"efrog: {exc}", file=sys.stderr)
|
|
131
|
+
return 1
|
|
132
|
+
out_text = render_mic(result)
|
|
133
|
+
if args.output:
|
|
134
|
+
with open(args.output, "w", encoding="utf-8") as f:
|
|
135
|
+
f.write(out_text)
|
|
136
|
+
else:
|
|
137
|
+
sys.stdout.write(out_text)
|
|
138
|
+
return 0
|
|
139
|
+
|
|
140
|
+
if not args.input:
|
|
141
|
+
parser.error("input file required (or use --mic in E4)")
|
|
142
|
+
|
|
143
|
+
path = args.input
|
|
144
|
+
if not os.path.isfile(path):
|
|
145
|
+
print(f"efrog: no such file: {path}", file=sys.stderr)
|
|
146
|
+
return 1
|
|
147
|
+
|
|
148
|
+
lang = _detect_language(path, args.lang)
|
|
149
|
+
decompiler = _DECOMPILERS.get(lang)
|
|
150
|
+
if decompiler is None:
|
|
151
|
+
if not lang:
|
|
152
|
+
print(
|
|
153
|
+
f"efrog: can't infer language from {path!r}; pass --lang",
|
|
154
|
+
file=sys.stderr,
|
|
155
|
+
)
|
|
156
|
+
return 1
|
|
157
|
+
print(
|
|
158
|
+
f"efrog: language `{lang}` ships in a later phase. "
|
|
159
|
+
f"E2.5 supports python, c, javascript/typescript, rust, and matlab. "
|
|
160
|
+
f"See ROADMAP.md.",
|
|
161
|
+
file=sys.stderr,
|
|
162
|
+
)
|
|
163
|
+
return 2
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
mod = decompiler(path)
|
|
167
|
+
except EFrogError as exc:
|
|
168
|
+
print(f"efrog: {exc}", file=sys.stderr)
|
|
169
|
+
return 1
|
|
170
|
+
|
|
171
|
+
if args.module:
|
|
172
|
+
mod.name = args.module
|
|
173
|
+
|
|
174
|
+
if args.optimize:
|
|
175
|
+
reports = optimize_module(mod)
|
|
176
|
+
if args.optimize_report:
|
|
177
|
+
sys.stderr.write(render_optimize(reports))
|
|
178
|
+
|
|
179
|
+
if args.profile:
|
|
180
|
+
sys.stdout.write(render_profile(mod))
|
|
181
|
+
return 0
|
|
182
|
+
|
|
183
|
+
if args.genome:
|
|
184
|
+
sys.stdout.write(render_genome(mod, top_k=args.genome_top))
|
|
185
|
+
return 0
|
|
186
|
+
|
|
187
|
+
if args.lean:
|
|
188
|
+
out_text = render_lean(mod)
|
|
189
|
+
if args.output:
|
|
190
|
+
with open(args.output, "w", encoding="utf-8") as f:
|
|
191
|
+
f.write(out_text)
|
|
192
|
+
else:
|
|
193
|
+
sys.stdout.write(out_text)
|
|
194
|
+
return 0
|
|
195
|
+
|
|
196
|
+
if args.verify:
|
|
197
|
+
# --verify is currently Python-only because the round-trip
|
|
198
|
+
# needs to run the original source. C round-trip lands when
|
|
199
|
+
# we can host a tiny Tiny C interpreter or shell out to gcc.
|
|
200
|
+
if lang != "python":
|
|
201
|
+
print(
|
|
202
|
+
f"efrog: --verify currently supports python only "
|
|
203
|
+
f"(your file is {lang}); the C round-trip needs a runtime",
|
|
204
|
+
file=sys.stderr,
|
|
205
|
+
)
|
|
206
|
+
return 2
|
|
207
|
+
result = verify_python_file(
|
|
208
|
+
path, n_samples=args.samples, seed=args.seed
|
|
209
|
+
)
|
|
210
|
+
sys.stdout.write(render_verify(result))
|
|
211
|
+
return 0 if result.passed else 1
|
|
212
|
+
|
|
213
|
+
eml = mod.to_eml()
|
|
214
|
+
if args.output:
|
|
215
|
+
with open(args.output, "w", encoding="utf-8") as f:
|
|
216
|
+
f.write(eml)
|
|
217
|
+
else:
|
|
218
|
+
sys.stdout.write(eml)
|
|
219
|
+
return 0
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
_DECOMPILERS = {
|
|
223
|
+
"python": decompile_python_file,
|
|
224
|
+
"c": decompile_c_file,
|
|
225
|
+
"javascript": decompile_javascript_file,
|
|
226
|
+
"rust": decompile_rust_file,
|
|
227
|
+
"matlab": decompile_matlab_file,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
if __name__ == "__main__":
|
|
232
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Per-language decompilers. E1 ships Python; E2 adds C/Rust/JS/MATLAB."""
|