Skip to content

Commit 70f1413

Browse files
Feat and Docs: Update CLI to implement inline commands, and README.md for compiler.
1 parent e08cc2d commit 70f1413

2 files changed

Lines changed: 81 additions & 10 deletions

File tree

compiler/README.md

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,77 @@
1-
*Update this documentation upon completion of the compiler (https://edgepython.com/resources/architecture)*
1+
## Edge Python
2+
3+
Single-pass SSA compiler for Python 3.13: logos lexer, token-to-bytecode parser, adaptive VM with inline caching, template memoization, and configurable sandbox limits.
4+
5+
---
6+
7+
### Architecture
8+
9+
- **Lexer**: DFA-driven tokenization, offset-indexed, zero-alloc
10+
- **Parser**: Single-pass SSA, phi nodes, precedence climbing, direct bytecode emission
11+
- **VM**: Adaptive stack machine, inline caching, template memoization
12+
- **Sandbox**: Configurable recursion, operation, and heap limits
13+
14+
### Quick Start
15+
16+
```bash
17+
cd compiler/
18+
19+
cargo build --release
20+
./target/release/edge -c 'print("Hello, world!")'
21+
```
22+
23+
### Usage
24+
25+
| Command | Description |
26+
|---------------------------------|---------------------------------------------------|
27+
| `edge script.py` | Run with no limits |
28+
| `edge --sandbox script.py` | Run with sandbox (512 calls, 100M ops, 100K heap) |
29+
| `edge -d --sandbox script.py` | Debug output (verbosity level 1) |
30+
| `edge -dd --sandbox script.py` | Debug output (verbosity level 2) |
31+
32+
### Building for WebAssembly
33+
34+
```bash
35+
rustup target add wasm32-unknown-unknown
36+
cargo build --target wasm32-unknown-unknown --release --no-default-features --features wasm
37+
```
38+
39+
*Exported functions: `src_ptr()`, `out_ptr()`, `run(len: usize)` -> `usize`*
40+
41+
### Project Structure
242

343
```bash
44+
├── Cargo.lock
45+
├── Cargo.toml
46+
├── main.py
47+
├── README.md
48+
├── src
49+
│ ├── lib.rs
50+
│ ├── main.rs
51+
│ ├── modules
52+
│ │ ├── lexer.rs
53+
│ │ ├── parser.rs
54+
│ │ └── vm.rs
55+
│ └── wasm.rs
56+
└── tests
57+
├── cases
58+
│ ├── lexer_cases.json
59+
│ ├── parser_cases.json
60+
│ └── vm_cases.json
61+
├── integration_test.rs
62+
├── lexer_test.rs
63+
├── parser_test.rs
64+
└── vm_test.rs
65+
```
466

5-
lexer.rs
6-
Tokenizes Python source into a stream of spanned Token variants.
67+
### Tests
768

8-
parser.rs
9-
Single-pass SSA bytecode emitter. No AST. Variables versioned on assignment (new def per write), phi-joined (select reaching defs) at control flow boundaries.
69+
```bash
70+
cargo test
71+
cargo test -- --ignored
72+
cargo test --features wasm-tests
1073
```
1174

12-
*upx packer*
75+
### License
76+
77+
MIT OR Apache-2.0

compiler/src/main.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ use log::{debug, info, error};
55
fn parse_args() -> (String, usize, bool, bool) {
66
let args: Vec<_> = env::args().skip(1).collect();
77
if args.is_empty() || args.contains(&"-h".into()) {
8-
println!("usage: edge [-d] [-dd] [-q] [--sandbox] <file>"); exit(0)
8+
println!("usage: edge [-c code] [-d] [-dd] [-q] [--sandbox] <file>"); exit(0)
9+
}
10+
if let Some(pos) = args.iter().position(|a| a == "-c") {
11+
let code = args.get(pos + 1).cloned().unwrap_or_default();
12+
return (code, 0, false, false);
913
}
1014
let p = args.iter().find(|&a| !a.starts_with('-')).cloned().unwrap_or_else(|| {
1115
eprintln!("abort: execution failed because no input target was specified"); exit(1)
@@ -15,9 +19,11 @@ fn parse_args() -> (String, usize, bool, bool) {
1519
}
1620

1721
fn run(path: &str, v: usize, q: bool, sandbox: bool) -> Result<(), Box<dyn std::error::Error>> {
18-
stderrlog::new().module(module_path!()).verbosity(v).quiet(q).init().ok();
19-
20-
let src = fs::read_to_string(path).map_err(|e| format!("io: cannot access '{}' because {}", path, e))?;
22+
let src = if path.ends_with(".py") {
23+
fs::read_to_string(path).map_err(|e| format!("io: cannot access '{}' because {}", path, e))?
24+
} else {
25+
path.to_string()
26+
};
2127

2228
let (chunk, errs) = Parser::new(&src, lexer(&src)).parse();
2329
if !errs.is_empty() {

0 commit comments

Comments
 (0)