shellsim 0.1.7__tar.gz → 0.1.9__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.
- {shellsim-0.1.7 → shellsim-0.1.9}/Cargo.lock +1 -1
- {shellsim-0.1.7 → shellsim-0.1.9}/Cargo.toml +1 -1
- {shellsim-0.1.7 → shellsim-0.1.9}/PKG-INFO +5 -3
- {shellsim-0.1.7 → shellsim-0.1.9}/README.md +4 -2
- {shellsim-0.1.7 → shellsim-0.1.9}/python/native/Cargo.lock +2 -2
- {shellsim-0.1.7 → shellsim-0.1.9}/python/native/Cargo.toml +1 -1
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/builtins.rs +120 -1
- {shellsim-0.1.7 → shellsim-0.1.9}/src/interp.rs +21 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/ast.rs +2 -3
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/compiler.rs +88 -9
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/mod.rs +443 -28
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/native.rs +7 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/object_model.rs +4 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/parser.rs +7 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/bisect.rs +109 -11
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/core.rs +344 -2
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/frozen.rs +4 -0
- shellsim-0.1.9/src/python/stdlib/itertools.rs +344 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/math.rs +169 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/mod.rs +1 -1
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/pytest.rs +4 -4
- shellsim-0.1.9/src/python/stdlib/source/copy.py +29 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/pathlib.py +30 -0
- shellsim-0.1.9/src/python/stdlib/source/pytest.py +36 -0
- shellsim-0.1.9/src/python/stdlib/source/shutil.py +57 -0
- shellsim-0.1.9/src/python/stdlib/source/textwrap.py +73 -0
- shellsim-0.1.9/src/python/stdlib/typing.rs +136 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/calls.rs +73 -1
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/iteration.rs +12 -3
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/namespace.rs +6 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/native_runtime.rs +62 -1
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm.rs +6 -0
- shellsim-0.1.7/src/python/stdlib/itertools.rs +0 -118
- shellsim-0.1.7/src/python/stdlib/typing.rs +0 -45
- {shellsim-0.1.7 → shellsim-0.1.9}/LICENSE +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/pyproject.toml +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/python/native/src/lib.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/python/shellsim/__init__.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/python/shellsim/__main__.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/python/shellsim/_api.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/python/shellsim/_cli.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/python/shellsim/py.typed +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/python/shellsim/python.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/rust-toolchain.toml +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/bin/shellsim-python.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/clock.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/archives.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/awk/ast.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/awk/eval.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/awk/lexer.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/awk/parser.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/awk.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/dd.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/echo.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/find.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/fs.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/apply.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/commit.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/compare.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/config.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/conflict.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/diff.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/ignore.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/import.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/log.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/merge.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/mod.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/plumbing.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/rebase.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/refs.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/repo.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/stash.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/switch.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/git/worktree.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/hashing.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/makecmd.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/mod.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/net.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/options.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/patch.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/pkg.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/printf.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/proc.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/regex_compat.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/rgcmd.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/sed.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/sort.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/system.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/tarcmd.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/text.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/unavailable.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/util.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/commands/zipcmd.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/descriptors.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/exec.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/expand.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/harness.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/harness_manager.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/hashes.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/host_ingest.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/jqcmd.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/lib.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/main.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/mcp.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/net.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/netcmd.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/process.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/pseudo_fs.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/bytecode.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/filesystem.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/heap.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/http.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/lexer.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/mapping.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/number.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/process.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/protocol.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/slice.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/source.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/argparse.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/base64.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/collections.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/dataclasses.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/enum.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/functools.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/hashlib.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/heapq.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/http.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/importlib.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/json.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/numpy.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/os.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/re.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/abc.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/base64.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/cmath.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/codecs.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/collections.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/complex.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/csv.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/datetime.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/glob.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/hashlib.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/http.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/http_client.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/importlib.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/io.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/json.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/logging.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/numpy_random.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/os.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/random.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/statistics.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/struct.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/subprocess.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/tempfile.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/urllib.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/urllib_error.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/urllib_request.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/uuid.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/zipfile.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/source/zlib.py +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/string.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/struct.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/subprocess.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/sys.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/time.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/unittest.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/vfs.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/stdlib/zlib.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/string.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/token.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/dispatch.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/host.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/objects.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/python/vm/operations.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/resources.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/sandbox.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/scenario.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/scheduler.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/shell.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/telemetry.rs +0 -0
- {shellsim-0.1.7 → shellsim-0.1.9}/src/vfs.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shellsim
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
6
6
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
@@ -160,8 +160,10 @@ printf '%s\n' \
|
|
|
160
160
|
|
|
161
161
|
CPU is deterministic fuel, memory is modeled working set, disk is current virtual-filesystem
|
|
162
162
|
usage, and output bounds materialized stdout and stderr. The defaults are 10,000,000 CPU units,
|
|
163
|
-
64 MiB memory, 64 MiB disk, and 4 MiB output. Costs
|
|
164
|
-
|
|
163
|
+
64 MiB memory, 64 MiB disk, and 4 MiB output. Costs use simple, stable approximations intended to
|
|
164
|
+
be correct within an order of magnitude. They bound runaway work and make runs comparable; they
|
|
165
|
+
do not model allocator layouts or instruction timing exactly. Exhaustion is observable and never
|
|
166
|
+
falls back to an ambient host implementation.
|
|
165
167
|
|
|
166
168
|
For internals and contribution workflow, see [implementation](docs/implementation.md),
|
|
167
169
|
[Python](docs/python.md), and [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -137,8 +137,10 @@ printf '%s\n' \
|
|
|
137
137
|
|
|
138
138
|
CPU is deterministic fuel, memory is modeled working set, disk is current virtual-filesystem
|
|
139
139
|
usage, and output bounds materialized stdout and stderr. The defaults are 10,000,000 CPU units,
|
|
140
|
-
64 MiB memory, 64 MiB disk, and 4 MiB output. Costs
|
|
141
|
-
|
|
140
|
+
64 MiB memory, 64 MiB disk, and 4 MiB output. Costs use simple, stable approximations intended to
|
|
141
|
+
be correct within an order of magnitude. They bound runaway work and make runs comparable; they
|
|
142
|
+
do not model allocator layouts or instruction timing exactly. Exhaustion is observable and never
|
|
143
|
+
falls back to an ambient host implementation.
|
|
142
144
|
|
|
143
145
|
For internals and contribution workflow, see [implementation](docs/implementation.md),
|
|
144
146
|
[Python](docs/python.md), and [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -406,7 +406,7 @@ dependencies = [
|
|
|
406
406
|
|
|
407
407
|
[[package]]
|
|
408
408
|
name = "shellsim"
|
|
409
|
-
version = "0.1.
|
|
409
|
+
version = "0.1.9"
|
|
410
410
|
dependencies = [
|
|
411
411
|
"base64",
|
|
412
412
|
"crc32fast",
|
|
@@ -427,7 +427,7 @@ dependencies = [
|
|
|
427
427
|
|
|
428
428
|
[[package]]
|
|
429
429
|
name = "shellsim-python-bindings"
|
|
430
|
-
version = "0.1.
|
|
430
|
+
version = "0.1.9"
|
|
431
431
|
dependencies = [
|
|
432
432
|
"pyo3",
|
|
433
433
|
"serde",
|
|
@@ -50,7 +50,7 @@ pub fn register(m: &mut HashMap<&'static str, CommandSpec>) {
|
|
|
50
50
|
reg_resumable(m, &["command"], Trust::Real, cmd_command, start_command);
|
|
51
51
|
reg(m, &["alias"], Trust::Partial, cmd_alias);
|
|
52
52
|
reg(m, &["unalias"], Trust::Real, cmd_unalias);
|
|
53
|
-
|
|
53
|
+
reg(m, &["getopts"], Trust::Real, cmd_getopts);
|
|
54
54
|
reg(m, &["let"], Trust::Real, cmd_let);
|
|
55
55
|
reg(m, &["mapfile", "readarray"], Trust::Real, cmd_mapfile);
|
|
56
56
|
reg(m, &["pushd"], Trust::Real, cmd_pushd);
|
|
@@ -1259,6 +1259,125 @@ fn cmd_shift(interp: &mut CommandContext<'_>, args: &[String], _io: &mut Io) ->
|
|
|
1259
1259
|
0
|
|
1260
1260
|
}
|
|
1261
1261
|
|
|
1262
|
+
fn cmd_getopts(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
1263
|
+
if args.len() < 2 {
|
|
1264
|
+
ewln(io.err, "getopts: usage: getopts optstring name [arg ...]");
|
|
1265
|
+
return 2;
|
|
1266
|
+
}
|
|
1267
|
+
let optstring = &args[0];
|
|
1268
|
+
let name = &args[1];
|
|
1269
|
+
let operands = if args.len() > 2 {
|
|
1270
|
+
args[2..].to_vec()
|
|
1271
|
+
} else {
|
|
1272
|
+
interp.positional.clone()
|
|
1273
|
+
};
|
|
1274
|
+
let visible_optind = interp
|
|
1275
|
+
.get_var("OPTIND")
|
|
1276
|
+
.and_then(|value| value.parse::<usize>().ok())
|
|
1277
|
+
.filter(|value| *value > 0)
|
|
1278
|
+
.unwrap_or(1);
|
|
1279
|
+
if visible_optind != interp.getopts.optind {
|
|
1280
|
+
interp.getopts.optind = visible_optind;
|
|
1281
|
+
interp.getopts.offset = 1;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
let argument_index = interp.getopts.optind - 1;
|
|
1285
|
+
let Some(argument) = operands.get(argument_index) else {
|
|
1286
|
+
set_getopts_optind(interp);
|
|
1287
|
+
return 1;
|
|
1288
|
+
};
|
|
1289
|
+
if argument == "--" {
|
|
1290
|
+
interp.getopts.optind += 1;
|
|
1291
|
+
interp.getopts.offset = 1;
|
|
1292
|
+
set_getopts_optind(interp);
|
|
1293
|
+
return 1;
|
|
1294
|
+
}
|
|
1295
|
+
let option_characters = argument.chars().collect::<Vec<_>>();
|
|
1296
|
+
if !argument.starts_with('-')
|
|
1297
|
+
|| argument == "-"
|
|
1298
|
+
|| interp.getopts.offset >= option_characters.len()
|
|
1299
|
+
{
|
|
1300
|
+
set_getopts_optind(interp);
|
|
1301
|
+
return 1;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
let option = option_characters[interp.getopts.offset];
|
|
1305
|
+
let silent = optstring.starts_with(':');
|
|
1306
|
+
let specification = optstring
|
|
1307
|
+
.trim_start_matches(':')
|
|
1308
|
+
.chars()
|
|
1309
|
+
.collect::<Vec<_>>();
|
|
1310
|
+
let Some(specification_index) = specification
|
|
1311
|
+
.iter()
|
|
1312
|
+
.position(|candidate| *candidate == option)
|
|
1313
|
+
else {
|
|
1314
|
+
advance_getopts(interp, option_characters.len());
|
|
1315
|
+
if silent {
|
|
1316
|
+
interp.set_var("OPTARG", option.to_string());
|
|
1317
|
+
} else {
|
|
1318
|
+
interp.vars.remove("OPTARG");
|
|
1319
|
+
}
|
|
1320
|
+
interp.set_var(name, "?");
|
|
1321
|
+
set_getopts_optind(interp);
|
|
1322
|
+
if !silent {
|
|
1323
|
+
ewln(io.err, &format!("getopts: illegal option -- {option}"));
|
|
1324
|
+
}
|
|
1325
|
+
return 0;
|
|
1326
|
+
};
|
|
1327
|
+
let requires_argument = specification.get(specification_index + 1) == Some(&':');
|
|
1328
|
+
if !requires_argument {
|
|
1329
|
+
advance_getopts(interp, option_characters.len());
|
|
1330
|
+
interp.vars.remove("OPTARG");
|
|
1331
|
+
interp.set_var(name, option.to_string());
|
|
1332
|
+
set_getopts_optind(interp);
|
|
1333
|
+
return 0;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
let inline = option_characters[interp.getopts.offset + 1..]
|
|
1337
|
+
.iter()
|
|
1338
|
+
.collect::<String>();
|
|
1339
|
+
let option_argument = if !inline.is_empty() {
|
|
1340
|
+
interp.getopts.optind += 1;
|
|
1341
|
+
inline
|
|
1342
|
+
} else if let Some(value) = operands.get(argument_index + 1) {
|
|
1343
|
+
interp.getopts.optind += 2;
|
|
1344
|
+
value.clone()
|
|
1345
|
+
} else {
|
|
1346
|
+
interp.getopts.optind += 1;
|
|
1347
|
+
interp.getopts.offset = 1;
|
|
1348
|
+
set_getopts_optind(interp);
|
|
1349
|
+
interp.set_var(name, if silent { ":" } else { "?" });
|
|
1350
|
+
if silent {
|
|
1351
|
+
interp.set_var("OPTARG", option.to_string());
|
|
1352
|
+
} else {
|
|
1353
|
+
interp.vars.remove("OPTARG");
|
|
1354
|
+
ewln(
|
|
1355
|
+
io.err,
|
|
1356
|
+
&format!("getopts: option requires an argument -- {option}"),
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
return 0;
|
|
1360
|
+
};
|
|
1361
|
+
interp.getopts.offset = 1;
|
|
1362
|
+
interp.set_var("OPTARG", option_argument);
|
|
1363
|
+
interp.set_var(name, option.to_string());
|
|
1364
|
+
set_getopts_optind(interp);
|
|
1365
|
+
0
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
fn advance_getopts(interp: &mut CommandContext<'_>, argument_length: usize) {
|
|
1369
|
+
interp.getopts.offset += 1;
|
|
1370
|
+
if interp.getopts.offset >= argument_length {
|
|
1371
|
+
interp.getopts.optind += 1;
|
|
1372
|
+
interp.getopts.offset = 1;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
fn set_getopts_optind(interp: &mut CommandContext<'_>) {
|
|
1377
|
+
let value = interp.getopts.optind.to_string();
|
|
1378
|
+
interp.vars.insert("OPTIND".to_string(), value);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1262
1381
|
fn cmd_test(interp: &mut CommandContext<'_>, args: &[String], io: &mut Io) -> i32 {
|
|
1263
1382
|
eval_test_cmd(interp, "test", args, io)
|
|
1264
1383
|
}
|
|
@@ -24,6 +24,13 @@ pub enum ArrayVal {
|
|
|
24
24
|
Assoc(BTreeMap<String, String>),
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/// Cursor retained between calls to the `getopts` shell builtin.
|
|
28
|
+
#[derive(Clone, Debug)]
|
|
29
|
+
pub(crate) struct GetoptsState {
|
|
30
|
+
pub(crate) optind: usize,
|
|
31
|
+
pub(crate) offset: usize,
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
/// A simulated background job started with `&`.
|
|
28
35
|
///
|
|
29
36
|
/// Its process continuation is owned separately by [`ProcessStates`]. This shell-facing record
|
|
@@ -144,6 +151,7 @@ pub struct ProcessState {
|
|
|
144
151
|
random_state: Cell<u32>,
|
|
145
152
|
/// positional parameters `$1 $2 ... $@`
|
|
146
153
|
pub positional: Vec<String>,
|
|
154
|
+
pub(crate) getopts: GetoptsState,
|
|
147
155
|
/// `set -e` / `set -u` / `set -x`
|
|
148
156
|
pub opt_errexit: bool,
|
|
149
157
|
pub opt_nounset: bool,
|
|
@@ -316,6 +324,7 @@ impl ProcessState {
|
|
|
316
324
|
last_status: self.last_status,
|
|
317
325
|
random_state: Cell::new(self.random_state.get()),
|
|
318
326
|
positional: self.positional.clone(),
|
|
327
|
+
getopts: self.getopts.clone(),
|
|
319
328
|
opt_errexit: self.opt_errexit,
|
|
320
329
|
opt_nounset: self.opt_nounset,
|
|
321
330
|
opt_xtrace: self.opt_xtrace,
|
|
@@ -550,6 +559,10 @@ impl Environment {
|
|
|
550
559
|
last_status: 0,
|
|
551
560
|
random_state: Cell::new(1),
|
|
552
561
|
positional: Vec::new(),
|
|
562
|
+
getopts: GetoptsState {
|
|
563
|
+
optind: 1,
|
|
564
|
+
offset: 1,
|
|
565
|
+
},
|
|
553
566
|
opt_errexit: false,
|
|
554
567
|
opt_nounset: false,
|
|
555
568
|
opt_xtrace: false,
|
|
@@ -1457,6 +1470,14 @@ impl Environment {
|
|
|
1457
1470
|
if name == "PWD" {
|
|
1458
1471
|
self.cwd = val.clone();
|
|
1459
1472
|
}
|
|
1473
|
+
if name == "OPTIND" {
|
|
1474
|
+
self.getopts.optind = val
|
|
1475
|
+
.parse::<usize>()
|
|
1476
|
+
.ok()
|
|
1477
|
+
.filter(|value| *value > 0)
|
|
1478
|
+
.unwrap_or(1);
|
|
1479
|
+
self.getopts.offset = 1;
|
|
1480
|
+
}
|
|
1460
1481
|
// A plain scalar assignment to an array name in bash sets element 0; we instead treat it
|
|
1461
1482
|
// as a fresh scalar (drop the array) — the common case in our scripts and lower-risk.
|
|
1462
1483
|
self.arrays.remove(name);
|
|
@@ -173,14 +173,13 @@ pub enum ExpressionKind {
|
|
|
173
173
|
value: Box<Expression>,
|
|
174
174
|
clauses: Vec<ComprehensionClause>,
|
|
175
175
|
},
|
|
176
|
-
///
|
|
177
|
-
/// generator expressions an ordinary iterable and isolated comprehension
|
|
178
|
-
/// scope while keeping the bounded-resource contract simple and explicit.
|
|
176
|
+
/// A lazy comprehension evaluated in its own generator frame.
|
|
179
177
|
GeneratorExpression {
|
|
180
178
|
element: Box<Expression>,
|
|
181
179
|
clauses: Vec<ComprehensionClause>,
|
|
182
180
|
},
|
|
183
181
|
Yield(Option<Box<Expression>>),
|
|
182
|
+
YieldFrom(Box<Expression>),
|
|
184
183
|
Attribute {
|
|
185
184
|
value: Box<Expression>,
|
|
186
185
|
name: String,
|
|
@@ -936,10 +936,7 @@ impl Compiler {
|
|
|
936
936
|
self.emit_dict_comprehension(*key, *value, clauses, span);
|
|
937
937
|
}
|
|
938
938
|
ExpressionKind::GeneratorExpression { element, clauses } => {
|
|
939
|
-
|
|
940
|
-
// It is still a separate function scope (like CPython's generator frame), and
|
|
941
|
-
// all iteration remains metered by the ordinary bytecode loop.
|
|
942
|
-
self.emit_comprehension(ComprehensionKind::List, *element, clauses, span);
|
|
939
|
+
self.emit_generator_expression(*element, clauses, span);
|
|
943
940
|
}
|
|
944
941
|
ExpressionKind::Yield(value) => {
|
|
945
942
|
if !self.in_function {
|
|
@@ -947,11 +944,6 @@ impl Compiler {
|
|
|
947
944
|
Operation::RuntimeError("'yield' outside function".into()),
|
|
948
945
|
span,
|
|
949
946
|
);
|
|
950
|
-
} else if let Some(region) = self.protected_regions.last() {
|
|
951
|
-
self.emit(
|
|
952
|
-
Operation::RuntimeError(format!("yield is not supported inside a {region} cleanup region; suspending here would lose exception or context-manager state")),
|
|
953
|
-
span,
|
|
954
|
-
);
|
|
955
947
|
} else {
|
|
956
948
|
if let Some(value) = value {
|
|
957
949
|
self.expression(*value);
|
|
@@ -961,6 +953,24 @@ impl Compiler {
|
|
|
961
953
|
self.emit(Operation::Yield, span);
|
|
962
954
|
}
|
|
963
955
|
}
|
|
956
|
+
ExpressionKind::YieldFrom(value) => {
|
|
957
|
+
if !self.in_function {
|
|
958
|
+
self.emit(
|
|
959
|
+
Operation::RuntimeError("'yield from' outside function".into()),
|
|
960
|
+
span,
|
|
961
|
+
);
|
|
962
|
+
} else {
|
|
963
|
+
self.expression(*value);
|
|
964
|
+
self.emit(Operation::GetIterator, span);
|
|
965
|
+
let next = self.emit(Operation::ForIterator(usize::MAX), span);
|
|
966
|
+
self.emit(Operation::Yield, span);
|
|
967
|
+
self.emit(Operation::PopTop, span);
|
|
968
|
+
self.emit(Operation::Jump(next), span);
|
|
969
|
+
let exhausted = self.instructions.len();
|
|
970
|
+
self.patch_jump(next, exhausted);
|
|
971
|
+
self.emit(Operation::LoadConstant(Constant::None), span);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
964
974
|
ExpressionKind::Attribute { value, name } => {
|
|
965
975
|
self.expression(*value);
|
|
966
976
|
self.emit(Operation::LoadAttribute(name), span);
|
|
@@ -1216,6 +1226,46 @@ impl Compiler {
|
|
|
1216
1226
|
);
|
|
1217
1227
|
}
|
|
1218
1228
|
|
|
1229
|
+
fn emit_generator_expression(
|
|
1230
|
+
&mut self,
|
|
1231
|
+
element: Expression,
|
|
1232
|
+
clauses: Vec<ComprehensionClause>,
|
|
1233
|
+
span: Span,
|
|
1234
|
+
) {
|
|
1235
|
+
let named_expression = self.comprehension_named_expression_context();
|
|
1236
|
+
let mut nested = Compiler {
|
|
1237
|
+
instructions: Vec::new(),
|
|
1238
|
+
loops: Vec::new(),
|
|
1239
|
+
finalizers: Vec::new(),
|
|
1240
|
+
protected_regions: Vec::new(),
|
|
1241
|
+
in_function: true,
|
|
1242
|
+
globals: HashSet::new(),
|
|
1243
|
+
nonlocals: HashSet::new(),
|
|
1244
|
+
named_expression,
|
|
1245
|
+
is_class_scope: false,
|
|
1246
|
+
structural_depth: self.structural_depth,
|
|
1247
|
+
};
|
|
1248
|
+
nested.emit_generator_comprehension_body(&clauses, 0, &element, span);
|
|
1249
|
+
nested.emit(Operation::LoadConstant(Constant::None), span);
|
|
1250
|
+
nested.emit(Operation::Return, span);
|
|
1251
|
+
self.emit(
|
|
1252
|
+
Operation::MakeFunction {
|
|
1253
|
+
name: "<genexpr>".into(),
|
|
1254
|
+
code: nested.finish(Vec::new()),
|
|
1255
|
+
defaults: 0,
|
|
1256
|
+
},
|
|
1257
|
+
span,
|
|
1258
|
+
);
|
|
1259
|
+
self.emit(
|
|
1260
|
+
Operation::Call {
|
|
1261
|
+
positional: 0,
|
|
1262
|
+
keywords: Vec::new(),
|
|
1263
|
+
starred: Vec::new(),
|
|
1264
|
+
},
|
|
1265
|
+
span,
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1219
1269
|
fn emit_dict_comprehension(
|
|
1220
1270
|
&mut self,
|
|
1221
1271
|
key: Expression,
|
|
@@ -1307,6 +1357,35 @@ impl Compiler {
|
|
|
1307
1357
|
self.patch_jump(next, exhausted);
|
|
1308
1358
|
}
|
|
1309
1359
|
|
|
1360
|
+
fn emit_generator_comprehension_body(
|
|
1361
|
+
&mut self,
|
|
1362
|
+
clauses: &[ComprehensionClause],
|
|
1363
|
+
index: usize,
|
|
1364
|
+
element: &Expression,
|
|
1365
|
+
span: Span,
|
|
1366
|
+
) {
|
|
1367
|
+
let clause = &clauses[index];
|
|
1368
|
+
self.expression(clause.iterable.clone());
|
|
1369
|
+
self.emit(Operation::GetIterator, span);
|
|
1370
|
+
let next = self.emit(Operation::ForIterator(usize::MAX), span);
|
|
1371
|
+
self.store_target(clause.target.clone(), span);
|
|
1372
|
+
for condition in &clause.conditions {
|
|
1373
|
+
self.expression(condition.clone());
|
|
1374
|
+
let skip = self.emit(Operation::PopJumpIfFalse(usize::MAX), span);
|
|
1375
|
+
self.patch_jump(skip, next);
|
|
1376
|
+
}
|
|
1377
|
+
if index + 1 < clauses.len() {
|
|
1378
|
+
self.emit_generator_comprehension_body(clauses, index + 1, element, span);
|
|
1379
|
+
} else {
|
|
1380
|
+
self.expression(element.clone());
|
|
1381
|
+
self.emit(Operation::Yield, span);
|
|
1382
|
+
self.emit(Operation::PopTop, span);
|
|
1383
|
+
}
|
|
1384
|
+
self.emit(Operation::Jump(next), span);
|
|
1385
|
+
let exhausted = self.instructions.len();
|
|
1386
|
+
self.patch_jump(next, exhausted);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1310
1389
|
fn emit_dict_comprehension_body(
|
|
1311
1390
|
&mut self,
|
|
1312
1391
|
clauses: &[ComprehensionClause],
|