gelang 0.1.0
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.
- package/CHANGELOG.md +65 -0
- package/LICENSE +21 -0
- package/README.md +535 -0
- package/bin/ge.js +112 -0
- package/package.json +62 -0
- package/python/pyeffic/__init__.py +9 -0
- package/python/pyeffic/__main__.py +6 -0
- package/python/pyeffic/analyzer.py +464 -0
- package/python/pyeffic/apisurface.py +238 -0
- package/python/pyeffic/autoselect.py +327 -0
- package/python/pyeffic/backends.py +87 -0
- package/python/pyeffic/bench.py +233 -0
- package/python/pyeffic/cli.py +184 -0
- package/python/pyeffic/compiler.py +421 -0
- package/python/pyeffic/config.py +383 -0
- package/python/pyeffic/dartgen.py +441 -0
- package/python/pyeffic/deploy.py +586 -0
- package/python/pyeffic/diagnostics.py +194 -0
- package/python/pyeffic/difftest.py +424 -0
- package/python/pyeffic/downloader.py +307 -0
- package/python/pyeffic/emitters/__init__.py +11 -0
- package/python/pyeffic/emitters/base.py +2359 -0
- package/python/pyeffic/emitters/cpp.py +266 -0
- package/python/pyeffic/emitters/csharp.py +342 -0
- package/python/pyeffic/emitters/dart.py +349 -0
- package/python/pyeffic/emitters/go.py +388 -0
- package/python/pyeffic/emitters/kotlin.py +314 -0
- package/python/pyeffic/emitters/rust.py +314 -0
- package/python/pyeffic/emitters/zig.py +411 -0
- package/python/pyeffic/ffi.py +49 -0
- package/python/pyeffic/frontends/__init__.py +94 -0
- package/python/pyeffic/frontends/hybrid.py +709 -0
- package/python/pyeffic/frontends/typescript.py +965 -0
- package/python/pyeffic/ge_cli.py +1148 -0
- package/python/pyeffic/golden.py +348 -0
- package/python/pyeffic/idents.py +206 -0
- package/python/pyeffic/modules.py +220 -0
- package/python/pyeffic/packer.py +222 -0
- package/python/pyeffic/pipeline.py +797 -0
- package/python/pyeffic/reactgen.py +966 -0
- package/python/pyeffic/researcher.py +177 -0
- package/python/pyeffic/scaffold.py +397 -0
- package/python/pyeffic/stdlib.py +246 -0
- package/python/pyeffic/styling.py +220 -0
- package/python/pyeffic/templates/desktop_gui/README.md +106 -0
- package/python/pyeffic/templates/desktop_gui/app/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/core/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/core/add.ge.py +13 -0
- package/python/pyeffic/templates/desktop_gui/app/core/factorial.ge.py +20 -0
- package/python/pyeffic/templates/desktop_gui/app/core/fibonacci.ge.py +25 -0
- package/python/pyeffic/templates/desktop_gui/app/core/gcd.ge.py +19 -0
- package/python/pyeffic/templates/desktop_gui/app/core/is_prime.ge.py +24 -0
- package/python/pyeffic/templates/desktop_gui/app/core/multiply.ge.py +13 -0
- package/python/pyeffic/templates/desktop_gui/app/core/power.ge.py +25 -0
- package/python/pyeffic/templates/desktop_gui/app/main.ge.py +49 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/buffer.ge.py +26 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/limits.ge.py +47 -0
- package/python/pyeffic/templates/desktop_gui/app/memory/state.ge.py +44 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/layout.ge.py +64 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/render.ge.py +87 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/theme.ge.py +147 -0
- package/python/pyeffic/templates/desktop_gui/app/ui/widgets.ge.py +105 -0
- package/python/pyeffic/templates/desktop_gui/desktop/__init__.py +1 -0
- package/python/pyeffic/templates/desktop_gui/desktop/main.ge.py +258 -0
- package/python/pyeffic/templates/desktop_gui/ge.toml +16 -0
- package/python/pyeffic/templates/desktop_gui/tests/__init__.py +0 -0
- package/python/pyeffic/templates/desktop_gui/tests/ge_loader.py +76 -0
- package/python/pyeffic/templates/desktop_gui/tests/test_app.py +173 -0
- package/python/pyeffic/templates/web_react/README.md +115 -0
- package/python/pyeffic/templates/web_react/app/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/app/core/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/app/core/add.ge.py +9 -0
- package/python/pyeffic/templates/web_react/app/core/factorial.ge.py +16 -0
- package/python/pyeffic/templates/web_react/app/core/fibonacci.ge.py +21 -0
- package/python/pyeffic/templates/web_react/app/core/is_prime.ge.py +20 -0
- package/python/pyeffic/templates/web_react/app/core/multiply.ge.py +9 -0
- package/python/pyeffic/templates/web_react/app/main.ge.py +25 -0
- package/python/pyeffic/templates/web_react/app/memory/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/app/memory/buffer.ge.py +25 -0
- package/python/pyeffic/templates/web_react/app/memory/limits.ge.py +51 -0
- package/python/pyeffic/templates/web_react/ge.toml +23 -0
- package/python/pyeffic/templates/web_react/tests/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/tests/ge_loader.py +68 -0
- package/python/pyeffic/templates/web_react/tests/test_app.py +105 -0
- package/python/pyeffic/templates/web_react/ui/main.ge.ui +33 -0
- package/python/pyeffic/templates/web_react/web/__init__.py +0 -0
- package/python/pyeffic/templates/web_react/web/server.ge.py +78 -0
- package/python/pyeffic/ts2py.py +657 -0
- package/python/pyeffic/typecheck.py +232 -0
- package/python/pyeffic/ui.py +154 -0
- package/python/pyeffic/ui_dsl.py +618 -0
- package/python/pyeffic/widgets.py +87 -0
- package/scripts/README.md +42 -0
- package/scripts/check-toolchains.py +85 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to GE. Format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Hybrid `.ge` frontend** — one file may mix Python-flavoured and
|
|
12
|
+
TypeScript-flavoured definitions. Flavour is detected per chunk.
|
|
13
|
+
- **Named blocks** — `<name> ... </name>` gives a chunk a name; `@name(...)`
|
|
14
|
+
calls it from anywhere in the file, in either flavour, forward or backward.
|
|
15
|
+
- **Mixed-backend native linking** — `ge build` emits each non-entry backend
|
|
16
|
+
in library mode with `extern "C"` exports, compiles it to an object, and
|
|
17
|
+
links one executable. No build script, no hand-written FFI.
|
|
18
|
+
- **`ge diff`** — differential testing. Runs the same program through CPython
|
|
19
|
+
and every installed backend, comparing output byte-for-byte.
|
|
20
|
+
- **`ge golden`** — golden lowering corpus. Emitted code must match the
|
|
21
|
+
committed golden, and compiling it must still print the expected output.
|
|
22
|
+
- **`ge api-check`** — committed dumps of the CLI, diagnostics, and intrinsic
|
|
23
|
+
surfaces. Drift fails the check.
|
|
24
|
+
- **`ge doctor`** — runtime and toolchain check with per-platform install
|
|
25
|
+
hints. `--json` for CI.
|
|
26
|
+
- **`ge react`** — generates a React 19 + TypeScript + Vite project from a
|
|
27
|
+
`.ge.ui` file, one component per file.
|
|
28
|
+
- **Organized build output** — `build/{desktop,web,mobile}/{backend,obj,bin}`.
|
|
29
|
+
- **npm distribution** — `npx gelang` runs the compiler with bundled source,
|
|
30
|
+
no `pip install` required.
|
|
31
|
+
- **`--target` buckets** — `desktop`, `web`, `mobile`.
|
|
32
|
+
- **Target-keyword safety** — identifiers that collide with a target
|
|
33
|
+
language's reserved words are escaped (`@base` in C#, `r#match` in Rust)
|
|
34
|
+
or renamed consistently across the ABI (`double` → `double_`).
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- C# reserved words in parameter positions emitted invalid code (`base`).
|
|
39
|
+
- Function names colliding with target keywords broke compilation
|
|
40
|
+
(`double` in C++, `match` in Rust).
|
|
41
|
+
- `from pyeffic.backends import rust` was resolved as user code, pulling the
|
|
42
|
+
compiler's own sources into the program.
|
|
43
|
+
- `ge_build`/`build_flutter` used an undefined `preamble` variable.
|
|
44
|
+
- Go backend wrote binaries next to the source instead of `build/<target>/bin`.
|
|
45
|
+
- Module resolver matched a sibling file for dotted imports
|
|
46
|
+
(`app.main` resolved to `desktop/main.ge`).
|
|
47
|
+
- `.ge.ui` parser rejected files with a leading docstring.
|
|
48
|
+
- `.ge.ui` parser only accepted `Screen "title" {}`, not `Window { title: }`.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Canonical extension is `.ge`. `.ge.py` and `.ge.ts` remain supported for
|
|
53
|
+
single-flavour files; `.ts.ge.py` is accepted as a legacy alias.
|
|
54
|
+
- Build root defaults to `build/` (was `ge_build/`).
|
|
55
|
+
- Package name on npm is `gelang`.
|
|
56
|
+
|
|
57
|
+
## [0.1.0] — 2026-09-12
|
|
58
|
+
|
|
59
|
+
Initial version.
|
|
60
|
+
|
|
61
|
+
- Python-like source language compiling to Rust, C++, C#, Zig, Go, Kotlin.
|
|
62
|
+
- Auto-selection of backend per function.
|
|
63
|
+
- Flutter/Dart UI generation from a `.ge.ui` DSL.
|
|
64
|
+
- `.ge` package format, `ge pack` / `ge install` / `ge deploy`.
|
|
65
|
+
- `ge bench` for parity benchmarking against hand-written C++.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zrald
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
# GE
|
|
2
|
+
|
|
3
|
+
**One typed source language. Native Rust, C++, C#, Zig, Go, or Kotlin — chosen per function.**
|
|
4
|
+
|
|
5
|
+
GE is a compiler. You write `.ge` files in Python-flavoured or
|
|
6
|
+
TypeScript-flavoured syntax (or both in the same file), and GE emits native
|
|
7
|
+
code for the backend that suits each function, then links it into a single
|
|
8
|
+
executable.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx gelang doctor # check what you have
|
|
12
|
+
npx gelang build main.ge --run # compile and run
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
"""main.ge — Python flavour and TypeScript flavour in one file."""
|
|
17
|
+
|
|
18
|
+
<factorial:typescript>
|
|
19
|
+
export function factorial(n: number): number {
|
|
20
|
+
if (n <= 1) {
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
let result: number = 1;
|
|
24
|
+
let i: number = 2;
|
|
25
|
+
while (i <= n) {
|
|
26
|
+
result = result * i;
|
|
27
|
+
i = i + 1;
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
</factorial>
|
|
32
|
+
|
|
33
|
+
<greet>
|
|
34
|
+
def greet(n: int) -> int:
|
|
35
|
+
return n * 7
|
|
36
|
+
</greet>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main() -> None:
|
|
40
|
+
print(@factorial(5)) # 120
|
|
41
|
+
print(@greet(6)) # 42
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
$ ge build main.ge --run
|
|
46
|
+
120
|
|
47
|
+
42
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Contents
|
|
53
|
+
|
|
54
|
+
- [Why GE](#why-ge)
|
|
55
|
+
- [Install](#install)
|
|
56
|
+
- [Quick start](#quick-start)
|
|
57
|
+
- [The language](#the-language)
|
|
58
|
+
- [Named blocks](#named-blocks)
|
|
59
|
+
- [Backends](#backends)
|
|
60
|
+
- [UI targets](#ui-targets)
|
|
61
|
+
- [CLI reference](#cli-reference)
|
|
62
|
+
- [Project layout](#project-layout)
|
|
63
|
+
- [Verification](#verification)
|
|
64
|
+
- [Compatibility](#compatibility)
|
|
65
|
+
- [Requirements](#requirements)
|
|
66
|
+
- [Troubleshooting](#troubleshooting)
|
|
67
|
+
- [Contributing](#contributing)
|
|
68
|
+
- [License](#license)
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Why GE
|
|
73
|
+
|
|
74
|
+
**One file, many languages, compiled.** Other polyglot tools interpret each
|
|
75
|
+
language at runtime. GE compiles: every flavour lowers to one typed IR, and
|
|
76
|
+
every backend emits native code from it.
|
|
77
|
+
|
|
78
|
+
**The backend is chosen per function, not per project.** A hot arithmetic
|
|
79
|
+
loop and a UI renderer have different needs. GE scores each function and
|
|
80
|
+
picks, or you pin one with `@rust`, `@cpp`, `@csharp`, `@zig`, `@go`,
|
|
81
|
+
`@kotlin`.
|
|
82
|
+
|
|
83
|
+
**Mixed backends link into one binary.** A Rust shell over C++ rendering
|
|
84
|
+
compiles to a single executable — no shared library, no IPC, no FFI
|
|
85
|
+
marshalling at runtime. `ge build` generates the `extern "C"` declarations
|
|
86
|
+
on both sides from the call graph.
|
|
87
|
+
|
|
88
|
+
**Small binaries.** A desktop app with a real window, audio capture, and
|
|
89
|
+
HTTPS is ~15 MB. The same thing in Electron is 120–200 MB.
|
|
90
|
+
|
|
91
|
+
**Two UI ecosystems from one DSL.** `.ge.ui` generates Flutter/Dart *or*
|
|
92
|
+
React 19 + TypeScript + Vite. The generated files are yours to edit;
|
|
93
|
+
regeneration never clobbers them without `--force`.
|
|
94
|
+
|
|
95
|
+
**AI-friendly by construction.** GE's input syntax *is* Python and
|
|
96
|
+
TypeScript, so existing model knowledge transfers directly. Named blocks
|
|
97
|
+
give an assistant a bounded, nameable unit with an explicit call contract,
|
|
98
|
+
and the compiler is the verifier that catches a hallucinated signature at
|
|
99
|
+
build time.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Install
|
|
104
|
+
|
|
105
|
+
### npm (recommended)
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npx gelang doctor # one-off, no install
|
|
109
|
+
npm install -g gelang # or install globally
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The npm package bundles the compiler source and runs it with your system
|
|
113
|
+
Python. No `pip install`, no network access at install time.
|
|
114
|
+
|
|
115
|
+
### pip
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
pip install gelang
|
|
119
|
+
ge doctor
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### From source
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
git clone https://github.com/Zrald1/gelang.git
|
|
126
|
+
cd gelang
|
|
127
|
+
pip install -e .
|
|
128
|
+
ge doctor
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Requirements
|
|
132
|
+
|
|
133
|
+
GE itself needs **Python 3.10+**. To compile, you need at least **one**
|
|
134
|
+
native toolchain. Each one you add widens the set of targets.
|
|
135
|
+
|
|
136
|
+
| Backend | Toolchain | Install |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| Rust | `rustc` ≥ 1.70 | `winget install Rustlang.Rustup` · `brew install rustup-init` · [rustup.rs](https://rustup.rs) |
|
|
139
|
+
| C++ | `clang++` or `g++` ≥ 10 | `winget install LLVM.LLVM` · `brew install llvm` · `apt install clang` |
|
|
140
|
+
| C# | .NET SDK ≥ 8 | `winget install Microsoft.DotNet.SDK.8` · `brew install --cask dotnet-sdk` |
|
|
141
|
+
| Zig | `zig` ≥ 0.13 | [ziglang.org/download](https://ziglang.org/download/) · `brew install zig` |
|
|
142
|
+
| Go | `go` ≥ 1.21 | `winget install GoLang.Go` · `brew install go` · `apt install golang` |
|
|
143
|
+
| Kotlin | `kotlinc-native` ≥ 2.0 | [Kotlin releases](https://github.com/JetBrains/kotlin/releases) |
|
|
144
|
+
|
|
145
|
+
Optional, for UI targets:
|
|
146
|
+
|
|
147
|
+
| Target | Toolchain | Command |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| Flutter / Dart | Flutter SDK | `ge flutter` |
|
|
150
|
+
| React + TypeScript | Node.js + npm | `ge react` |
|
|
151
|
+
|
|
152
|
+
Run `ge doctor` any time to see what is detected and what is missing.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Quick start
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# 1. check your environment
|
|
160
|
+
npx gelang doctor
|
|
161
|
+
|
|
162
|
+
# 2. scaffold a project
|
|
163
|
+
npx gelang create myapp --template desktop-gui -y
|
|
164
|
+
cd myapp
|
|
165
|
+
|
|
166
|
+
# 3. build and run
|
|
167
|
+
npx gelang build desktop/main.ge --run
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Two templates ship today:
|
|
171
|
+
|
|
172
|
+
| Template | What you get |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `desktop-gui` | Rust shell + C++ core + C++ UI (native Win32 window) |
|
|
175
|
+
| `web-react` | React 19 + TypeScript SPA + Rust backend |
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
ge create myapp --template desktop-gui -y
|
|
179
|
+
ge create myapp --template web-react -y
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## The language
|
|
185
|
+
|
|
186
|
+
### Flavours
|
|
187
|
+
|
|
188
|
+
| File | Frontend | Notes |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| `foo.ge` | **hybrid** | Canonical. Flavour detected per chunk. |
|
|
191
|
+
| `foo.ge.py` | python | Whole file is Python-flavoured |
|
|
192
|
+
| `foo.ge.ts` | typescript | Whole file is TypeScript-flavoured |
|
|
193
|
+
|
|
194
|
+
A single `.ge` file may mix both. The compiler classifies each top-level
|
|
195
|
+
chunk from its syntax and lowers it.
|
|
196
|
+
|
|
197
|
+
### Python flavour
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from pyeffic.backends import cpp, rust
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@rust
|
|
204
|
+
def checksum(data: list) -> int:
|
|
205
|
+
total: int = 0
|
|
206
|
+
for x in data:
|
|
207
|
+
total = total + x
|
|
208
|
+
return total
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@cpp
|
|
212
|
+
def render(value: int) -> int:
|
|
213
|
+
return value * 2
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### TypeScript flavour
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
export function factorial(n: number): number {
|
|
220
|
+
if (n <= 1) {
|
|
221
|
+
return 1;
|
|
222
|
+
}
|
|
223
|
+
let result: number = 1;
|
|
224
|
+
let i: number = 2;
|
|
225
|
+
while (i <= n) {
|
|
226
|
+
result = result * i;
|
|
227
|
+
i = i + 1;
|
|
228
|
+
}
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Types map as `number → int`, `string → str`, `boolean → bool`,
|
|
234
|
+
`T[] → list`, `void → None`. `console.log` becomes `print`, `Math.floor`
|
|
235
|
+
becomes `int`, `arr.length` becomes `len(arr)`.
|
|
236
|
+
|
|
237
|
+
### A Python signature with a braced body
|
|
238
|
+
|
|
239
|
+
Both spellings are accepted:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
def clamp(v: int) -> int:
|
|
243
|
+
if (v > LIMIT) {
|
|
244
|
+
return LIMIT;
|
|
245
|
+
}
|
|
246
|
+
return v;
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Escape hatches
|
|
250
|
+
|
|
251
|
+
When you need to drop to the target language:
|
|
252
|
+
|
|
253
|
+
| Python flavour | TypeScript flavour | Scope | Purpose |
|
|
254
|
+
|---|---|---|---|
|
|
255
|
+
| `ge_preamble(backend, code)` | `gePreamble(...)` | module level | File-scope injection (includes, FFI, statics) |
|
|
256
|
+
| `ge_inline(backend, code)` | `geInline(...)` | function body | Target-specific inline expression |
|
|
257
|
+
| `ge_raw(code)` | `geRaw(...)` | function body | Unconditional raw code |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Named blocks
|
|
262
|
+
|
|
263
|
+
A block gives a chunk a name and makes it callable from anywhere in the file,
|
|
264
|
+
regardless of which flavour either side uses.
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
<add>
|
|
268
|
+
def add(a: int, b: int) -> int:
|
|
269
|
+
return a + b
|
|
270
|
+
</add>
|
|
271
|
+
|
|
272
|
+
<render:typescript>
|
|
273
|
+
export function render(x: number): number {
|
|
274
|
+
return @add(x, 1); // @block(...) calls the block
|
|
275
|
+
}
|
|
276
|
+
</render>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Rules:
|
|
280
|
+
|
|
281
|
+
- `<name>` opens, `</name>` closes. Tags must match.
|
|
282
|
+
- Language is detected from the content, or pinned with
|
|
283
|
+
`<name:python>` / `<name:typescript>` (aliases `:py` / `:ts`).
|
|
284
|
+
- `@name(...)` calls the block. It resolves to the function inside the block
|
|
285
|
+
named `name`, or to the block's only function if the names differ.
|
|
286
|
+
- A call site may appear before the block it names.
|
|
287
|
+
- Backend decorators (`@cpp`, `@rust`, …) are never rewritten — `@ident(` is
|
|
288
|
+
a call, bare `@ident` is a decorator.
|
|
289
|
+
- `@name(` inside a string literal is left alone.
|
|
290
|
+
- Pin an ambiguous chunk with a marker comment:
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
# ge:typescript
|
|
294
|
+
const SCALE: number = 2;
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Backends
|
|
300
|
+
|
|
301
|
+
| Backend | Decorator | Emits | Runs as |
|
|
302
|
+
|---|---|---|---|
|
|
303
|
+
| Rust | `@rust` | `build/<target>/backend/*.rs` | native exe / cdylib |
|
|
304
|
+
| C++ | `@cpp` | `*.cpp` | native exe / object / dll |
|
|
305
|
+
| C# | `@csharp` | `*.cs` | NativeAOT exe / dll |
|
|
306
|
+
| Zig | `@zig` | `*.zig` | native exe / shared lib |
|
|
307
|
+
| Go | `@go` | `*.go` | native exe / c-shared lib |
|
|
308
|
+
| Kotlin | `@kotlin` | `*.kt` | Kotlin/Native exe / lib |
|
|
309
|
+
|
|
310
|
+
Without a decorator, GE scores each function and picks. Explicit decorators
|
|
311
|
+
always win.
|
|
312
|
+
|
|
313
|
+
### Mixed-backend linking
|
|
314
|
+
|
|
315
|
+
When a program spans more than one native backend, `ge build` does the whole
|
|
316
|
+
job itself:
|
|
317
|
+
|
|
318
|
+
1. Emits each non-entry backend in library mode with `extern "C"` exports and
|
|
319
|
+
compiles it to an object file.
|
|
320
|
+
2. Emits the entry backend (Rust by default) with matching `extern "C"`
|
|
321
|
+
declarations derived from the call graph.
|
|
322
|
+
3. Links the objects into one executable.
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
ge build desktop/main.ge --run # Rust shell + C++ core → one .exe
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
No build script and no hand-written FFI declarations are needed.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## UI targets
|
|
333
|
+
|
|
334
|
+
### Flutter / Dart
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
ge flutter app/main.ge --app-name myapp
|
|
338
|
+
cd build/mobile/myapp && flutter pub get && flutter run
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### React + TypeScript
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
ge react ui/main.ge.ui --app-name myapp
|
|
345
|
+
cd build/web/frontend && npm install && npm run dev
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
`ge react` reads a `.ge.ui` DSL file and generates a Vite project with one
|
|
349
|
+
component per file. Existing files are kept unless you pass `--force`.
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
Window {
|
|
353
|
+
title: "My App"
|
|
354
|
+
Column {
|
|
355
|
+
padding: 24
|
|
356
|
+
children:
|
|
357
|
+
Text "Hello" style="headline"
|
|
358
|
+
TextField state="query" hint="type here"
|
|
359
|
+
ElevatedButton "Run" on_click=Action(call="compute")
|
|
360
|
+
Text state="result" style="value"
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## CLI reference
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
ge doctor Check runtime + toolchains, with install hints
|
|
371
|
+
ge compilers Show detected toolchains
|
|
372
|
+
ge create [NAME] Scaffold a project (--template, --platforms, --backends)
|
|
373
|
+
ge build <file> Compile (--backend, --target, --run, -o)
|
|
374
|
+
ge analyze <file> Type check and report diagnostics
|
|
375
|
+
ge diff <file-or-dir> Prove every backend matches CPython byte-for-byte
|
|
376
|
+
ge golden --check Prove emitted code has not drifted
|
|
377
|
+
ge api-check Prove the CLI surface has not changed
|
|
378
|
+
ge react <ui.ge.ui> Generate a React + TypeScript UI
|
|
379
|
+
ge flutter <file> Build a Flutter app (native FFI lib + Dart UI)
|
|
380
|
+
ge pack <file> Bundle into a single .ge package
|
|
381
|
+
ge install <package> Unpack and build for a target
|
|
382
|
+
ge deploy <package> Distribute and run
|
|
383
|
+
ge tools list|install|check Manage toolchains
|
|
384
|
+
ge bench Benchmark against hand-written C++
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Common flags
|
|
388
|
+
|
|
389
|
+
| Flag | Meaning |
|
|
390
|
+
|---|---|
|
|
391
|
+
| `--backend rust\|cpp\|csharp\|zig\|go\|kotlin\|auto` | Force a backend (default `auto`) |
|
|
392
|
+
| `--target desktop\|web\|mobile\|crossplatform` | Platform bucket |
|
|
393
|
+
| `--entry NAME` | Entry point function (default `main`) |
|
|
394
|
+
| `-o, --out-dir DIR` | Output root (default `build`) |
|
|
395
|
+
| `--run` | Run after a successful build |
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Project layout
|
|
400
|
+
|
|
401
|
+
### Build output
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
build/
|
|
405
|
+
desktop/ native build
|
|
406
|
+
backend/ generated sources
|
|
407
|
+
obj/ object files
|
|
408
|
+
bin/ executables
|
|
409
|
+
web/ web build
|
|
410
|
+
backend/ obj/ bin/
|
|
411
|
+
mobile/ Flutter project
|
|
412
|
+
<app>/backend/ native FFI library
|
|
413
|
+
<app>/ui/ generated Dart UI
|
|
414
|
+
<app>/lib/ Dart bindings
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### A scaffolded project
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
myapp/
|
|
421
|
+
app/
|
|
422
|
+
memory/ bounded state (limits, buffers, slots)
|
|
423
|
+
core/ computation, one function per file
|
|
424
|
+
ui/ theme, layout, widgets, render
|
|
425
|
+
main.ge aggregator
|
|
426
|
+
desktop/
|
|
427
|
+
main.ge entry point
|
|
428
|
+
tests/
|
|
429
|
+
ge.toml
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Verification
|
|
435
|
+
|
|
436
|
+
GE ships the machinery to prove it is correct, not just that it runs.
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
# every backend must produce the same output as CPython
|
|
440
|
+
ge diff tests/differential
|
|
441
|
+
|
|
442
|
+
# emitted code must not drift, and must still behave
|
|
443
|
+
ge golden --check
|
|
444
|
+
|
|
445
|
+
# the CLI / diagnostics / intrinsics surface must not move
|
|
446
|
+
ge api-check
|
|
447
|
+
|
|
448
|
+
# the full suite
|
|
449
|
+
python -m unittest discover tests
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
| Guard | What it catches |
|
|
453
|
+
|---|---|
|
|
454
|
+
| `ge diff` | Backend-specific codegen bugs, semantic drift from Python |
|
|
455
|
+
| `ge golden` | Silent emitter churn — code that still compiles but changed |
|
|
456
|
+
| `ge api-check` | Renamed flags, removed commands, reused diagnostic codes |
|
|
457
|
+
| Test suite | Everything else, including 600 compile-and-run cases |
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Compatibility
|
|
462
|
+
|
|
463
|
+
GE is pre-1.0. The promise and the mechanisms behind it are documented in
|
|
464
|
+
[`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md):
|
|
465
|
+
|
|
466
|
+
- A released `.ge` program keeps compiling and keeps producing the same
|
|
467
|
+
output, within its edition.
|
|
468
|
+
- Breaking changes go into a new **edition** — never a patch or minor release.
|
|
469
|
+
- Editions interoperate: a module on a newer edition is importable from an
|
|
470
|
+
older one.
|
|
471
|
+
- Deprecations last at least two minor releases with a published removal
|
|
472
|
+
version.
|
|
473
|
+
- Unstable features require explicit opt-in.
|
|
474
|
+
|
|
475
|
+
See also [`docs/STABILITY.md`](docs/STABILITY.md) (how it works) and
|
|
476
|
+
[`docs/PRODUCTION_GAPS.md`](docs/PRODUCTION_GAPS.md) (what is not done yet).
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Requirements
|
|
481
|
+
|
|
482
|
+
| Component | Minimum |
|
|
483
|
+
|---|---|
|
|
484
|
+
| Python | 3.10 |
|
|
485
|
+
| Node.js (npm install only) | 16 |
|
|
486
|
+
| rustc | 1.70 |
|
|
487
|
+
| clang++ / g++ | 10 |
|
|
488
|
+
| .NET SDK | 8 |
|
|
489
|
+
| zig | 0.13 |
|
|
490
|
+
| go | 1.21 |
|
|
491
|
+
| kotlinc-native | 2.0 |
|
|
492
|
+
|
|
493
|
+
GE detects whatever versions you have — no pinned toolchains, no version
|
|
494
|
+
switching.
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Troubleshooting
|
|
499
|
+
|
|
500
|
+
**`GE needs Python 3.10 or newer`**
|
|
501
|
+
Install Python, or point GE at one with `GE_PYTHON=/path/to/python`.
|
|
502
|
+
|
|
503
|
+
**`0 of 6 native backends available`**
|
|
504
|
+
You need at least one compiler. `ge doctor` prints the install command for
|
|
505
|
+
your platform.
|
|
506
|
+
|
|
507
|
+
**A build succeeds but nothing runs**
|
|
508
|
+
Some constructs fall back to CPython instead of native code. The build
|
|
509
|
+
summary lists them under `fallback:`. See
|
|
510
|
+
[`docs/PRODUCTION_GAPS.md`](docs/PRODUCTION_GAPS.md) §C4.
|
|
511
|
+
|
|
512
|
+
**`ge build` says "renamed 'x' -> 'x_'"**
|
|
513
|
+
`x` is a reserved word in a target language (e.g. `double` is a C++ type).
|
|
514
|
+
GE renames the symbol consistently on both sides of the ABI.
|
|
515
|
+
|
|
516
|
+
**Generated React files were overwritten**
|
|
517
|
+
They are not, unless you pass `--force`. `ge react` only writes files that do
|
|
518
|
+
not exist.
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## Contributing
|
|
523
|
+
|
|
524
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md). Two guides for extending GE:
|
|
525
|
+
|
|
526
|
+
- **Add a backend** — `pyeffic/emitters/<name>.py` + a `Spec` + a compiler entry
|
|
527
|
+
- **Add a frontend** — `pyeffic/frontends/<name>.py` + suffix registration
|
|
528
|
+
|
|
529
|
+
`AGENTS.md` documents the architecture in detail for AI coding agents.
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## License
|
|
534
|
+
|
|
535
|
+
MIT. See [`LICENSE`](LICENSE).
|