snail-lang 0.7.1__tar.gz → 0.7.3__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 (59) hide show
  1. {snail_lang-0.7.1 → snail_lang-0.7.3}/Cargo.lock +5 -5
  2. {snail_lang-0.7.1 → snail_lang-0.7.3}/PKG-INFO +26 -1
  3. {snail_lang-0.7.1 → snail_lang-0.7.3}/README.md +25 -0
  4. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-ast/Cargo.toml +1 -1
  5. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-error/Cargo.toml +1 -1
  6. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/Cargo.toml +1 -1
  7. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/snail.pest +2 -2
  8. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/tests/syntax_expressions.rs +9 -0
  9. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/Cargo.toml +1 -1
  10. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/constants.rs +3 -0
  11. {snail_lang-0.7.1 → snail_lang-0.7.3}/pyproject.toml +1 -1
  12. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/cli.py +37 -0
  13. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/__init__.py +11 -0
  14. snail_lang-0.7.3/python/snail/runtime/env.py +26 -0
  15. {snail_lang-0.7.1 → snail_lang-0.7.3}/Cargo.toml +0 -0
  16. {snail_lang-0.7.1 → snail_lang-0.7.3}/LICENSE +0 -0
  17. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-ast/README.md +0 -0
  18. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-ast/src/ast.rs +0 -0
  19. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-ast/src/awk.rs +0 -0
  20. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-ast/src/lib.rs +0 -0
  21. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-error/README.md +0 -0
  22. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-error/src/lib.rs +0 -0
  23. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/README.md +0 -0
  24. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/awk.rs +0 -0
  25. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/expr.rs +0 -0
  26. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/lib.rs +0 -0
  27. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/literal.rs +0 -0
  28. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/stmt.rs +0 -0
  29. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/string.rs +0 -0
  30. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/src/util.rs +0 -0
  31. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/tests/common.rs +0 -0
  32. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/tests/errors.rs +0 -0
  33. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/tests/parser.rs +0 -0
  34. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/tests/statements.rs +0 -0
  35. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-parser/tests/syntax_strings.rs +0 -0
  36. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/build.rs +0 -0
  37. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/compiler.rs +0 -0
  38. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lib.rs +0 -0
  39. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/linecache.rs +0 -0
  40. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/awk.rs +0 -0
  41. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/desugar.rs +0 -0
  42. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/expr.rs +0 -0
  43. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/helpers.rs +0 -0
  44. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/map.rs +0 -0
  45. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/mod.rs +0 -0
  46. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/operators.rs +0 -0
  47. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/program.rs +0 -0
  48. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/py_ast.rs +0 -0
  49. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/stmt.rs +0 -0
  50. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/lower/validate.rs +0 -0
  51. {snail_lang-0.7.1 → snail_lang-0.7.3}/crates/snail-python/src/profiling.rs +0 -0
  52. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/__init__.py +0 -0
  53. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/augmented.py +0 -0
  54. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/compact_try.py +0 -0
  55. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/lazy_file.py +0 -0
  56. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/lazy_text.py +0 -0
  57. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/regex.py +0 -0
  58. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/structured_accessor.py +0 -0
  59. {snail_lang-0.7.1 → snail_lang-0.7.3}/python/snail/runtime/subprocess.py +0 -0
@@ -312,25 +312,25 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
312
312
 
313
313
  [[package]]
314
314
  name = "snail-ast"
315
- version = "0.7.1"
315
+ version = "0.7.3"
316
316
 
317
317
  [[package]]
318
318
  name = "snail-error"
319
- version = "0.7.1"
319
+ version = "0.7.3"
320
320
  dependencies = [
321
321
  "snail-ast",
322
322
  ]
323
323
 
324
324
  [[package]]
325
325
  name = "snail-lower"
326
- version = "0.7.1"
326
+ version = "0.7.3"
327
327
  dependencies = [
328
328
  "snail-python",
329
329
  ]
330
330
 
331
331
  [[package]]
332
332
  name = "snail-parser"
333
- version = "0.7.1"
333
+ version = "0.7.3"
334
334
  dependencies = [
335
335
  "pest",
336
336
  "pest_derive",
@@ -340,7 +340,7 @@ dependencies = [
340
340
 
341
341
  [[package]]
342
342
  name = "snail-python"
343
- version = "0.7.1"
343
+ version = "0.7.3"
344
344
  dependencies = [
345
345
  "pyo3",
346
346
  "snail-ast",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: snail-lang
3
- Version: 0.7.1
3
+ Version: 0.7.3
4
4
  Requires-Dist: astunparse>=1.6.3 ; python_full_version < '3.9'
5
5
  Requires-Dist: jmespath>=1.0.1
6
6
  Requires-Dist: maturin>=1.5 ; extra == 'dev'
@@ -76,6 +76,7 @@ END { print("done") }
76
76
  | `$p` | Current file path |
77
77
  | `$m` | Last regex match object |
78
78
 
79
+
79
80
  Begin/end blocks can live in the source file (`BEGIN { ... }` / `END { ... }`) or be supplied
80
81
  via CLI flags (`-b`/`--begin`, `-e`/`--end`) for setup and teardown. CLI BEGIN blocks run
81
82
  before in-file BEGIN blocks; CLI END blocks run after in-file END blocks.
@@ -113,6 +114,13 @@ BEGIN/END blocks are regular Snail blocks, so awk/map-only `$` variables are not
113
114
  snail --map --begin "print('start')" --end "print('done')" "print($src)" *.txt
114
115
  ```
115
116
 
117
+ ### Built-in Variables (All Modes)
118
+
119
+ | Variable | Description |
120
+ |----------|-------------|
121
+ | `$e` | Exception object in `expr:fallback?` |
122
+ | `$env` | Environment map (wrapper around `os.environ`) |
123
+
116
124
  ### Compact Error Handling
117
125
 
118
126
  The `?` operator makes error handling terse yet expressive:
@@ -263,6 +271,9 @@ snail 'if let [_, user, domain] = "user@example.com" in /^[\w.]+@([\w.]+)$/ { pr
263
271
 
264
272
  # Awk mode: print line numbers for matches
265
273
  rg -n "TODO" README.md | snail --awk '/TODO/ { print("{$n}: {$0}") }'
274
+
275
+ # Environment variables
276
+ snail 'print($env.PATH)'
266
277
  ```
267
278
 
268
279
  ## 📚 Documentation
@@ -316,3 +327,17 @@ make test
316
327
  make install
317
328
  ```
318
329
 
330
+ ### Arch Linux (PKGBUILD)
331
+
332
+ An Arch package build file is available at `extras/arch/PKGBUILD`.
333
+
334
+ ```bash
335
+ mkdir -p /tmp/snail-pkg
336
+ cp extras/arch/PKGBUILD /tmp/snail-pkg/
337
+ cd /tmp/snail-pkg
338
+
339
+ # Update pkgver and sha256sums as needed, then build and install
340
+ makepkg -si
341
+ ```
342
+
343
+
@@ -63,6 +63,7 @@ END { print("done") }
63
63
  | `$p` | Current file path |
64
64
  | `$m` | Last regex match object |
65
65
 
66
+
66
67
  Begin/end blocks can live in the source file (`BEGIN { ... }` / `END { ... }`) or be supplied
67
68
  via CLI flags (`-b`/`--begin`, `-e`/`--end`) for setup and teardown. CLI BEGIN blocks run
68
69
  before in-file BEGIN blocks; CLI END blocks run after in-file END blocks.
@@ -100,6 +101,13 @@ BEGIN/END blocks are regular Snail blocks, so awk/map-only `$` variables are not
100
101
  snail --map --begin "print('start')" --end "print('done')" "print($src)" *.txt
101
102
  ```
102
103
 
104
+ ### Built-in Variables (All Modes)
105
+
106
+ | Variable | Description |
107
+ |----------|-------------|
108
+ | `$e` | Exception object in `expr:fallback?` |
109
+ | `$env` | Environment map (wrapper around `os.environ`) |
110
+
103
111
  ### Compact Error Handling
104
112
 
105
113
  The `?` operator makes error handling terse yet expressive:
@@ -250,6 +258,9 @@ snail 'if let [_, user, domain] = "user@example.com" in /^[\w.]+@([\w.]+)$/ { pr
250
258
 
251
259
  # Awk mode: print line numbers for matches
252
260
  rg -n "TODO" README.md | snail --awk '/TODO/ { print("{$n}: {$0}") }'
261
+
262
+ # Environment variables
263
+ snail 'print($env.PATH)'
253
264
  ```
254
265
 
255
266
  ## 📚 Documentation
@@ -302,3 +313,17 @@ cd snail
302
313
  make test
303
314
  make install
304
315
  ```
316
+
317
+ ### Arch Linux (PKGBUILD)
318
+
319
+ An Arch package build file is available at `extras/arch/PKGBUILD`.
320
+
321
+ ```bash
322
+ mkdir -p /tmp/snail-pkg
323
+ cp extras/arch/PKGBUILD /tmp/snail-pkg/
324
+ cd /tmp/snail-pkg
325
+
326
+ # Update pkgver and sha256sums as needed, then build and install
327
+ makepkg -si
328
+ ```
329
+
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "snail-ast"
3
- version = "0.7.1"
3
+ version = "0.7.3"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "snail-error"
3
- version = "0.7.1"
3
+ version = "0.7.3"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "snail-parser"
3
- version = "0.7.1"
3
+ version = "0.7.3"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -250,9 +250,9 @@ boolean = { "True" | "False" }
250
250
  none = { "None" }
251
251
 
252
252
  // Special variables: exception, AWK fields, map vars, injected vars
253
- exception_var = { "$e" }
253
+ exception_var = { "$e" ~ !ident_continue }
254
254
  field_index_var = @{ "$" ~ ASCII_DIGIT+ }
255
- injected_var = { "$text" | "$src" | "$fn" | "$fd" | "$n" | "$p" | "$m" | "$f" }
255
+ injected_var = { "$text" | "$src" | "$env" | "$fn" | "$fd" | "$n" | "$p" | "$m" | "$f" }
256
256
 
257
257
  // Number, string, and regex literals
258
258
  number = @{ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
@@ -293,6 +293,15 @@ fn parses_structured_accessor_with_pipeline() {
293
293
  }
294
294
  }
295
295
 
296
+ #[test]
297
+ fn parses_env_var() {
298
+ let program = parse_ok("value = $env");
299
+ assert_eq!(program.stmts.len(), 1);
300
+
301
+ let (_, value) = expect_assign(&program.stmts[0]);
302
+ expect_name(value, "$env");
303
+ }
304
+
296
305
  #[test]
297
306
  fn parses_empty_structured_accessor() {
298
307
  let program = parse_ok("result = $[]");
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "snail-python"
3
- version = "0.7.1"
3
+ version = "0.7.3"
4
4
  edition.workspace = true
5
5
  build = "build.rs"
6
6
 
@@ -37,9 +37,11 @@ pub(crate) const SNAIL_AWK_MATCH_PYVAR: &str = "__snail_match";
37
37
  pub(crate) const SNAIL_MAP_SRC: &str = "$src";
38
38
  pub(crate) const SNAIL_MAP_FD: &str = "$fd";
39
39
  pub(crate) const SNAIL_MAP_TEXT: &str = "$text";
40
+ pub(crate) const SNAIL_ENV: &str = "$env";
40
41
  pub(crate) const SNAIL_MAP_SRC_PYVAR: &str = "__snail_src";
41
42
  pub(crate) const SNAIL_MAP_FD_PYVAR: &str = "__snail_fd";
42
43
  pub(crate) const SNAIL_MAP_TEXT_PYVAR: &str = "__snail_text";
44
+ pub(crate) const SNAIL_ENV_PYVAR: &str = "__snail_env";
43
45
  pub const SNAIL_LAZY_TEXT_CLASS: &str = "__SnailLazyText";
44
46
  pub const SNAIL_LAZY_FILE_CLASS: &str = "__SnailLazyFile";
45
47
 
@@ -55,6 +57,7 @@ pub(crate) fn injected_py_name(name: &str) -> Option<&'static str> {
55
57
  SNAIL_MAP_SRC => Some(SNAIL_MAP_SRC_PYVAR),
56
58
  SNAIL_MAP_FD => Some(SNAIL_MAP_FD_PYVAR),
57
59
  SNAIL_MAP_TEXT => Some(SNAIL_MAP_TEXT_PYVAR),
60
+ SNAIL_ENV => Some(SNAIL_ENV_PYVAR),
58
61
  _ => None,
59
62
  }
60
63
  }
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "snail-lang"
7
- version = "0.7.1"
7
+ version = "0.7.3"
8
8
  description = "Snail programming language interpreter"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -99,6 +99,7 @@ class _Args:
99
99
  self.no_auto_import = False
100
100
  self.debug = False
101
101
  self.debug_snail_ast = False
102
+ self.debug_python_ast = False
102
103
  self.version = False
103
104
  self.help = False
104
105
  self.begin_code: list[str] = []
@@ -132,6 +133,7 @@ def _print_help(file=None) -> None:
132
133
  print(" -I, --no-auto-import disable auto-imports", file=file)
133
134
  print(" --debug parse and compile, then print, do not run", file=file)
134
135
  print(" --debug-snail-ast parse and print Snail AST, do not run", file=file)
136
+ print(" --debug-python-ast parse and print Python AST, do not run", file=file)
135
137
  print(" -v, --version show version and exit", file=file)
136
138
  print(" -h, --help show this help message and exit", file=file)
137
139
 
@@ -234,6 +236,10 @@ def _parse_args(argv: list[str]) -> _Args:
234
236
  args.debug_snail_ast = True
235
237
  idx += 1
236
238
  continue
239
+ if token == "--debug-python-ast":
240
+ args.debug_python_ast = True
241
+ idx += 1
242
+ continue
237
243
  if token == "-f":
238
244
  if idx + 1 >= len(argv):
239
245
  raise ValueError("option -f requires an argument")
@@ -282,6 +288,18 @@ def _get_version() -> str:
282
288
  return version
283
289
 
284
290
 
291
+ def _format_python_runtime() -> str:
292
+ version = (
293
+ f"{sys.version_info.major}."
294
+ f"{sys.version_info.minor}."
295
+ f"{sys.version_info.micro}"
296
+ )
297
+ executable = sys.executable or "<unknown>"
298
+ if executable != "<unknown>":
299
+ executable = os.path.abspath(executable)
300
+ return f"Python {version} ({executable})"
301
+
302
+
285
303
  def main(argv: Optional[list[str]] = None) -> int:
286
304
  if argv is None:
287
305
  _install_trimmed_excepthook()
@@ -299,6 +317,7 @@ def main(argv: Optional[list[str]] = None) -> int:
299
317
  return 0
300
318
  if namespace.version:
301
319
  print(_format_version(_get_version(), __build_info__))
320
+ print(_format_python_runtime())
302
321
  return 0
303
322
 
304
323
  # Validate --awk and --map are mutually exclusive
@@ -348,6 +367,24 @@ def main(argv: Optional[list[str]] = None) -> int:
348
367
  print(snail_ast)
349
368
  return 0
350
369
 
370
+ if namespace.debug_python_ast:
371
+ import ast
372
+
373
+ python_ast = compile_ast(
374
+ source,
375
+ mode=mode,
376
+ auto_print=not namespace.no_print,
377
+ filename=filename,
378
+ begin_code=namespace.begin_code,
379
+ end_code=namespace.end_code,
380
+ )
381
+ try:
382
+ output = ast.dump(python_ast, indent=2)
383
+ except TypeError:
384
+ output = ast.dump(python_ast)
385
+ print(output)
386
+ return 0
387
+
351
388
  if namespace.debug:
352
389
  import ast
353
390
  import builtins
@@ -48,6 +48,7 @@ _incr_attr = None
48
48
  _incr_index = None
49
49
  _aug_attr = None
50
50
  _aug_index = None
51
+ _env_map = None
51
52
 
52
53
 
53
54
  def _get_compact_try():
@@ -131,6 +132,15 @@ def _get_lazy_file_class():
131
132
  return _lazy_file_class
132
133
 
133
134
 
135
+ def _get_env_map():
136
+ global _env_map
137
+ if _env_map is None:
138
+ from .env import EnvMap
139
+
140
+ _env_map = EnvMap()
141
+ return _env_map
142
+
143
+
134
144
  def _get_incr_attr():
135
145
  global _incr_attr
136
146
  if _incr_attr is None:
@@ -245,6 +255,7 @@ def install_helpers(globals_dict: dict) -> None:
245
255
  globals_dict["__snail_incr_index"] = _lazy_incr_index
246
256
  globals_dict["__snail_aug_attr"] = _lazy_aug_attr
247
257
  globals_dict["__snail_aug_index"] = _lazy_aug_index
258
+ globals_dict["__snail_env"] = _get_env_map()
248
259
  globals_dict["js"] = _lazy_js
249
260
  globals_dict["__SnailLazyText"] = _get_lazy_text_class()
250
261
  globals_dict["__SnailLazyFile"] = _get_lazy_file_class()
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+
5
+
6
+ class EnvMap:
7
+ __slots__ = ("_env",)
8
+
9
+ def __init__(self, env=None) -> None:
10
+ self._env = os.environ if env is None else env
11
+
12
+ def __fallback__(self) -> str:
13
+ return ""
14
+
15
+ def _lookup(self, key):
16
+ try:
17
+ return self._env[key]
18
+ except KeyError as exc:
19
+ exc.__fallback__ = self.__fallback__
20
+ raise
21
+
22
+ def __getitem__(self, key):
23
+ return self._lookup(key)
24
+
25
+ def __getattr__(self, name):
26
+ return self._lookup(name)
File without changes
File without changes