Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
Python v2 is a programming language that lets you work quickly and integrate
systems more effectively — same energy as the original snake, without the
paper cuts. No indentation errors. Real closures. F-strings that just work.
A ternary that reads left to right. And it runs **right in your browser**.
Structured errors you can actually recover from. A ternary that reads left to
right. And it runs **right in your browser**.

```python
# hello.pyv2
Expand Down Expand Up @@ -45,6 +46,7 @@ The product is: 384
| `nonlocal` scavenger hunts | closures just work |
| `"n=" + str(n)` | `"n=" + n` |
| `x if ok else y` (backwards) | `ok ? x : y` |
| exception classes for routine app errors | `catch error` gives a useful map; `finally` always runs |
| `assert` is a keyword with moods | `assert(cond, msg)` is a function |
| trailing commas *sometimes* | trailing commas & multi-line everything |
| one runtime | two parity-tested runtimes — CLI **and** browser |
Expand Down Expand Up @@ -206,8 +208,8 @@ The short version:
$ python3 -m unittest discover -s tests -t .
```

**108 tests pass:** 63 language tests, 9 PyHope engine tests, 14 production-app/build tests,
13 workspace/Launcher tests, 8 arcade/Playground site tests, plus a parity harness that runs 25 programs (including error paths) through both the
**112 tests pass:** 67 language tests, 9 PyHope engine tests, 14 production-app/build tests,
13 workspace/Launcher tests, 8 arcade/Playground site tests, plus a parity harness that runs 28 programs (including error paths) through both the
Python and JavaScript runtimes and demands byte-identical output.

## 📦 Repo layout
Expand Down
26 changes: 24 additions & 2 deletions docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<link rel="stylesheet" href="style.css">
</head>
<body>
<a class="skip-link" href="#main-content">Skip to content</a>

<!-- ============ top utility bar ============ -->
<div class="topbar">
Expand Down Expand Up @@ -69,7 +70,7 @@ <h1>Documentation</h1>
</div>
</section>

<main class="doc-section">
<main id="main-content" class="doc-section">
<div class="doc-section-inner">

<!-- ==================== INSTALL ==================== -->
Expand Down Expand Up @@ -508,17 +509,38 @@ <h3>Statements</h3>
<tr><td>while</td><td><code>while running: step() end</code></td></tr>
<tr><td>for</td><td><code>for item in [1, 2, 3]: print(item) end</code></td></tr>
<tr><td>range loop</td><td><code>for i in range(1, 10, 2): print(i) end</code></td></tr>
<tr><td>recover</td><td><code>try: risky() catch error: print(error.kind) finally: cleanup() end</code></td></tr>
<tr><td>raise</td><td><code>raise {kind: "ConfigError", message: "port required"}</code></td></tr>
<tr><td>jump</td><td><code>return</code>, <code>break</code>, <code>continue</code></td></tr>
</tbody>
</table>

<h3>Structured error recovery</h3>
<p>Runtime errors are catchable values. A named <code>catch</code> receives a map with
<code>kind</code>, <code>message</code>, <code>line</code>, and <code>trace</code>.
The optional <code>finally</code> block always runs, including during
<code>return</code>, <code>break</code>, and <code>continue</code>.</p>
<pre class="terminal"><code>try:
result = 100 / divisor
catch error:
print(error.kind + ":", error.message)
result = 0
finally:
print("calculation complete")
end</code></pre>
<p><code>raise "message"</code> creates a <code>UserError</code>. Raise a map with string
<code>kind</code> and <code>message</code> fields to create a named application error.
Syntax errors are detected before execution and are not catchable.</p>

<h3>Builtins</h3>
<table class="ref-table">
<thead><tr><th>Function</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>print(...)</code></td><td>Print values, space-separated</td></tr>
<tr><td><code>len(x)</code></td><td>Length of string / list / map / range</td></tr>
<tr><td><code>range(stop)</code> · <code>range(a, b, step)</code></td><td>Integer range</td></tr>
<tr><td><code>sum</code> · <code>enumerate</code> · <code>zip</code></td><td>Iterable aggregation and pairing</td></tr>
<tr><td><code>all</code> · <code>any</code></td><td>Truth tests across an iterable</td></tr>
<tr><td><code>str</code> <code>int</code> <code>float</code> <code>bool</code> <code>repr</code></td><td>Conversions</td></tr>
<tr><td><code>abs floor ceil round sqrt pow</code></td><td>Math</td></tr>
<tr><td><code>min</code> · <code>max</code></td><td>Over arguments or one list</td></tr>
Expand Down Expand Up @@ -596,7 +618,7 @@ <h4>Community</h4>
<a href="https://github.com/gefrus112/pythonv2">GitHub</a>
<a href="https://github.com/gefrus112/pythonv2/issues">Issues</a>
<a href="index.html#news">News</a>
<a href="index.html#news">Events</a>
<a href="index.html#events">Events</a>
</div>
<div class="footer-col">
<h4>Success Stories</h4>
Expand Down
57 changes: 46 additions & 11 deletions docs/LANGUAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Hello, stranger!
## 2. Syntax at a glance

* **Statements** are separated by newlines. Blank lines are ignored.
* **Blocks** open after `:` and close with `end` (for `if`, `while`, `for`, `fn`).
* **Blocks** open after `:` and close with `end` (for `if`, `while`, `for`, `fn`, `try`).
Indentation is cosmetic — tabs vs. spaces can never break your program.
* One-liners are fine: `fn sq(x): return x * x end`
* **Trailing commas** are allowed in lists, maps, calls and parameter lists,
Expand Down Expand Up @@ -132,7 +132,34 @@ end
`for` iterates lists (a snapshot — mutation during the loop is safe), strings
(characters), maps (keys) and ranges.

### 2.5 Functions
### 2.5 Recoverable errors

Use `try`, `catch`, and `finally` for structured recovery. A named catch receives
an inspectable map with `kind`, `message`, `line`, and `trace` fields. `finally`
always runs—even when the protected block returns, breaks, continues, or raises.

```python
try:
config = json_decode(read_text("settings.json"))
catch error:
print(f"Could not load settings: {error.kind} — {error.message}")
config = {theme: "dark"}
finally:
print("Settings check complete")
end
```

Create a `UserError` by raising any value, or supply a map to choose the kind:

```python
raise "The operation stopped"
raise {kind: "ConfigError", message: "port is required"}
```

Either `catch`, `finally`, or both are required. A bare `catch:` is allowed when
the program does not need the error details.

### 2.6 Functions

```python
fn add(a, b):
Expand All @@ -152,7 +179,7 @@ ZeroDivisionError: Division by zero at line 3
in outer (line 5)
```

### 2.6 Strings & f-strings
### 2.7 Strings & f-strings

```python
name = "Ada"
Expand All @@ -162,7 +189,7 @@ print(f"{{literal braces}} survive")

Anything inside `{…}` is a full expression. `{{` and `}}` produce literal braces.

### 2.7 Data structures
### 2.8 Data structures

```python
xs = [3, 1, 2]
Expand All @@ -186,6 +213,10 @@ hero.scores.push(30)
| `print(...)` | print values, space-separated |
| `len(x)` | length of string / list / map / range |
| `range(stop)` `range(a, b)` `range(a, b, step)` | integer range |
| `sum(items, start?)` | add numbers from an iterable |
| `enumerate(items, start?)` | list of `[index, value]` pairs |
| `zip(a, b, ...)` | rows from iterables, stopping at the shortest |
| `all(items)` / `any(items)` | truth tests across an iterable |
| `str(x)` `repr(x)` `int(x)` `float(x)` `bool(x)` | conversions |
| `abs(x)` `floor(x)` `ceil(x)` `round(x, digits)` `sqrt(x)` `pow(a, b)` | math |
| `min(...)` / `max(...)` | over arguments or one list |
Expand Down Expand Up @@ -235,9 +266,11 @@ Errors are `Kind: message at line N` with an optional call trace:

`SyntaxError`, `NameError`, `TypeError`, `IndexError`, `KeyError`,
`ZeroDivisionError`, `ValueError`, `OverflowError`, `AssertionError`,
`AttributeError`, `CapabilityError`, `RuntimeError`.
`AttributeError`, `CapabilityError`, `RuntimeError`, `UserError`.

The CLI exits with status 1 on error; the playground prints the error in red
Runtime errors can be recovered with `try` / `catch`; syntax errors happen before
execution and cannot be caught. The CLI exits with status 1 on an uncaught error;
the playground prints the error in red
and keeps your code.

## 5. What's better than Python v1
Expand All @@ -248,6 +281,7 @@ and keeps your code.
| `nonlocal` required for closure writes | assignment finds the binding, period |
| `"n=" + str(n)` | `"n=" + n` |
| `x if ok else y` (reads backwards) | `ok ? x : y` |
| exceptions need class boilerplate | caught errors are useful `kind` / `message` / `line` / `trace` maps |
| `assert` is a statement | `assert()` is a function |
| trailing commas only *sometimes* | trailing commas everywhere |
| one runtime | two parity-tested runtimes, one in your browser |
Expand All @@ -257,13 +291,14 @@ and keeps your code.
```ebnf
program := stmt*
stmt := simple | compound
simple := "return" expr? | "break" | "continue" | assign | expr
compound := if | while | for | fn
simple := "return" expr? | "raise" expr | "break" | "continue" | assign | expr
compound := if | while | for | fn | try
if := "if" expr ":" block ("elif" expr ":" block)* ("else" ":" block)? "end"
while := "while" expr ":" block "end"
for := "for" IDENT "in" expr ":" block "end"
fn := "fn" IDENT "(" params ")" ":" block "end"
block := stmt* until "end" / "elif" / "else"
try := "try" ":" block ("catch" IDENT? ":" block)? ("finally" ":" block)? "end"
block := stmt* until its compound terminator
assign := target ("=" | "+=" | "-=" | "*=" | "/=" | "%=") expr
target := IDENT | index | attr
ternary := or ("?" ternary ":" ternary)?
Expand Down Expand Up @@ -305,8 +340,8 @@ non-Windows binary.

## 8. Parity guarantee

The suite runs **108 tests**: 63 language tests, 9 PyHope engine tests, 14 production-app/build tests,
8 arcade/Playground site tests, 13 workspace/Launcher tests, and one parity harness that sends 25 programs (including error paths) through
The suite runs **112 tests**: 67 language tests, 9 PyHope engine tests, 14 production-app/build tests,
8 arcade/Playground site tests, 13 workspace/Launcher tests, and one parity harness that sends 28 programs (including error paths) through
**both** language runtimes and compares outputs byte for byte. If the twins
ever disagree, the suite fails. That's the deal.

Expand Down
7 changes: 4 additions & 3 deletions download.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<link rel="stylesheet" href="style.css">
</head>
<body>
<a class="skip-link" href="#main-content">Skip to content</a>

<!-- ============ top utility bar ============ -->
<div class="topbar">
Expand Down Expand Up @@ -67,7 +68,7 @@ <h1>Downloads &amp; Installation</h1>
</div>
</section>

<main class="doc-section">
<main id="main-content" class="doc-section">
<div class="doc-section-inner">

<!-- ==================== APP ==================== -->
Expand Down Expand Up @@ -211,7 +212,7 @@ <h3>What's in the box</h3>
<tr><td>Examples</td><td><code>examples/</code></td><td>hello, fib, fizzbuzz, terminal_raycast</td></tr>
<tr><td>VS Code extension</td><td><code>editors/vscode/</code></td><td>Syntax highlighting + snippets</td></tr>
<tr><td>Dev container</td><td><code>.devcontainer/</code></td><td>Ready environment for VS Code / Codespaces</td></tr>
<tr><td>Tests</td><td><code>tests/</code></td><td>108 tests: language + app/EXE builder + parity + PyHope + workspace + Playground + arcade</td></tr>
<tr><td>Tests</td><td><code>tests/</code></td><td>112 tests: language + app/EXE builder + parity + PyHope + workspace + Playground + arcade</td></tr>
</tbody>
</table>

Expand Down Expand Up @@ -370,7 +371,7 @@ <h4>Community</h4>
<a href="https://github.com/gefrus112/pythonv2">GitHub</a>
<a href="https://github.com/gefrus112/pythonv2/issues">Issues</a>
<a href="index.html#news">News</a>
<a href="index.html#news">Events</a>
<a href="index.html#events">Events</a>
</div>
<div class="footer-col">
<h4>Success Stories</h4>
Expand Down
24 changes: 24 additions & 0 deletions editors/vscode/snippets/pyv2.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@
],
"description": "For loop over a range"
},
"try-catch": {
"prefix": "trycatch",
"body": [
"try:",
" ${1:work}",
"catch ${2:error}:",
" ${3:print(error.kind, error.message)}",
"end"
],
"description": "Recover from a runtime error"
},
"try-catch-finally": {
"prefix": "tryfinal",
"body": [
"try:",
" ${1:work}",
"catch ${2:error}:",
" ${3:recovery}",
"finally:",
" ${4:cleanup}",
"end"
],
"description": "Recover from an error and always clean up"
},
"f-string": {
"prefix": "fstr",
"body": "f\"${1:text} {${2:expr}}\"",
Expand Down
2 changes: 1 addition & 1 deletion editors/vscode/syntaxes/pyv2.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"patterns": [
{
"name": "keyword.control.pyv2",
"match": "\\b(if|elif|else|while|for|in|return|break|continue)\\b"
"match": "\\b(if|elif|else|while|for|in|return|raise|try|catch|finally|break|continue)\\b"
},
{
"name": "storage.type.function.pyv2",
Expand Down
27 changes: 27 additions & 0 deletions examples/error_recovery.pyv2
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# error_recovery.pyv2 — structured failures without exception classes

fn parse_port(raw):
if raw == "":
raise {kind: "ConfigError", message: "port is required"}
end
port = int(raw)
if port < 1 or port > 65535:
raise {kind: "ConfigError", message: "port must be between 1 and 65535"}
end
return port
end

inputs = ["8080", "", "70000", "not-a-number"]
for raw in inputs:
try:
port = parse_port(raw)
print("ready:", port)
catch error:
print(error.kind + ":", error.message, "at line", error.line)
finally:
print("checked", repr(raw))
end
end

print("numbered inputs:", enumerate(inputs, 1))
print("numeric total:", sum([8000, 80]))
3 changes: 2 additions & 1 deletion games.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<link rel="stylesheet" href="style.css">
</head>
<body>
<a class="skip-link" href="#main-content">Skip to content</a>
<div class="scroll-progress" id="scroll-progress" aria-hidden="true"></div>

<div class="topbar">
Expand Down Expand Up @@ -73,7 +74,7 @@ <h2>Help @CubeCometYT reach 1K</h2>
<a class="btn-youtube btn-youtube-big" href="https://www.youtube.com/@CubeCometYT" target="_blank" rel="noopener">Subscribe on YouTube</a>
</aside>

<main class="games-main">
<main id="main-content" class="games-main">
<div class="game-tabs" role="tablist" aria-label="Games and engine sections">
<button role="tab" data-game-tab="play" aria-selected="true">🎮 10 Games</button>
<button role="tab" data-game-tab="gpu">⚡ 9M GPU Lab</button>
Expand Down
27 changes: 16 additions & 11 deletions guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<link rel="stylesheet" href="style.css">
</head>
<body>
<a class="skip-link" href="#main-content">Skip to content</a>
<div class="topbar"><nav class="topbar-inner" aria-label="Site"><a href="index.html">Python</a><a href="docs.html">Docs</a><a href="download.html">Downloads</a><a href="tutorial.html">Tutorial</a><a href="games.html">Games</a><a class="active" href="guide.html">50 Guides</a><a href="playground.html">Playground</a></nav></div>
<header class="masthead"><div class="masthead-inner">
<a class="brand" href="index.html"><img src="logo-v2.svg" alt="Python v2 red and blue snakes" width="64" height="64"><span class="brand-word">python<sup>™</sup><em>v2</em></span></a>
Expand All @@ -23,7 +24,7 @@ <h1>50 things worth knowing</h1>
closures, editor setup, CC0 sprites, DDA ray casting and a 9.4-million-pixel GPU frame.</p>
</div></section>

<main class="guide-main">
<main id="main-content" class="guide-main">
<div class="guide-toolbar">
<label for="guide-search">Search all 50 topics</label>
<input id="guide-search" type="search" placeholder="Try: closures, sprites, VS Code, raycast…" autocomplete="off">
Expand Down Expand Up @@ -210,12 +211,15 @@ <h3>push and pop</h3>
<h3>Slices</h3>
<p>slice(start, end) makes a new string or list and supports negative positions.</p>
<pre><code>print([0, 1, 2, 3].slice(1, 3))</code></pre>
</article><article class="guide-card" data-category="data" data-search="sorting lists sort returns a new list, while sort_by accepts a key function. print([3, 1, 2].sort())">
</article><article class="guide-card" data-category="data" data-search="iterable toolkit sort sum enumerate zip all any lists ranges strings maps print(sum(range(5)))">
<div class="guide-number">24</div>
<div class="guide-category">Data</div>
<h3>Sorting lists</h3>
<p>sort returns a new list, while sort_by accepts a key function.</p>
<pre><code>print([3, 1, 2].sort())</code></pre>
<h3>Iterable toolkit</h3>
<p>Sort, total, number, pair, or truth-test iterable values with concise builtins.</p>
<pre><code>print([3, 1, 2].sort())
print(sum(range(5)))
print(enumerate([&quot;a&quot;, &quot;b&quot;], 1))
print(zip([1, 2], [&quot;a&quot;, &quot;b&quot;]))</code></pre>
</article><article class="guide-card" data-category="data" data-search="map literals bare identifier keys become strings; quoted and computed keys work too. hero = {name: &quot;ada&quot;, hp: 100}">
<div class="guide-number">25</div>
<div class="guide-category">Data</div>
Expand Down Expand Up @@ -316,14 +320,15 @@ <h3>Conversions</h3>
<h3>Assertions</h3>
<p>assert is a normal function and accepts your own message.</p>
<pre><code>assert(len([1, 2]) == 2, &quot;list size changed&quot;)</code></pre>
</article><article class="guide-card" data-category="tools" data-search="read errors errors include a kind, message, source line, and function stack frames. fn boom(): return missing end
boom()">
</article><article class="guide-card" data-category="tools" data-search="recover errors try catch finally raise kind message line trace cleanup">
<div class="guide-number">37</div>
<div class="guide-category">Tools</div>
<h3>Read errors</h3>
<p>Errors include a kind, message, source line, and function stack frames.</p>
<pre><code>fn boom(): return missing end
boom()</code></pre>
<h3>Recover from errors</h3>
<p>Catch runtime failures as maps with kind, message, line, and trace; finally always runs.</p>
<pre><code>try: raise &quot;stop&quot;
catch error: print(error.kind, error.message)
finally: print(&quot;clean&quot;)
end</code></pre>
</article><article class="guide-card" data-category="tools" data-search="use the repl run pyv2 with no file for an interactive prompt; ctrl-d exits. python3 -m pyv2">
<div class="guide-number">38</div>
<div class="guide-category">Tools</div>
Expand Down
Loading
Loading