snail-lang 0.3.4__tar.gz → 0.3.7__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.
- {snail_lang-0.3.4 → snail_lang-0.3.7}/Cargo.lock +10 -27
- {snail_lang-0.3.4 → snail_lang-0.3.7}/PKG-INFO +27 -15
- {snail_lang-0.3.4 → snail_lang-0.3.7}/README.md +26 -14
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-ast/Cargo.toml +1 -1
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-ast/README.md +1 -3
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-ast/src/ast.rs +3 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-core/Cargo.toml +2 -3
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-core/README.md +5 -9
- snail_lang-0.3.7/crates/snail-core/src/lib.rs +36 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-error/Cargo.toml +1 -1
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-error/src/lib.rs +15 -7
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-lower/Cargo.toml +2 -2
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-lower/README.md +7 -8
- snail_lang-0.3.7/crates/snail-lower/src/awk.rs +470 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-lower/src/constants.rs +2 -3
- snail_lang-0.3.7/crates/snail-lower/src/expr.rs +1391 -0
- snail_lang-0.3.7/crates/snail-lower/src/helpers.rs +103 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-lower/src/lib.rs +5 -2
- snail_lang-0.3.7/crates/snail-lower/src/operators.rs +69 -0
- snail_lang-0.3.7/crates/snail-lower/src/program.rs +176 -0
- snail_lang-0.3.7/crates/snail-lower/src/py_ast.rs +80 -0
- snail_lang-0.3.7/crates/snail-lower/src/stmt.rs +686 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/Cargo.toml +1 -1
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/src/expr.rs +6 -0
- snail_lang-0.3.7/crates/snail-parser/src/lib.rs +418 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/src/snail.pest +4 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/src/string.rs +1 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/src/util.rs +1 -0
- snail_lang-0.3.7/crates/snail-parser/tests/common.rs +84 -0
- snail_lang-0.3.7/crates/snail-parser/tests/errors.rs +195 -0
- snail_lang-0.3.7/crates/snail-parser/tests/parser.rs +634 -0
- snail_lang-0.3.7/crates/snail-parser/tests/statements.rs +409 -0
- snail_lang-0.3.7/crates/snail-parser/tests/syntax_expressions.rs +369 -0
- snail_lang-0.3.7/crates/snail-parser/tests/syntax_strings.rs +92 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-python/Cargo.toml +1 -1
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-python/src/lib.rs +29 -17
- {snail_lang-0.3.4 → snail_lang-0.3.7}/pyproject.toml +1 -1
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/cli.py +2 -0
- snail_lang-0.3.7/python/snail/runtime/__init__.py +59 -0
- snail_lang-0.3.7/python/snail/runtime/structured_accessor.py +75 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/runtime/subprocess.py +2 -2
- snail_lang-0.3.4/crates/snail-codegen/Cargo.toml +0 -9
- snail_lang-0.3.4/crates/snail-codegen/README.md +0 -41
- snail_lang-0.3.4/crates/snail-codegen/src/expr.rs +0 -483
- snail_lang-0.3.4/crates/snail-codegen/src/lib.rs +0 -58
- snail_lang-0.3.4/crates/snail-codegen/src/writer.rs +0 -217
- snail_lang-0.3.4/crates/snail-core/src/lib.rs +0 -33
- snail_lang-0.3.4/crates/snail-lower/src/awk.rs +0 -360
- snail_lang-0.3.4/crates/snail-lower/src/expr.rs +0 -560
- snail_lang-0.3.4/crates/snail-lower/src/helpers.rs +0 -49
- snail_lang-0.3.4/crates/snail-lower/src/operators.rs +0 -42
- snail_lang-0.3.4/crates/snail-lower/src/program.rs +0 -87
- snail_lang-0.3.4/crates/snail-lower/src/span.rs +0 -65
- snail_lang-0.3.4/crates/snail-lower/src/stmt.rs +0 -270
- snail_lang-0.3.4/crates/snail-parser/src/lib.rs +0 -85
- snail_lang-0.3.4/crates/snail-parser/tests/parser.rs +0 -819
- snail_lang-0.3.4/crates/snail-python-ast/Cargo.toml +0 -8
- snail_lang-0.3.4/crates/snail-python-ast/README.md +0 -32
- snail_lang-0.3.4/crates/snail-python-ast/src/lib.rs +0 -311
- snail_lang-0.3.4/python/snail/runtime/__init__.py +0 -25
- snail_lang-0.3.4/python/snail/runtime/structured_accessor.py +0 -71
- {snail_lang-0.3.4 → snail_lang-0.3.7}/Cargo.toml +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/LICENSE +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-ast/src/awk.rs +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-ast/src/lib.rs +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-error/README.md +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/README.md +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/src/awk.rs +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/src/literal.rs +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/crates/snail-parser/src/stmt.rs +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/__init__.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/runtime/compact_try.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/runtime/regex.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/__init__.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/LICENSE +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/__init__.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/ast.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/compat.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/exceptions.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/functions.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/lexer.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/parser.py +0 -0
- {snail_lang-0.3.4 → snail_lang-0.3.7}/python/snail/vendor/jmespath/visitor.py +0 -0
|
@@ -485,47 +485,38 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|
|
485
485
|
|
|
486
486
|
[[package]]
|
|
487
487
|
name = "snail-ast"
|
|
488
|
-
version = "0.3.
|
|
489
|
-
|
|
490
|
-
[[package]]
|
|
491
|
-
name = "snail-codegen"
|
|
492
|
-
version = "0.3.4"
|
|
493
|
-
dependencies = [
|
|
494
|
-
"snail-ast",
|
|
495
|
-
"snail-python-ast",
|
|
496
|
-
]
|
|
488
|
+
version = "0.3.7"
|
|
497
489
|
|
|
498
490
|
[[package]]
|
|
499
491
|
name = "snail-core"
|
|
500
|
-
version = "0.3.
|
|
492
|
+
version = "0.3.7"
|
|
501
493
|
dependencies = [
|
|
494
|
+
"pyo3",
|
|
502
495
|
"snail-ast",
|
|
503
|
-
"snail-codegen",
|
|
504
496
|
"snail-error",
|
|
505
497
|
"snail-lower",
|
|
506
498
|
"snail-parser",
|
|
507
|
-
"snail-python-ast",
|
|
508
499
|
]
|
|
509
500
|
|
|
510
501
|
[[package]]
|
|
511
502
|
name = "snail-error"
|
|
512
|
-
version = "0.3.
|
|
503
|
+
version = "0.3.7"
|
|
513
504
|
dependencies = [
|
|
514
505
|
"snail-ast",
|
|
515
506
|
]
|
|
516
507
|
|
|
517
508
|
[[package]]
|
|
518
509
|
name = "snail-lower"
|
|
519
|
-
version = "0.3.
|
|
510
|
+
version = "0.3.7"
|
|
520
511
|
dependencies = [
|
|
512
|
+
"pyo3",
|
|
521
513
|
"snail-ast",
|
|
522
514
|
"snail-error",
|
|
523
|
-
"snail-python-ast",
|
|
524
515
|
]
|
|
525
516
|
|
|
526
517
|
[[package]]
|
|
527
518
|
name = "snail-parser"
|
|
528
|
-
version = "0.3.
|
|
519
|
+
version = "0.3.7"
|
|
529
520
|
dependencies = [
|
|
530
521
|
"pest",
|
|
531
522
|
"pest_derive",
|
|
@@ -535,34 +526,26 @@ dependencies = [
|
|
|
535
526
|
|
|
536
527
|
[[package]]
|
|
537
528
|
name = "snail-proptest"
|
|
538
|
-
version = "0.3.
|
|
529
|
+
version = "0.3.7"
|
|
539
530
|
dependencies = [
|
|
540
531
|
"proptest",
|
|
532
|
+
"pyo3",
|
|
541
533
|
"snail-ast",
|
|
542
|
-
"snail-codegen",
|
|
543
534
|
"snail-core",
|
|
544
535
|
"snail-error",
|
|
545
536
|
"snail-lower",
|
|
546
537
|
"snail-parser",
|
|
547
|
-
"snail-python-ast",
|
|
548
538
|
"tempfile",
|
|
549
539
|
]
|
|
550
540
|
|
|
551
541
|
[[package]]
|
|
552
542
|
name = "snail-python"
|
|
553
|
-
version = "0.3.
|
|
543
|
+
version = "0.3.7"
|
|
554
544
|
dependencies = [
|
|
555
545
|
"pyo3",
|
|
556
546
|
"snail-core",
|
|
557
547
|
]
|
|
558
548
|
|
|
559
|
-
[[package]]
|
|
560
|
-
name = "snail-python-ast"
|
|
561
|
-
version = "0.3.4"
|
|
562
|
-
dependencies = [
|
|
563
|
-
"snail-ast",
|
|
564
|
-
]
|
|
565
|
-
|
|
566
549
|
[[package]]
|
|
567
550
|
name = "syn"
|
|
568
551
|
version = "2.0.114"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: snail-lang
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Requires-Dist: maturin>=1.5 ; extra == 'dev'
|
|
5
5
|
Requires-Dist: pytest ; extra == 'dev'
|
|
6
6
|
Provides-Extra: dev
|
|
@@ -64,7 +64,7 @@ The `?` operator makes error handling terse yet expressive:
|
|
|
64
64
|
err = risky_operation()?
|
|
65
65
|
|
|
66
66
|
# Provide a fallback value (exception available as $e)
|
|
67
|
-
value =
|
|
67
|
+
value = js(data):{}?
|
|
68
68
|
details = fetch_url(url):"Error: {$e}"?
|
|
69
69
|
|
|
70
70
|
# Access attributes directly
|
|
@@ -101,7 +101,7 @@ Built-in variables: `$l` (line), `$f` (fields), `$n` (line number), `$fn` (per-f
|
|
|
101
101
|
|
|
102
102
|
### Pipeline Operator
|
|
103
103
|
|
|
104
|
-
The `|` operator enables data pipelining through
|
|
104
|
+
The `|` operator enables data pipelining through pipeline-aware callables:
|
|
105
105
|
|
|
106
106
|
```snail
|
|
107
107
|
# Pipe data to subprocess stdin
|
|
@@ -112,23 +112,37 @@ output = "foo\nbar" | $(grep foo) | $(wc -l)
|
|
|
112
112
|
|
|
113
113
|
# Custom pipeline handlers
|
|
114
114
|
class Doubler {
|
|
115
|
-
def
|
|
115
|
+
def __call__(self, x) { return x * 2 }
|
|
116
116
|
}
|
|
117
117
|
doubled = 21 | Doubler() # yields 42
|
|
118
|
+
|
|
119
|
+
# Use placeholders to control where piped values land in calls
|
|
120
|
+
greeting = "World" | greet("Hello ", _) # greet("Hello ", "World")
|
|
121
|
+
excited = "World" | greet(_, "!") # greet("World", "!")
|
|
122
|
+
formal = "World" | greet("Hello ", suffix=_) # greet("Hello ", "World")
|
|
118
123
|
```
|
|
119
124
|
|
|
125
|
+
When a pipeline targets a call expression, the left-hand value is passed to the
|
|
126
|
+
resulting callable. If the call includes a single `_` placeholder, Snail substitutes
|
|
127
|
+
the piped value at that position (including keyword arguments). Only one
|
|
128
|
+
placeholder is allowed in a piped call. Outside of pipeline calls, `_` remains a
|
|
129
|
+
normal identifier.
|
|
130
|
+
|
|
120
131
|
### JSON Queries with JMESPath
|
|
121
132
|
|
|
122
|
-
Parse and query JSON data with the `
|
|
133
|
+
Parse and query JSON data with the `js()` function and structured pipeline accessor:
|
|
123
134
|
|
|
124
135
|
```snail
|
|
125
136
|
# Parse JSON and query with $[jmespath]
|
|
126
|
-
data =
|
|
137
|
+
data = js($(curl -s api.example.com/users))
|
|
127
138
|
names = data | $[users[*].name]
|
|
128
139
|
first_email = data | $[users[0].email]
|
|
129
140
|
|
|
130
141
|
# Inline parsing and querying
|
|
131
|
-
result =
|
|
142
|
+
result = js('{"foo": 12}') | $[foo]
|
|
143
|
+
|
|
144
|
+
# JSONL parsing returns a list
|
|
145
|
+
names = js('{"name": "Ada"}\n{"name": "Lin"}') | $[[*].name]
|
|
132
146
|
```
|
|
133
147
|
|
|
134
148
|
### Full Python Interoperability
|
|
@@ -147,7 +161,7 @@ filtered = df[df["value"] > 100]
|
|
|
147
161
|
|
|
148
162
|
```bash
|
|
149
163
|
# Install from PyPI
|
|
150
|
-
pip install snail
|
|
164
|
+
pip install snail-lang
|
|
151
165
|
|
|
152
166
|
# Run a one-liner
|
|
153
167
|
snail "print('Hello, Snail!')"
|
|
@@ -179,10 +193,9 @@ flowchart TB
|
|
|
179
193
|
C2[crates/snail-ast/src/awk.rs<br/>AwkProgram AST]
|
|
180
194
|
end
|
|
181
195
|
|
|
182
|
-
subgraph Lowering["Lowering
|
|
196
|
+
subgraph Lowering["Lowering"]
|
|
183
197
|
D1[crates/snail-lower/<br/>AST → Python AST Transform]
|
|
184
198
|
D2[python/snail/runtime/<br/>Runtime Helpers]
|
|
185
|
-
D3[crates/snail-codegen/<br/>Python AST → Source Code]
|
|
186
199
|
end
|
|
187
200
|
|
|
188
201
|
subgraph Execution
|
|
@@ -198,9 +211,8 @@ flowchart TB
|
|
|
198
211
|
C1 --> D1
|
|
199
212
|
C2 --> D1
|
|
200
213
|
D1 --> D2
|
|
201
|
-
D1 -->
|
|
202
|
-
D2 -->
|
|
203
|
-
D3 --> E1
|
|
214
|
+
D1 --> E1
|
|
215
|
+
D2 --> E1
|
|
204
216
|
E1 --> E2
|
|
205
217
|
E2 --> F[Python Execution]
|
|
206
218
|
|
|
@@ -218,7 +230,7 @@ flowchart TB
|
|
|
218
230
|
- `$(cmd)` subprocess capture → `__SnailSubprocessCapture`
|
|
219
231
|
- `@(cmd)` subprocess status → `__SnailSubprocessStatus`
|
|
220
232
|
- Regex literals → `__snail_regex_search` and `__snail_regex_compile`
|
|
221
|
-
- **
|
|
233
|
+
- **Execution**: Compiles Python AST directly for in-process execution
|
|
222
234
|
- **CLI**: Python wrapper (`python/snail/cli.py`) that executes via the extension module
|
|
223
235
|
|
|
224
236
|
## 📚 Documentation
|
|
@@ -333,7 +345,7 @@ python3 -m venv myenv
|
|
|
333
345
|
source myenv/bin/activate # On Windows: myenv\Scripts\activate
|
|
334
346
|
|
|
335
347
|
# Install and run
|
|
336
|
-
pip install snail
|
|
348
|
+
pip install snail-lang
|
|
337
349
|
snail "import sys; print(sys.prefix)"
|
|
338
350
|
```
|
|
339
351
|
|
|
@@ -53,7 +53,7 @@ The `?` operator makes error handling terse yet expressive:
|
|
|
53
53
|
err = risky_operation()?
|
|
54
54
|
|
|
55
55
|
# Provide a fallback value (exception available as $e)
|
|
56
|
-
value =
|
|
56
|
+
value = js(data):{}?
|
|
57
57
|
details = fetch_url(url):"Error: {$e}"?
|
|
58
58
|
|
|
59
59
|
# Access attributes directly
|
|
@@ -90,7 +90,7 @@ Built-in variables: `$l` (line), `$f` (fields), `$n` (line number), `$fn` (per-f
|
|
|
90
90
|
|
|
91
91
|
### Pipeline Operator
|
|
92
92
|
|
|
93
|
-
The `|` operator enables data pipelining through
|
|
93
|
+
The `|` operator enables data pipelining through pipeline-aware callables:
|
|
94
94
|
|
|
95
95
|
```snail
|
|
96
96
|
# Pipe data to subprocess stdin
|
|
@@ -101,23 +101,37 @@ output = "foo\nbar" | $(grep foo) | $(wc -l)
|
|
|
101
101
|
|
|
102
102
|
# Custom pipeline handlers
|
|
103
103
|
class Doubler {
|
|
104
|
-
def
|
|
104
|
+
def __call__(self, x) { return x * 2 }
|
|
105
105
|
}
|
|
106
106
|
doubled = 21 | Doubler() # yields 42
|
|
107
|
+
|
|
108
|
+
# Use placeholders to control where piped values land in calls
|
|
109
|
+
greeting = "World" | greet("Hello ", _) # greet("Hello ", "World")
|
|
110
|
+
excited = "World" | greet(_, "!") # greet("World", "!")
|
|
111
|
+
formal = "World" | greet("Hello ", suffix=_) # greet("Hello ", "World")
|
|
107
112
|
```
|
|
108
113
|
|
|
114
|
+
When a pipeline targets a call expression, the left-hand value is passed to the
|
|
115
|
+
resulting callable. If the call includes a single `_` placeholder, Snail substitutes
|
|
116
|
+
the piped value at that position (including keyword arguments). Only one
|
|
117
|
+
placeholder is allowed in a piped call. Outside of pipeline calls, `_` remains a
|
|
118
|
+
normal identifier.
|
|
119
|
+
|
|
109
120
|
### JSON Queries with JMESPath
|
|
110
121
|
|
|
111
|
-
Parse and query JSON data with the `
|
|
122
|
+
Parse and query JSON data with the `js()` function and structured pipeline accessor:
|
|
112
123
|
|
|
113
124
|
```snail
|
|
114
125
|
# Parse JSON and query with $[jmespath]
|
|
115
|
-
data =
|
|
126
|
+
data = js($(curl -s api.example.com/users))
|
|
116
127
|
names = data | $[users[*].name]
|
|
117
128
|
first_email = data | $[users[0].email]
|
|
118
129
|
|
|
119
130
|
# Inline parsing and querying
|
|
120
|
-
result =
|
|
131
|
+
result = js('{"foo": 12}') | $[foo]
|
|
132
|
+
|
|
133
|
+
# JSONL parsing returns a list
|
|
134
|
+
names = js('{"name": "Ada"}\n{"name": "Lin"}') | $[[*].name]
|
|
121
135
|
```
|
|
122
136
|
|
|
123
137
|
### Full Python Interoperability
|
|
@@ -136,7 +150,7 @@ filtered = df[df["value"] > 100]
|
|
|
136
150
|
|
|
137
151
|
```bash
|
|
138
152
|
# Install from PyPI
|
|
139
|
-
pip install snail
|
|
153
|
+
pip install snail-lang
|
|
140
154
|
|
|
141
155
|
# Run a one-liner
|
|
142
156
|
snail "print('Hello, Snail!')"
|
|
@@ -168,10 +182,9 @@ flowchart TB
|
|
|
168
182
|
C2[crates/snail-ast/src/awk.rs<br/>AwkProgram AST]
|
|
169
183
|
end
|
|
170
184
|
|
|
171
|
-
subgraph Lowering["Lowering
|
|
185
|
+
subgraph Lowering["Lowering"]
|
|
172
186
|
D1[crates/snail-lower/<br/>AST → Python AST Transform]
|
|
173
187
|
D2[python/snail/runtime/<br/>Runtime Helpers]
|
|
174
|
-
D3[crates/snail-codegen/<br/>Python AST → Source Code]
|
|
175
188
|
end
|
|
176
189
|
|
|
177
190
|
subgraph Execution
|
|
@@ -187,9 +200,8 @@ flowchart TB
|
|
|
187
200
|
C1 --> D1
|
|
188
201
|
C2 --> D1
|
|
189
202
|
D1 --> D2
|
|
190
|
-
D1 -->
|
|
191
|
-
D2 -->
|
|
192
|
-
D3 --> E1
|
|
203
|
+
D1 --> E1
|
|
204
|
+
D2 --> E1
|
|
193
205
|
E1 --> E2
|
|
194
206
|
E2 --> F[Python Execution]
|
|
195
207
|
|
|
@@ -207,7 +219,7 @@ flowchart TB
|
|
|
207
219
|
- `$(cmd)` subprocess capture → `__SnailSubprocessCapture`
|
|
208
220
|
- `@(cmd)` subprocess status → `__SnailSubprocessStatus`
|
|
209
221
|
- Regex literals → `__snail_regex_search` and `__snail_regex_compile`
|
|
210
|
-
- **
|
|
222
|
+
- **Execution**: Compiles Python AST directly for in-process execution
|
|
211
223
|
- **CLI**: Python wrapper (`python/snail/cli.py`) that executes via the extension module
|
|
212
224
|
|
|
213
225
|
## 📚 Documentation
|
|
@@ -322,7 +334,7 @@ python3 -m venv myenv
|
|
|
322
334
|
source myenv/bin/activate # On Windows: myenv\Scripts\activate
|
|
323
335
|
|
|
324
336
|
# Install and run
|
|
325
|
-
pip install snail
|
|
337
|
+
pip install snail-lang
|
|
326
338
|
snail "import sys; print(sys.prefix)"
|
|
327
339
|
```
|
|
328
340
|
|
|
@@ -21,11 +21,9 @@ None - this crate has no dependencies and provides pure data structures.
|
|
|
21
21
|
|
|
22
22
|
## Used By
|
|
23
23
|
|
|
24
|
-
- **snail-python-ast**: Uses `SourceSpan` and `StringDelimiter` for its own AST nodes
|
|
25
24
|
- **snail-error**: Uses `SourceSpan` for error reporting with source locations
|
|
26
25
|
- **snail-parser**: Produces `Program` and `AwkProgram` as output
|
|
27
|
-
- **snail-lower**: Consumes Snail AST and transforms it to Python
|
|
28
|
-
- **snail-codegen**: Uses `StringDelimiter` for string literal formatting
|
|
26
|
+
- **snail-lower**: Consumes Snail AST and transforms it to Python `ast` nodes via pyo3
|
|
29
27
|
- **snail-core**: Re-exports all types for the unified API
|
|
30
28
|
|
|
31
29
|
## Design
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "snail-core"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.7"
|
|
4
4
|
edition.workspace = true
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
|
|
7
7
|
[dependencies]
|
|
8
8
|
snail-ast = { path = "../snail-ast" }
|
|
9
|
-
snail-python-ast = { path = "../snail-python-ast" }
|
|
10
9
|
snail-error = { path = "../snail-error" }
|
|
11
10
|
snail-parser = { path = "../snail-parser" }
|
|
12
11
|
snail-lower = { path = "../snail-lower" }
|
|
13
|
-
|
|
12
|
+
pyo3 = { version = "0.21", features = ["abi3-py310"] }
|
|
@@ -4,27 +4,24 @@ Unified compilation API for the Snail programming language.
|
|
|
4
4
|
|
|
5
5
|
## Purpose
|
|
6
6
|
|
|
7
|
-
This crate serves as the main entry point for Snail compilation. It re-exports
|
|
7
|
+
This crate serves as the main entry point for Snail compilation. It re-exports types from the workspace crates and provides high-level compilation functions that orchestrate the complete pipeline from source code to Python `ast` nodes.
|
|
8
8
|
|
|
9
9
|
## Key Components
|
|
10
10
|
|
|
11
|
-
- **compile_snail_source()**: One-step compilation from Snail source to Python
|
|
11
|
+
- **compile_snail_source()**: One-step compilation from Snail source to Python `ast` module
|
|
12
12
|
- **compile_snail_source_with_auto_print()**: Compilation with optional auto-print for CLI usage
|
|
13
|
-
- Re-exports from
|
|
13
|
+
- Re-exports from workspace crates:
|
|
14
14
|
- `snail-ast`: All AST types
|
|
15
|
-
- `snail-python-ast`: All Python AST types
|
|
16
15
|
- `snail-error`: Error types and formatting
|
|
17
16
|
- `snail-parser`: Parsing functions
|
|
18
17
|
- `snail-lower`: Lowering functions
|
|
19
|
-
- `snail-codegen`: Code generation functions
|
|
20
18
|
|
|
21
19
|
## Compilation Pipeline
|
|
22
20
|
|
|
23
21
|
The `compile_snail_source()` function orchestrates the complete compilation:
|
|
24
22
|
|
|
25
23
|
1. **Parse**: `parse_program()` or `parse_awk_program()` → Snail AST
|
|
26
|
-
2. **Lower**: `lower_program()` or `lower_awk_program()` → Python
|
|
27
|
-
3. **Codegen**: `python_source()` → Python source string
|
|
24
|
+
2. **Lower**: `lower_program()` or `lower_awk_program()` → Python `ast.Module`
|
|
28
25
|
|
|
29
26
|
Each stage can fail with appropriate error types (`ParseError` or `LowerError`), wrapped in the unified `SnailError` type.
|
|
30
27
|
|
|
@@ -45,11 +42,10 @@ This enables REPL-like behavior for interactive use and CLI one-liners.
|
|
|
45
42
|
## Dependencies
|
|
46
43
|
|
|
47
44
|
- **snail-ast**: Core AST types
|
|
48
|
-
- **snail-python-ast**: Python AST types
|
|
49
45
|
- **snail-error**: Error handling
|
|
50
46
|
- **snail-parser**: Parsing logic
|
|
51
47
|
- **snail-lower**: AST transformation
|
|
52
|
-
- **
|
|
48
|
+
- **pyo3**: Python AST construction
|
|
53
49
|
|
|
54
50
|
## Used By
|
|
55
51
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
use pyo3::prelude::*;
|
|
2
|
+
|
|
3
|
+
// Re-export all workspace crates for unified API
|
|
4
|
+
pub use snail_ast::*;
|
|
5
|
+
pub use snail_error::*;
|
|
6
|
+
pub use snail_lower::*;
|
|
7
|
+
pub use snail_parser::*;
|
|
8
|
+
|
|
9
|
+
/// Compilation API
|
|
10
|
+
pub fn compile_snail_source(
|
|
11
|
+
py: Python<'_>,
|
|
12
|
+
source: &str,
|
|
13
|
+
mode: CompileMode,
|
|
14
|
+
) -> Result<PyObject, SnailError> {
|
|
15
|
+
compile_snail_source_with_auto_print(py, source, mode, false)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pub fn compile_snail_source_with_auto_print(
|
|
19
|
+
py: Python<'_>,
|
|
20
|
+
source: &str,
|
|
21
|
+
mode: CompileMode,
|
|
22
|
+
auto_print_last: bool,
|
|
23
|
+
) -> Result<PyObject, SnailError> {
|
|
24
|
+
match mode {
|
|
25
|
+
CompileMode::Snail => {
|
|
26
|
+
let program = parse_program(source)?;
|
|
27
|
+
let module = lower_program_with_auto_print(py, &program, auto_print_last)?;
|
|
28
|
+
Ok(module)
|
|
29
|
+
}
|
|
30
|
+
CompileMode::Awk => {
|
|
31
|
+
let program = parse_awk_program(source)?;
|
|
32
|
+
let module = lower_awk_program_with_auto_print(py, &program, auto_print_last)?;
|
|
33
|
+
Ok(module)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -42,21 +42,29 @@ impl fmt::Display for ParseError {
|
|
|
42
42
|
impl Error for ParseError {}
|
|
43
43
|
|
|
44
44
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
45
|
-
pub
|
|
46
|
-
|
|
45
|
+
pub enum LowerError {
|
|
46
|
+
Message(String),
|
|
47
|
+
MultiplePlaceholders { span: SourceSpan },
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
impl LowerError {
|
|
50
51
|
pub fn new(message: impl Into<String>) -> Self {
|
|
51
|
-
Self
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
Self::Message(message.into())
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn multiple_placeholders(span: SourceSpan) -> Self {
|
|
56
|
+
Self::MultiplePlaceholders { span }
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
impl fmt::Display for LowerError {
|
|
58
61
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
59
|
-
|
|
62
|
+
match self {
|
|
63
|
+
LowerError::Message(message) => write!(f, "{message}"),
|
|
64
|
+
LowerError::MultiplePlaceholders { .. } => {
|
|
65
|
+
write!(f, "pipeline calls may include at most one placeholder")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
|
|
@@ -101,7 +109,7 @@ impl From<LowerError> for SnailError {
|
|
|
101
109
|
pub fn format_snail_error(err: &SnailError, filename: &str) -> String {
|
|
102
110
|
match err {
|
|
103
111
|
SnailError::Parse(parse) => format_parse_error(parse, filename),
|
|
104
|
-
SnailError::Lower(lower) => format!("error: {}"
|
|
112
|
+
SnailError::Lower(lower) => format!("error: {lower}"),
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
115
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "snail-lower"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.7"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
|
|
7
7
|
[dependencies]
|
|
8
8
|
snail-ast = { path = "../snail-ast" }
|
|
9
|
-
snail-python-ast = { path = "../snail-python-ast" }
|
|
10
9
|
snail-error = { path = "../snail-error" }
|
|
10
|
+
pyo3 = { version = "0.21", features = ["abi3-py310"] }
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# snail-lower
|
|
2
2
|
|
|
3
|
-
AST transformation layer that lowers Snail AST to Python
|
|
3
|
+
AST transformation layer that lowers Snail AST to Python `ast` nodes via pyo3.
|
|
4
4
|
|
|
5
5
|
## Purpose
|
|
6
6
|
|
|
7
|
-
This crate is the semantic transformation core of the Snail compiler. It takes Snail AST nodes and transforms them into equivalent Python
|
|
7
|
+
This crate is the semantic transformation core of the Snail compiler. It takes Snail AST nodes and transforms them into equivalent Python `ast` nodes, handling all Snail-specific features by generating appropriate Python AST patterns and helper function calls.
|
|
8
8
|
|
|
9
9
|
## Key Components
|
|
10
10
|
|
|
11
|
-
- **lower_program()**: Transforms a regular `Program` to `
|
|
12
|
-
- **lower_awk_program()**: Transforms an `AwkProgram` to `
|
|
11
|
+
- **lower_program()**: Transforms a regular `Program` to a Python `ast.Module`
|
|
12
|
+
- **lower_awk_program()**: Transforms an `AwkProgram` to a Python `ast.Module` with awk runtime
|
|
13
13
|
- **lower_awk_program_with_auto_print()**: Awk lowering with optional auto-print
|
|
14
14
|
- Helper constants for generated Python code:
|
|
15
15
|
- `SNAIL_TRY_HELPER`: Name for the `?` operator helper function
|
|
@@ -31,7 +31,7 @@ This crate is the semantic transformation core of the Snail compiler. It takes S
|
|
|
31
31
|
|
|
32
32
|
## Awk Mode Lowering
|
|
33
33
|
|
|
34
|
-
When lowering awk programs, generates a complete Python
|
|
34
|
+
When lowering awk programs, generates a complete Python AST that:
|
|
35
35
|
1. Imports `sys` for accessing command-line arguments and stdin
|
|
36
36
|
2. Executes BEGIN blocks before processing input
|
|
37
37
|
3. Creates a main loop that reads lines from files or stdin
|
|
@@ -42,15 +42,14 @@ When lowering awk programs, generates a complete Python program that:
|
|
|
42
42
|
## Dependencies
|
|
43
43
|
|
|
44
44
|
- **snail-ast**: Consumes Snail `Program` and `AwkProgram`
|
|
45
|
-
- **
|
|
45
|
+
- **pyo3**: Constructs Python `ast` nodes
|
|
46
46
|
- **snail-error**: Returns `LowerError` on transformation failures
|
|
47
47
|
|
|
48
48
|
## Used By
|
|
49
49
|
|
|
50
|
-
- **snail-codegen**: Consumes the Python AST to generate source code
|
|
51
50
|
- **snail-core**: Calls lowering functions as part of the compilation pipeline
|
|
52
51
|
- Tests validate transformation correctness
|
|
53
52
|
|
|
54
53
|
## Design
|
|
55
54
|
|
|
56
|
-
The lowering process preserves Python semantics exactly - only syntax differs.
|
|
55
|
+
The lowering process preserves Python semantics exactly - only syntax differs. `SourceSpan` information is used to populate Python AST location metadata for accurate error reporting.
|