shellsim 0.1.5__tar.gz → 0.1.8__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.5 → shellsim-0.1.8}/Cargo.lock +1 -1
- {shellsim-0.1.5 → shellsim-0.1.8}/Cargo.toml +1 -1
- {shellsim-0.1.5 → shellsim-0.1.8}/PKG-INFO +5 -3
- {shellsim-0.1.5 → shellsim-0.1.8}/README.md +4 -2
- {shellsim-0.1.5 → shellsim-0.1.8}/python/native/Cargo.lock +2 -2
- {shellsim-0.1.5 → shellsim-0.1.8}/python/native/Cargo.toml +1 -1
- {shellsim-0.1.5 → shellsim-0.1.8}/python/shellsim/_cli.py +4 -1
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/builtins.rs +120 -1
- {shellsim-0.1.5 → shellsim-0.1.8}/src/interp.rs +21 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/heap.rs +41 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/object_model.rs +1 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/bisect.rs +109 -11
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/core.rs +589 -1
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/frozen.rs +5 -0
- shellsim-0.1.8/src/python/stdlib/itertools.rs +344 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/math.rs +319 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/mod.rs +1 -0
- shellsim-0.1.8/src/python/stdlib/source/cmath.py +65 -0
- shellsim-0.1.8/src/python/stdlib/source/complex.py +112 -0
- shellsim-0.1.8/src/python/stdlib/source/copy.py +29 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/pathlib.py +30 -0
- shellsim-0.1.8/src/python/stdlib/source/shutil.py +57 -0
- shellsim-0.1.8/src/python/stdlib/source/textwrap.py +73 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/calls.rs +165 -4
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/namespace.rs +18 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm.rs +8 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/vfs.rs +163 -41
- shellsim-0.1.5/src/python/stdlib/itertools.rs +0 -118
- {shellsim-0.1.5 → shellsim-0.1.8}/LICENSE +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/pyproject.toml +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/python/native/src/lib.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/python/shellsim/__init__.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/python/shellsim/__main__.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/python/shellsim/_api.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/python/shellsim/py.typed +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/python/shellsim/python.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/rust-toolchain.toml +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/bin/shellsim-python.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/clock.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/archives.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/awk/ast.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/awk/eval.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/awk/lexer.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/awk/parser.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/awk.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/dd.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/echo.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/find.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/fs.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/apply.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/commit.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/compare.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/config.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/conflict.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/diff.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/ignore.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/import.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/log.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/merge.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/mod.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/plumbing.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/rebase.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/refs.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/repo.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/stash.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/switch.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/git/worktree.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/hashing.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/makecmd.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/mod.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/net.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/options.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/patch.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/pkg.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/printf.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/proc.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/regex_compat.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/rgcmd.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/sed.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/sort.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/system.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/tarcmd.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/text.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/unavailable.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/util.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/commands/zipcmd.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/descriptors.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/exec.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/expand.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/harness.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/harness_manager.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/hashes.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/host_ingest.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/jqcmd.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/lib.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/main.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/mcp.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/net.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/netcmd.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/process.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/pseudo_fs.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/ast.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/bytecode.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/compiler.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/filesystem.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/http.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/lexer.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/mapping.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/mod.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/native.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/number.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/parser.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/process.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/protocol.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/slice.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/source.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/argparse.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/base64.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/collections.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/dataclasses.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/enum.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/functools.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/hashlib.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/heapq.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/http.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/importlib.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/json.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/numpy.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/os.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/pytest.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/re.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/abc.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/base64.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/codecs.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/collections.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/csv.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/datetime.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/glob.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/hashlib.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/http.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/http_client.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/importlib.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/io.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/json.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/logging.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/numpy_random.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/os.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/random.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/statistics.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/struct.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/subprocess.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/tempfile.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/urllib.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/urllib_error.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/urllib_request.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/uuid.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/zipfile.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/source/zlib.py +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/string.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/struct.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/subprocess.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/sys.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/time.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/typing.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/unittest.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/vfs.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/stdlib/zlib.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/string.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/token.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/dispatch.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/host.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/iteration.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/native_runtime.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/objects.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/python/vm/operations.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/resources.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/sandbox.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/scenario.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/scheduler.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/shell.rs +0 -0
- {shellsim-0.1.5 → shellsim-0.1.8}/src/telemetry.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.8
|
|
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.8"
|
|
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.8"
|
|
431
431
|
dependencies = [
|
|
432
432
|
"pyo3",
|
|
433
433
|
"serde",
|
|
@@ -148,7 +148,10 @@ def _interactive(environment: Environment, stdin: Any, stdout: Any, stderr: Any)
|
|
|
148
148
|
def main(arguments: Optional[Sequence[str]] = None) -> int:
|
|
149
149
|
"""Run the package CLI and return the simulated or usage exit status."""
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
parsed_arguments = list(sys.argv[1:] if arguments is None else arguments)
|
|
152
|
+
if parsed_arguments[-1:] == ["--"]:
|
|
153
|
+
parsed_arguments.pop()
|
|
154
|
+
options = _parser().parse_args(parsed_arguments)
|
|
152
155
|
environment, preparation_status = _prepare_environment(options, sys.stdout, sys.stderr)
|
|
153
156
|
if environment is None:
|
|
154
157
|
return preparation_status
|
|
@@ -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);
|
|
@@ -48,6 +48,10 @@ impl SymbolId {
|
|
|
48
48
|
pub(super) const fn index(self) -> usize {
|
|
49
49
|
self.0 as usize
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
pub(super) fn from_index(index: usize) -> Option<Self> {
|
|
53
|
+
u32::try_from(index).ok().map(Self)
|
|
54
|
+
}
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
/// Runtime-local identity for one append-only instance storage layout.
|
|
@@ -386,6 +390,43 @@ impl Heap {
|
|
|
386
390
|
self.symbol_ids.get(name).copied()
|
|
387
391
|
}
|
|
388
392
|
|
|
393
|
+
/// Resolve a symbol identity back to its interpreter-owned name.
|
|
394
|
+
pub fn symbol_name(&self, symbol: SymbolId) -> Option<&str> {
|
|
395
|
+
self.symbol_names.get(symbol.index()).map(AsRef::as_ref)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/// Snapshot the names stored directly on an instance in either attribute representation.
|
|
399
|
+
pub fn instance_attribute_names(&self, id: ObjectId) -> Result<Vec<String>, String> {
|
|
400
|
+
let object = self
|
|
401
|
+
.objects
|
|
402
|
+
.get(id.0)
|
|
403
|
+
.and_then(Option::as_ref)
|
|
404
|
+
.ok_or("invalid object reference")?;
|
|
405
|
+
let Object::Instance { attributes, .. } = &object.payload else {
|
|
406
|
+
return Err("object does not have instance attributes".into());
|
|
407
|
+
};
|
|
408
|
+
match attributes {
|
|
409
|
+
InstanceAttributes::Shaped { shape, values } => (0..values.len())
|
|
410
|
+
.map(|slot| {
|
|
411
|
+
let symbol = self
|
|
412
|
+
.shape_attribute_at(*shape, slot)
|
|
413
|
+
.ok_or("invalid instance shape slot")?;
|
|
414
|
+
self.symbol_name(symbol)
|
|
415
|
+
.map(str::to_string)
|
|
416
|
+
.ok_or_else(|| "invalid instance attribute symbol".into())
|
|
417
|
+
})
|
|
418
|
+
.collect(),
|
|
419
|
+
InstanceAttributes::Dictionary(values) => values
|
|
420
|
+
.keys()
|
|
421
|
+
.map(|symbol| {
|
|
422
|
+
self.symbol_name(*symbol)
|
|
423
|
+
.map(str::to_string)
|
|
424
|
+
.ok_or_else(|| "invalid instance attribute symbol".into())
|
|
425
|
+
})
|
|
426
|
+
.collect(),
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
389
430
|
/// Intern one identifier, charging its process-lifetime storage before mutation.
|
|
390
431
|
pub fn intern_symbol(
|
|
391
432
|
&mut self,
|
|
@@ -883,6 +883,7 @@ fn install_builtin_slots(types: &mut [PyType]) {
|
|
|
883
883
|
slots.add = Some(intrinsic(super::stdlib::core::slot_string_add));
|
|
884
884
|
slots.multiply = Some(intrinsic(super::stdlib::core::slot_string_multiply));
|
|
885
885
|
slots.reflected_multiply = Some(intrinsic(super::stdlib::core::slot_string_multiply));
|
|
886
|
+
slots.remainder = Some(intrinsic(super::stdlib::core::slot_string_remainder));
|
|
886
887
|
|
|
887
888
|
let slots = &mut types[BuiltinType::Bytes as usize].slots;
|
|
888
889
|
slots.length = Some(unary(super::stdlib::core::slot_bytes_length));
|
|
@@ -8,32 +8,67 @@ use std::cmp::Ordering;
|
|
|
8
8
|
|
|
9
9
|
use super::super::native::PyValue as Value;
|
|
10
10
|
use super::super::native::{
|
|
11
|
-
CallArgs, FunctionDef, ModuleDef, PyError, PyResult, PyRuntime, PySequence, PyValueCast,
|
|
11
|
+
CallArgs, FunctionDef, ModuleDef, PyError, PyList, PyResult, PyRuntime, PySequence, PyValueCast,
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
pub(super) static MODULE: ModuleDef = ModuleDef {
|
|
15
15
|
name: "bisect",
|
|
16
|
-
functions: &[
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
functions: &[
|
|
17
|
+
FunctionDef {
|
|
18
|
+
module: "bisect",
|
|
19
|
+
name: "bisect_left",
|
|
20
|
+
call: native_bisect_left,
|
|
21
|
+
},
|
|
22
|
+
FunctionDef {
|
|
23
|
+
module: "bisect",
|
|
24
|
+
name: "bisect_right",
|
|
25
|
+
call: native_bisect_right,
|
|
26
|
+
},
|
|
27
|
+
FunctionDef {
|
|
28
|
+
module: "bisect",
|
|
29
|
+
name: "bisect",
|
|
30
|
+
call: native_bisect_right,
|
|
31
|
+
},
|
|
32
|
+
FunctionDef {
|
|
33
|
+
module: "bisect",
|
|
34
|
+
name: "insort_left",
|
|
35
|
+
call: native_insort_left,
|
|
36
|
+
},
|
|
37
|
+
FunctionDef {
|
|
38
|
+
module: "bisect",
|
|
39
|
+
name: "insort_right",
|
|
40
|
+
call: native_insort_right,
|
|
41
|
+
},
|
|
42
|
+
FunctionDef {
|
|
43
|
+
module: "bisect",
|
|
44
|
+
name: "insort",
|
|
45
|
+
call: native_insort_right,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
21
48
|
values: &[],
|
|
22
49
|
};
|
|
23
50
|
|
|
24
51
|
fn native_bisect_left(runtime: &mut dyn PyRuntime, args: CallArgs) -> PyResult {
|
|
25
|
-
|
|
26
|
-
|
|
52
|
+
native_bisect(runtime, args, false)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fn native_bisect_right(runtime: &mut dyn PyRuntime, args: CallArgs) -> PyResult {
|
|
56
|
+
native_bisect(runtime, args, true)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fn native_bisect(runtime: &mut dyn PyRuntime, args: CallArgs, right: bool) -> PyResult {
|
|
60
|
+
args.expect_positional("bisect", 2, 4)?;
|
|
61
|
+
args.reject_keywords("bisect")?;
|
|
27
62
|
let values = args.positional()[0]
|
|
28
63
|
.cast::<PySequence>(runtime)?
|
|
29
64
|
.items(runtime)?;
|
|
30
65
|
let needle = &args.positional()[1];
|
|
31
|
-
let mut low =
|
|
32
|
-
let mut high = values.len();
|
|
66
|
+
let (mut low, mut high) = bisect_bounds(runtime, &args, values.len())?;
|
|
33
67
|
while low < high {
|
|
34
68
|
runtime.charge_cpu(1)?;
|
|
35
69
|
let middle = low + (high - low) / 2;
|
|
36
|
-
|
|
70
|
+
let ordering = runtime.compare(&values[middle], needle)?;
|
|
71
|
+
if ordering == Ordering::Less || (right && ordering == Ordering::Equal) {
|
|
37
72
|
low = middle + 1;
|
|
38
73
|
} else {
|
|
39
74
|
high = middle;
|
|
@@ -44,6 +79,69 @@ fn native_bisect_left(runtime: &mut dyn PyRuntime, args: CallArgs) -> PyResult {
|
|
|
44
79
|
.map_err(|_| PyError::overflow_error("bisect result exceeds bounded integer range"))
|
|
45
80
|
}
|
|
46
81
|
|
|
82
|
+
fn bisect_bounds(
|
|
83
|
+
runtime: &dyn PyRuntime,
|
|
84
|
+
args: &CallArgs,
|
|
85
|
+
length: usize,
|
|
86
|
+
) -> PyResult<(usize, usize)> {
|
|
87
|
+
let low = args
|
|
88
|
+
.positional()
|
|
89
|
+
.get(2)
|
|
90
|
+
.map(|value| {
|
|
91
|
+
runtime
|
|
92
|
+
.int_value(value)
|
|
93
|
+
.ok_or_else(|| PyError::type_error("lo must be an integer"))
|
|
94
|
+
.and_then(|value| {
|
|
95
|
+
usize::try_from(value)
|
|
96
|
+
.map_err(|_| PyError::value_error("lo must be non-negative"))
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
.transpose()?
|
|
100
|
+
.unwrap_or(0);
|
|
101
|
+
let high = args
|
|
102
|
+
.positional()
|
|
103
|
+
.get(3)
|
|
104
|
+
.map(|value| {
|
|
105
|
+
runtime
|
|
106
|
+
.int_value(value)
|
|
107
|
+
.ok_or_else(|| PyError::type_error("hi must be an integer"))
|
|
108
|
+
.and_then(|value| {
|
|
109
|
+
usize::try_from(value)
|
|
110
|
+
.map_err(|_| PyError::value_error("hi must be non-negative"))
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
.transpose()?
|
|
114
|
+
.unwrap_or(length);
|
|
115
|
+
if high > length {
|
|
116
|
+
return Err(PyError::value_error("hi exceeds sequence length"));
|
|
117
|
+
}
|
|
118
|
+
Ok((low, high))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
fn native_insort_left(runtime: &mut dyn PyRuntime, args: CallArgs) -> PyResult {
|
|
122
|
+
native_insort(runtime, args, false)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fn native_insort_right(runtime: &mut dyn PyRuntime, args: CallArgs) -> PyResult {
|
|
126
|
+
native_insort(runtime, args, true)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fn native_insort(runtime: &mut dyn PyRuntime, args: CallArgs, right: bool) -> PyResult {
|
|
130
|
+
let list = args
|
|
131
|
+
.positional()
|
|
132
|
+
.first()
|
|
133
|
+
.copied()
|
|
134
|
+
.ok_or_else(|| PyError::type_error("insort expected a list and a value"))?
|
|
135
|
+
.cast::<PyList>(runtime)?;
|
|
136
|
+
let index_value = native_bisect(runtime, args.clone(), right)?;
|
|
137
|
+
let index = runtime
|
|
138
|
+
.int_value(&index_value)
|
|
139
|
+
.and_then(|index| usize::try_from(index).ok())
|
|
140
|
+
.ok_or_else(|| PyError::runtime_error("bisect returned an invalid index"))?;
|
|
141
|
+
runtime.list_insert(list, index, args.positional()[1])?;
|
|
142
|
+
Ok(Value::None)
|
|
143
|
+
}
|
|
144
|
+
|
|
47
145
|
/// Errors for an explicitly bounded search.
|
|
48
146
|
#[cfg(test)]
|
|
49
147
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|