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.
Files changed (36) hide show
  1. efrog-0.4.0/PKG-INFO +192 -0
  2. efrog-0.4.0/README.md +164 -0
  3. efrog-0.4.0/efrog/__init__.py +46 -0
  4. efrog-0.4.0/efrog/cli.py +232 -0
  5. efrog-0.4.0/efrog/decompilers/__init__.py +1 -0
  6. efrog-0.4.0/efrog/decompilers/c.py +339 -0
  7. efrog-0.4.0/efrog/decompilers/javascript.py +472 -0
  8. efrog-0.4.0/efrog/decompilers/matlab.py +526 -0
  9. efrog-0.4.0/efrog/decompilers/python.py +737 -0
  10. efrog-0.4.0/efrog/decompilers/rust.py +659 -0
  11. efrog-0.4.0/efrog/genome.py +340 -0
  12. efrog-0.4.0/efrog/lean.py +302 -0
  13. efrog-0.4.0/efrog/mic.py +188 -0
  14. efrog-0.4.0/efrog/optimize.py +386 -0
  15. efrog-0.4.0/efrog/profile.py +146 -0
  16. efrog-0.4.0/efrog/verify.py +384 -0
  17. efrog-0.4.0/efrog.egg-info/PKG-INFO +192 -0
  18. efrog-0.4.0/efrog.egg-info/SOURCES.txt +34 -0
  19. efrog-0.4.0/efrog.egg-info/dependency_links.txt +1 -0
  20. efrog-0.4.0/efrog.egg-info/entry_points.txt +2 -0
  21. efrog-0.4.0/efrog.egg-info/requires.txt +9 -0
  22. efrog-0.4.0/efrog.egg-info/top_level.txt +1 -0
  23. efrog-0.4.0/pyproject.toml +51 -0
  24. efrog-0.4.0/setup.cfg +4 -0
  25. efrog-0.4.0/tests/test_c_decompiler.py +149 -0
  26. efrog-0.4.0/tests/test_genome.py +100 -0
  27. efrog-0.4.0/tests/test_javascript_decompiler.py +185 -0
  28. efrog-0.4.0/tests/test_lean.py +95 -0
  29. efrog-0.4.0/tests/test_matlab_decompiler.py +178 -0
  30. efrog-0.4.0/tests/test_mic.py +55 -0
  31. efrog-0.4.0/tests/test_optimize.py +169 -0
  32. efrog-0.4.0/tests/test_profile.py +68 -0
  33. efrog-0.4.0/tests/test_python_decompiler.py +216 -0
  34. efrog-0.4.0/tests/test_python_e2.py +146 -0
  35. efrog-0.4.0/tests/test_rust_decompiler.py +166 -0
  36. 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
+ ]
@@ -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."""