pystacker 1.9.2__tar.gz → 1.13.0__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.
- {pystacker-1.9.2/pystacker.egg-info → pystacker-1.13.0}/PKG-INFO +88 -19
- {pystacker-1.9.2 → pystacker-1.13.0}/README.md +87 -18
- {pystacker-1.9.2 → pystacker-1.13.0}/pyproject.toml +1 -1
- {pystacker-1.9.2 → pystacker-1.13.0/pystacker.egg-info}/PKG-INFO +88 -19
- {pystacker-1.9.2 → pystacker-1.13.0}/pystacker.egg-info/SOURCES.txt +23 -1
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/__main__.py +34 -5
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/constant.py +1 -1
- pystacker-1.13.0/stacker/engine/core.py +1158 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/engine/data_type.py +13 -11
- pystacker-1.13.0/stacker/engine/recursion.py +74 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/engine/scope.py +43 -39
- pystacker-1.13.0/stacker/engine/sfunction.py +65 -0
- pystacker-1.13.0/stacker/engine/slambda.py +76 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/engine/smacro.py +3 -3
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/error.py +63 -12
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/error_formatter.py +0 -1
- pystacker-1.13.0/stacker/include/include.py +92 -0
- pystacker-1.13.0/stacker/include/stk_file_read.py +22 -0
- pystacker-1.13.0/stacker/lib/config.py +32 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/defun.py +2 -2
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/eval.py +0 -1
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/file.py +11 -7
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/if_else.py +33 -9
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/include.py +11 -2
- pystacker-1.13.0/stacker/operators/list.py +70 -0
- pystacker-1.13.0/stacker/operators/loop.py +142 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/manager.py +77 -32
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/math.py +33 -33
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/os.py +1 -1
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/stack.py +18 -12
- pystacker-1.13.0/stacker/operators/types.py +83 -0
- pystacker-1.13.0/stacker/reserved.py +1 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/runtime/exec_modes/commandline_mode.py +1 -1
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/runtime/exec_modes/error.py +2 -2
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/runtime/exec_modes/execution_mode.py +45 -56
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/runtime/exec_modes/repl_mode.py +61 -67
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/runtime/exec_modes/script_mode.py +7 -3
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/stacker.py +38 -45
- pystacker-1.13.0/stacker/syntax/lexer.py +466 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/syntax/parser.py +35 -34
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/syntax/test_parser.py +3 -1
- pystacker-1.13.0/stacker/syntax/token_rules.py +66 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/util/disp.py +34 -33
- pystacker-1.13.0/test/test_apply.py +51 -0
- pystacker-1.13.0/test/test_block_comments.py +77 -0
- pystacker-1.13.0/test/test_cond.py +45 -0
- pystacker-1.13.0/test/test_debug_flag.py +49 -0
- pystacker-1.13.0/test/test_defmacro_advanced.py +52 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_defun.py +7 -2
- pystacker-1.13.0/test/test_defun_advanced.py +65 -0
- pystacker-1.13.0/test/test_disp.py +33 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_error_messages.py +15 -0
- pystacker-1.13.0/test/test_expand.py +25 -0
- pystacker-1.13.0/test/test_hof_advanced.py +98 -0
- pystacker-1.13.0/test/test_include.py +184 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_inline_comments.py +49 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_lambda.py +16 -0
- pystacker-1.13.0/test/test_lazy_block_binding.py +100 -0
- pystacker-1.13.0/test/test_list_primitives.py +139 -0
- pystacker-1.13.0/test/test_loop_advanced.py +67 -0
- pystacker-1.13.0/test/test_multiline_accumulation.py +64 -0
- pystacker-1.13.0/test/test_recursion_limit.py +125 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_reduce.py +33 -0
- pystacker-1.13.0/test/test_repl_continuation.py +66 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_scope.py +14 -0
- pystacker-1.13.0/test/test_semantics_freeze.py +180 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_stacker.py +62 -0
- pystacker-1.13.0/test/test_token_list_cache.py +56 -0
- pystacker-1.13.0/test/test_triple_quote_strings.py +95 -0
- pystacker-1.13.0/test/test_unterminated_errors.py +124 -0
- pystacker-1.13.0/test/test_while_loop.py +47 -0
- pystacker-1.9.2/stacker/engine/core.py +0 -875
- pystacker-1.9.2/stacker/engine/sfunction.py +0 -43
- pystacker-1.9.2/stacker/engine/slambda.py +0 -44
- pystacker-1.9.2/stacker/include/include.py +0 -32
- pystacker-1.9.2/stacker/include/stk_file_read.py +0 -46
- pystacker-1.9.2/stacker/lib/config.py +0 -12
- pystacker-1.9.2/stacker/operators/list.py +0 -53
- pystacker-1.9.2/stacker/operators/loop.py +0 -93
- pystacker-1.9.2/stacker/operators/types.py +0 -41
- pystacker-1.9.2/stacker/reserved.py +0 -2
- pystacker-1.9.2/stacker/syntax/lexer.py +0 -210
- pystacker-1.9.2/test/test_include.py +0 -52
- {pystacker-1.9.2 → pystacker-1.13.0}/LICENSE +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/pystacker.egg-info/dependency_links.txt +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/pystacker.egg-info/entry_points.txt +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/pystacker.egg-info/requires.txt +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/pystacker.egg-info/top_level.txt +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/setup.cfg +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/data/about.txt +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/data/help.txt +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/data/top.txt +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/engine/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/include/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/lib/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/lib/ui_tools.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/manager/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/aggregate.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/algebra.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/arith.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/base.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/bitwise.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/comparison.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/defmacro.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/exit.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/hof.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/io.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/lmd.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/logic.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/random.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/setting.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/string.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/system.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/time.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/operators/transform.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/plugins/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/plugins/matrix.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/plugins/whos.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/runtime/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/runtime/exec_modes/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/slib/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/syntax/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/util/__init__.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/stacker/util/color.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_aggregate.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_defmacro.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_error_formatter.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_if_else_statement.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_loop_statement.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_no_dollar_in_blocks.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_no_dollar_syntax.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_string_apostrophe.py +0 -0
- {pystacker-1.9.2 → pystacker-1.13.0}/test/test_transform.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pystacker
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.13.0
|
|
4
4
|
Summary: Stacker: RPN Calculator in Python
|
|
5
5
|
Author: remokasu
|
|
6
6
|
License: MIT License
|
|
@@ -276,6 +276,26 @@ Stacker allows for straightforward RPN input. For example:
|
|
|
276
276
|
|
|
277
277
|
Result: Pushes `7` onto the stack as `x` equals `0`.
|
|
278
278
|
|
|
279
|
+
- ##### cond Statement
|
|
280
|
+
|
|
281
|
+
The `cond` statement evaluates condition-result pairs in order and executes the first matching branch.
|
|
282
|
+
|
|
283
|
+
Syntax:
|
|
284
|
+
```bash
|
|
285
|
+
{condition1} {result1} {condition2} {result2} ... n cond
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`n` is the number of condition-result pairs.
|
|
289
|
+
|
|
290
|
+
Example:
|
|
291
|
+
```bash
|
|
292
|
+
stacker:0> 5 $x set
|
|
293
|
+
stacker:1> {x 0 >} {"positive"} {x 0 <} {"negative"} {true} {"zero"} 3 cond
|
|
294
|
+
["positive"]
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Result: Pushes `"positive"` onto the stack as `x` is greater than `0`. Use `{true}` as the last condition to provide a default branch.
|
|
298
|
+
|
|
279
299
|
- #### Loops
|
|
280
300
|
|
|
281
301
|
Loops in Stacker allow for repeated execution of code blocks.
|
|
@@ -347,23 +367,43 @@ Stacker allows for straightforward RPN input. For example:
|
|
|
347
367
|
|
|
348
368
|
Result: Pushes numbers 1 through 11 onto the stack by repeatedly duplicating and incrementing.
|
|
349
369
|
|
|
370
|
+
- ##### while Loop
|
|
371
|
+
|
|
372
|
+
The `while` loop repeats a code block while a condition is true.
|
|
373
|
+
|
|
374
|
+
Syntax:
|
|
375
|
+
```bash
|
|
376
|
+
{condition} {body} while
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Example:
|
|
380
|
+
```bash
|
|
381
|
+
stacker:0> 1 $i set 0 $s set
|
|
382
|
+
stacker:2> {i 6 <=} {s i + $s set i ++ $i set} while
|
|
383
|
+
stacker:2> s
|
|
384
|
+
[21]
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Result: Sums numbers from 1 to 6.
|
|
388
|
+
|
|
389
|
+
Note: Use `{condition}` as a code block that leaves a boolean on the stack. The loop terminates when the condition evaluates to false.
|
|
390
|
+
|
|
350
391
|
- #### break
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
This example prints the numbers from 0 to 5. When `i` is equal to `5`, the loop is terminated by `break`.
|
|
392
|
+
|
|
393
|
+
`break` immediately exits the innermost loop (`do`, `dolist`, `times`, `while`).
|
|
394
|
+
|
|
395
|
+
Syntax:
|
|
396
|
+
```bash
|
|
397
|
+
{break}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Example:
|
|
401
|
+
```bash
|
|
402
|
+
stacker:0> 0 $s set 1 10 $i {i 5 == {break} if s i + $s set} do s
|
|
403
|
+
[10]
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Result: Sums 1 through 4, then exits when `i` reaches 5. Note that `break` inside `if` immediately stops execution of the current block — `s i + $s set` is not executed when `i` equals 5.
|
|
367
407
|
|
|
368
408
|
- ### Define a function:
|
|
369
409
|
- syntax:
|
|
@@ -722,11 +762,14 @@ print(stacker.eval("3 4 +"))
|
|
|
722
762
|
### Control Operators
|
|
723
763
|
| Operator | Description | Example |
|
|
724
764
|
|----------|-------------------------------------------------------|----------------------------|
|
|
725
|
-
| if | Conditional statement | `{...}
|
|
726
|
-
| ifelse | Conditional statement with an else block | `{true block} {false block}
|
|
765
|
+
| if | Conditional statement | `true {...} if` |
|
|
766
|
+
| ifelse | Conditional statement with an else block | `true {true block} {false block} ifelse` |
|
|
727
767
|
| iferror | Conditional statement for error handling | `{try block} {catch block} iferror` |
|
|
768
|
+
| cond | Multi-branch conditional (first matching pair wins) | `{x 0 >} {"pos"} {true} {"other"} 2 cond` |
|
|
728
769
|
| do | Loop | `0 10 i {i echo} do` |
|
|
770
|
+
| dolist | Loop over the elements of a list | `[1 2 3] x {x echo} dolist` |
|
|
729
771
|
| times | Loop a specified number of times | `{dup ++} 10 times` |
|
|
772
|
+
| while | Loop while a condition is true | `{i 10 <} {i ++ $i set} while` |
|
|
730
773
|
| break | Break out of a loop | `break` |
|
|
731
774
|
|
|
732
775
|
|
|
@@ -749,6 +792,32 @@ print(stacker.eval("3 4 +"))
|
|
|
749
792
|
| filter | Filter an array based on a condition | `[1 2 3 4 5] {2 % 0 ==} filter` |
|
|
750
793
|
| all | Check if all elements of an array satisfy a condition | `[1 2 3 4 5] {2 % 0 ==} all` |
|
|
751
794
|
| any | Check if any element of an array satisfies a condition | `[1 2 3 4 5] {2 % 0 ==} any` |
|
|
795
|
+
| car | Return the first element of a list | `[1 2 3] car` |
|
|
796
|
+
| cdr | Return the list without its first element | `[1 2 3] cdr` |
|
|
797
|
+
| cons | Prepend an element to a list | `1 [2 3] cons` |
|
|
798
|
+
| pair? | Return true if the value is a non-empty list | `[1 2 3] pair?` |
|
|
799
|
+
| apply | Expand list elements onto the stack and apply a function | `[3 4] {+} apply` |
|
|
800
|
+
|
|
801
|
+
Note: Blocks passed to `map`, `filter`, `reduce`, and `fold` must leave a value on the stack. For side-effect-only iteration (e.g. printing each element), use `dolist` instead.
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
### Type Operators
|
|
805
|
+
| Operator | Description | Example |
|
|
806
|
+
|----------|-------------------------------------------------------|----------------------------|
|
|
807
|
+
| int | Convert to int | `3.7 int` |
|
|
808
|
+
| float | Convert to float | `3 float` |
|
|
809
|
+
| str | Convert to string | `42 str` |
|
|
810
|
+
| bool | Convert to bool | `1 bool` |
|
|
811
|
+
| complex | Convert to complex number | `3 complex` |
|
|
812
|
+
| type | Get the type of a value | `42 type` |
|
|
813
|
+
| int? | Returns true if the value is an int (not bool) | `42 int?` |
|
|
814
|
+
| float? | Returns true if the value is a float | `3.14 float?` |
|
|
815
|
+
| str? | Returns true if the value is a string | `"hello" str?` |
|
|
816
|
+
| bool? | Returns true if the value is a bool | `true bool?` |
|
|
817
|
+
| complex? | Returns true if the value is a complex number | `1+2j complex?` |
|
|
818
|
+
| list? | Returns true if the value is a list | `[1 2 3] list?` |
|
|
819
|
+
| null? | Returns true if the value is null or an empty list | `null null?` |
|
|
820
|
+
| number? | Returns true if the value is a number (int, float, or complex) | `42 number?` |
|
|
752
821
|
|
|
753
822
|
|
|
754
823
|
### Other Operators
|
|
@@ -241,6 +241,26 @@ Stacker allows for straightforward RPN input. For example:
|
|
|
241
241
|
|
|
242
242
|
Result: Pushes `7` onto the stack as `x` equals `0`.
|
|
243
243
|
|
|
244
|
+
- ##### cond Statement
|
|
245
|
+
|
|
246
|
+
The `cond` statement evaluates condition-result pairs in order and executes the first matching branch.
|
|
247
|
+
|
|
248
|
+
Syntax:
|
|
249
|
+
```bash
|
|
250
|
+
{condition1} {result1} {condition2} {result2} ... n cond
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`n` is the number of condition-result pairs.
|
|
254
|
+
|
|
255
|
+
Example:
|
|
256
|
+
```bash
|
|
257
|
+
stacker:0> 5 $x set
|
|
258
|
+
stacker:1> {x 0 >} {"positive"} {x 0 <} {"negative"} {true} {"zero"} 3 cond
|
|
259
|
+
["positive"]
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Result: Pushes `"positive"` onto the stack as `x` is greater than `0`. Use `{true}` as the last condition to provide a default branch.
|
|
263
|
+
|
|
244
264
|
- #### Loops
|
|
245
265
|
|
|
246
266
|
Loops in Stacker allow for repeated execution of code blocks.
|
|
@@ -312,23 +332,43 @@ Stacker allows for straightforward RPN input. For example:
|
|
|
312
332
|
|
|
313
333
|
Result: Pushes numbers 1 through 11 onto the stack by repeatedly duplicating and incrementing.
|
|
314
334
|
|
|
335
|
+
- ##### while Loop
|
|
336
|
+
|
|
337
|
+
The `while` loop repeats a code block while a condition is true.
|
|
338
|
+
|
|
339
|
+
Syntax:
|
|
340
|
+
```bash
|
|
341
|
+
{condition} {body} while
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Example:
|
|
345
|
+
```bash
|
|
346
|
+
stacker:0> 1 $i set 0 $s set
|
|
347
|
+
stacker:2> {i 6 <=} {s i + $s set i ++ $i set} while
|
|
348
|
+
stacker:2> s
|
|
349
|
+
[21]
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Result: Sums numbers from 1 to 6.
|
|
353
|
+
|
|
354
|
+
Note: Use `{condition}` as a code block that leaves a boolean on the stack. The loop terminates when the condition evaluates to false.
|
|
355
|
+
|
|
315
356
|
- #### break
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
This example prints the numbers from 0 to 5. When `i` is equal to `5`, the loop is terminated by `break`.
|
|
357
|
+
|
|
358
|
+
`break` immediately exits the innermost loop (`do`, `dolist`, `times`, `while`).
|
|
359
|
+
|
|
360
|
+
Syntax:
|
|
361
|
+
```bash
|
|
362
|
+
{break}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Example:
|
|
366
|
+
```bash
|
|
367
|
+
stacker:0> 0 $s set 1 10 $i {i 5 == {break} if s i + $s set} do s
|
|
368
|
+
[10]
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Result: Sums 1 through 4, then exits when `i` reaches 5. Note that `break` inside `if` immediately stops execution of the current block — `s i + $s set` is not executed when `i` equals 5.
|
|
332
372
|
|
|
333
373
|
- ### Define a function:
|
|
334
374
|
- syntax:
|
|
@@ -687,11 +727,14 @@ print(stacker.eval("3 4 +"))
|
|
|
687
727
|
### Control Operators
|
|
688
728
|
| Operator | Description | Example |
|
|
689
729
|
|----------|-------------------------------------------------------|----------------------------|
|
|
690
|
-
| if | Conditional statement | `{...}
|
|
691
|
-
| ifelse | Conditional statement with an else block | `{true block} {false block}
|
|
730
|
+
| if | Conditional statement | `true {...} if` |
|
|
731
|
+
| ifelse | Conditional statement with an else block | `true {true block} {false block} ifelse` |
|
|
692
732
|
| iferror | Conditional statement for error handling | `{try block} {catch block} iferror` |
|
|
733
|
+
| cond | Multi-branch conditional (first matching pair wins) | `{x 0 >} {"pos"} {true} {"other"} 2 cond` |
|
|
693
734
|
| do | Loop | `0 10 i {i echo} do` |
|
|
735
|
+
| dolist | Loop over the elements of a list | `[1 2 3] x {x echo} dolist` |
|
|
694
736
|
| times | Loop a specified number of times | `{dup ++} 10 times` |
|
|
737
|
+
| while | Loop while a condition is true | `{i 10 <} {i ++ $i set} while` |
|
|
695
738
|
| break | Break out of a loop | `break` |
|
|
696
739
|
|
|
697
740
|
|
|
@@ -714,6 +757,32 @@ print(stacker.eval("3 4 +"))
|
|
|
714
757
|
| filter | Filter an array based on a condition | `[1 2 3 4 5] {2 % 0 ==} filter` |
|
|
715
758
|
| all | Check if all elements of an array satisfy a condition | `[1 2 3 4 5] {2 % 0 ==} all` |
|
|
716
759
|
| any | Check if any element of an array satisfies a condition | `[1 2 3 4 5] {2 % 0 ==} any` |
|
|
760
|
+
| car | Return the first element of a list | `[1 2 3] car` |
|
|
761
|
+
| cdr | Return the list without its first element | `[1 2 3] cdr` |
|
|
762
|
+
| cons | Prepend an element to a list | `1 [2 3] cons` |
|
|
763
|
+
| pair? | Return true if the value is a non-empty list | `[1 2 3] pair?` |
|
|
764
|
+
| apply | Expand list elements onto the stack and apply a function | `[3 4] {+} apply` |
|
|
765
|
+
|
|
766
|
+
Note: Blocks passed to `map`, `filter`, `reduce`, and `fold` must leave a value on the stack. For side-effect-only iteration (e.g. printing each element), use `dolist` instead.
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
### Type Operators
|
|
770
|
+
| Operator | Description | Example |
|
|
771
|
+
|----------|-------------------------------------------------------|----------------------------|
|
|
772
|
+
| int | Convert to int | `3.7 int` |
|
|
773
|
+
| float | Convert to float | `3 float` |
|
|
774
|
+
| str | Convert to string | `42 str` |
|
|
775
|
+
| bool | Convert to bool | `1 bool` |
|
|
776
|
+
| complex | Convert to complex number | `3 complex` |
|
|
777
|
+
| type | Get the type of a value | `42 type` |
|
|
778
|
+
| int? | Returns true if the value is an int (not bool) | `42 int?` |
|
|
779
|
+
| float? | Returns true if the value is a float | `3.14 float?` |
|
|
780
|
+
| str? | Returns true if the value is a string | `"hello" str?` |
|
|
781
|
+
| bool? | Returns true if the value is a bool | `true bool?` |
|
|
782
|
+
| complex? | Returns true if the value is a complex number | `1+2j complex?` |
|
|
783
|
+
| list? | Returns true if the value is a list | `[1 2 3] list?` |
|
|
784
|
+
| null? | Returns true if the value is null or an empty list | `null null?` |
|
|
785
|
+
| number? | Returns true if the value is a number (int, float, or complex) | `42 number?` |
|
|
717
786
|
|
|
718
787
|
|
|
719
788
|
### Other Operators
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pystacker
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.13.0
|
|
4
4
|
Summary: Stacker: RPN Calculator in Python
|
|
5
5
|
Author: remokasu
|
|
6
6
|
License: MIT License
|
|
@@ -276,6 +276,26 @@ Stacker allows for straightforward RPN input. For example:
|
|
|
276
276
|
|
|
277
277
|
Result: Pushes `7` onto the stack as `x` equals `0`.
|
|
278
278
|
|
|
279
|
+
- ##### cond Statement
|
|
280
|
+
|
|
281
|
+
The `cond` statement evaluates condition-result pairs in order and executes the first matching branch.
|
|
282
|
+
|
|
283
|
+
Syntax:
|
|
284
|
+
```bash
|
|
285
|
+
{condition1} {result1} {condition2} {result2} ... n cond
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`n` is the number of condition-result pairs.
|
|
289
|
+
|
|
290
|
+
Example:
|
|
291
|
+
```bash
|
|
292
|
+
stacker:0> 5 $x set
|
|
293
|
+
stacker:1> {x 0 >} {"positive"} {x 0 <} {"negative"} {true} {"zero"} 3 cond
|
|
294
|
+
["positive"]
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Result: Pushes `"positive"` onto the stack as `x` is greater than `0`. Use `{true}` as the last condition to provide a default branch.
|
|
298
|
+
|
|
279
299
|
- #### Loops
|
|
280
300
|
|
|
281
301
|
Loops in Stacker allow for repeated execution of code blocks.
|
|
@@ -347,23 +367,43 @@ Stacker allows for straightforward RPN input. For example:
|
|
|
347
367
|
|
|
348
368
|
Result: Pushes numbers 1 through 11 onto the stack by repeatedly duplicating and incrementing.
|
|
349
369
|
|
|
370
|
+
- ##### while Loop
|
|
371
|
+
|
|
372
|
+
The `while` loop repeats a code block while a condition is true.
|
|
373
|
+
|
|
374
|
+
Syntax:
|
|
375
|
+
```bash
|
|
376
|
+
{condition} {body} while
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Example:
|
|
380
|
+
```bash
|
|
381
|
+
stacker:0> 1 $i set 0 $s set
|
|
382
|
+
stacker:2> {i 6 <=} {s i + $s set i ++ $i set} while
|
|
383
|
+
stacker:2> s
|
|
384
|
+
[21]
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Result: Sums numbers from 1 to 6.
|
|
388
|
+
|
|
389
|
+
Note: Use `{condition}` as a code block that leaves a boolean on the stack. The loop terminates when the condition evaluates to false.
|
|
390
|
+
|
|
350
391
|
- #### break
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
This example prints the numbers from 0 to 5. When `i` is equal to `5`, the loop is terminated by `break`.
|
|
392
|
+
|
|
393
|
+
`break` immediately exits the innermost loop (`do`, `dolist`, `times`, `while`).
|
|
394
|
+
|
|
395
|
+
Syntax:
|
|
396
|
+
```bash
|
|
397
|
+
{break}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Example:
|
|
401
|
+
```bash
|
|
402
|
+
stacker:0> 0 $s set 1 10 $i {i 5 == {break} if s i + $s set} do s
|
|
403
|
+
[10]
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Result: Sums 1 through 4, then exits when `i` reaches 5. Note that `break` inside `if` immediately stops execution of the current block — `s i + $s set` is not executed when `i` equals 5.
|
|
367
407
|
|
|
368
408
|
- ### Define a function:
|
|
369
409
|
- syntax:
|
|
@@ -722,11 +762,14 @@ print(stacker.eval("3 4 +"))
|
|
|
722
762
|
### Control Operators
|
|
723
763
|
| Operator | Description | Example |
|
|
724
764
|
|----------|-------------------------------------------------------|----------------------------|
|
|
725
|
-
| if | Conditional statement | `{...}
|
|
726
|
-
| ifelse | Conditional statement with an else block | `{true block} {false block}
|
|
765
|
+
| if | Conditional statement | `true {...} if` |
|
|
766
|
+
| ifelse | Conditional statement with an else block | `true {true block} {false block} ifelse` |
|
|
727
767
|
| iferror | Conditional statement for error handling | `{try block} {catch block} iferror` |
|
|
768
|
+
| cond | Multi-branch conditional (first matching pair wins) | `{x 0 >} {"pos"} {true} {"other"} 2 cond` |
|
|
728
769
|
| do | Loop | `0 10 i {i echo} do` |
|
|
770
|
+
| dolist | Loop over the elements of a list | `[1 2 3] x {x echo} dolist` |
|
|
729
771
|
| times | Loop a specified number of times | `{dup ++} 10 times` |
|
|
772
|
+
| while | Loop while a condition is true | `{i 10 <} {i ++ $i set} while` |
|
|
730
773
|
| break | Break out of a loop | `break` |
|
|
731
774
|
|
|
732
775
|
|
|
@@ -749,6 +792,32 @@ print(stacker.eval("3 4 +"))
|
|
|
749
792
|
| filter | Filter an array based on a condition | `[1 2 3 4 5] {2 % 0 ==} filter` |
|
|
750
793
|
| all | Check if all elements of an array satisfy a condition | `[1 2 3 4 5] {2 % 0 ==} all` |
|
|
751
794
|
| any | Check if any element of an array satisfies a condition | `[1 2 3 4 5] {2 % 0 ==} any` |
|
|
795
|
+
| car | Return the first element of a list | `[1 2 3] car` |
|
|
796
|
+
| cdr | Return the list without its first element | `[1 2 3] cdr` |
|
|
797
|
+
| cons | Prepend an element to a list | `1 [2 3] cons` |
|
|
798
|
+
| pair? | Return true if the value is a non-empty list | `[1 2 3] pair?` |
|
|
799
|
+
| apply | Expand list elements onto the stack and apply a function | `[3 4] {+} apply` |
|
|
800
|
+
|
|
801
|
+
Note: Blocks passed to `map`, `filter`, `reduce`, and `fold` must leave a value on the stack. For side-effect-only iteration (e.g. printing each element), use `dolist` instead.
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
### Type Operators
|
|
805
|
+
| Operator | Description | Example |
|
|
806
|
+
|----------|-------------------------------------------------------|----------------------------|
|
|
807
|
+
| int | Convert to int | `3.7 int` |
|
|
808
|
+
| float | Convert to float | `3 float` |
|
|
809
|
+
| str | Convert to string | `42 str` |
|
|
810
|
+
| bool | Convert to bool | `1 bool` |
|
|
811
|
+
| complex | Convert to complex number | `3 complex` |
|
|
812
|
+
| type | Get the type of a value | `42 type` |
|
|
813
|
+
| int? | Returns true if the value is an int (not bool) | `42 int?` |
|
|
814
|
+
| float? | Returns true if the value is a float | `3.14 float?` |
|
|
815
|
+
| str? | Returns true if the value is a string | `"hello" str?` |
|
|
816
|
+
| bool? | Returns true if the value is a bool | `true bool?` |
|
|
817
|
+
| complex? | Returns true if the value is a complex number | `1+2j complex?` |
|
|
818
|
+
| list? | Returns true if the value is a list | `[1 2 3] list?` |
|
|
819
|
+
| null? | Returns true if the value is null or an empty list | `null null?` |
|
|
820
|
+
| number? | Returns true if the value is a number (int, float, or complex) | `42 number?` |
|
|
752
821
|
|
|
753
822
|
|
|
754
823
|
### Other Operators
|
|
@@ -20,6 +20,7 @@ stacker/data/top.txt
|
|
|
20
20
|
stacker/engine/__init__.py
|
|
21
21
|
stacker/engine/core.py
|
|
22
22
|
stacker/engine/data_type.py
|
|
23
|
+
stacker/engine/recursion.py
|
|
23
24
|
stacker/engine/scope.py
|
|
24
25
|
stacker/engine/sfunction.py
|
|
25
26
|
stacker/engine/slambda.py
|
|
@@ -77,23 +78,44 @@ stacker/syntax/__init__.py
|
|
|
77
78
|
stacker/syntax/lexer.py
|
|
78
79
|
stacker/syntax/parser.py
|
|
79
80
|
stacker/syntax/test_parser.py
|
|
81
|
+
stacker/syntax/token_rules.py
|
|
80
82
|
stacker/util/__init__.py
|
|
81
83
|
stacker/util/color.py
|
|
82
84
|
stacker/util/disp.py
|
|
83
85
|
test/test_aggregate.py
|
|
86
|
+
test/test_apply.py
|
|
87
|
+
test/test_block_comments.py
|
|
88
|
+
test/test_cond.py
|
|
89
|
+
test/test_debug_flag.py
|
|
84
90
|
test/test_defmacro.py
|
|
91
|
+
test/test_defmacro_advanced.py
|
|
85
92
|
test/test_defun.py
|
|
93
|
+
test/test_defun_advanced.py
|
|
94
|
+
test/test_disp.py
|
|
86
95
|
test/test_error_formatter.py
|
|
87
96
|
test/test_error_messages.py
|
|
97
|
+
test/test_expand.py
|
|
98
|
+
test/test_hof_advanced.py
|
|
88
99
|
test/test_if_else_statement.py
|
|
89
100
|
test/test_include.py
|
|
90
101
|
test/test_inline_comments.py
|
|
91
102
|
test/test_lambda.py
|
|
103
|
+
test/test_lazy_block_binding.py
|
|
104
|
+
test/test_list_primitives.py
|
|
105
|
+
test/test_loop_advanced.py
|
|
92
106
|
test/test_loop_statement.py
|
|
107
|
+
test/test_multiline_accumulation.py
|
|
93
108
|
test/test_no_dollar_in_blocks.py
|
|
94
109
|
test/test_no_dollar_syntax.py
|
|
110
|
+
test/test_recursion_limit.py
|
|
95
111
|
test/test_reduce.py
|
|
112
|
+
test/test_repl_continuation.py
|
|
96
113
|
test/test_scope.py
|
|
114
|
+
test/test_semantics_freeze.py
|
|
97
115
|
test/test_stacker.py
|
|
98
116
|
test/test_string_apostrophe.py
|
|
99
|
-
test/
|
|
117
|
+
test/test_token_list_cache.py
|
|
118
|
+
test/test_transform.py
|
|
119
|
+
test/test_triple_quote_strings.py
|
|
120
|
+
test/test_unterminated_errors.py
|
|
121
|
+
test/test_while_loop.py
|
|
@@ -10,8 +10,16 @@ import stacker
|
|
|
10
10
|
|
|
11
11
|
from stacker.runtime.exec_modes import CommandLineMode, ReplMode, ScriptMode
|
|
12
12
|
|
|
13
|
+
from stacker.engine import recursion
|
|
13
14
|
from stacker.lib import disp_logo
|
|
14
|
-
from stacker.lib.config import
|
|
15
|
+
from stacker.lib.config import (
|
|
16
|
+
DEFAULT_RECURSION_LIMIT,
|
|
17
|
+
MAX_RECURSION_LIMIT,
|
|
18
|
+
RECURSION_BACKSTOP_MARGIN,
|
|
19
|
+
RECURSION_FRAMES_PER_LEVEL,
|
|
20
|
+
plugins_dir_path,
|
|
21
|
+
stacker_dotfile_path,
|
|
22
|
+
)
|
|
15
23
|
from stacker.stacker import Stacker
|
|
16
24
|
from stacker.util import colored
|
|
17
25
|
|
|
@@ -21,13 +29,34 @@ parser.add_argument(
|
|
|
21
29
|
)
|
|
22
30
|
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
|
23
31
|
parser.add_argument("-e", default=None, help="Execute the given command.")
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--recursion-limit",
|
|
34
|
+
metavar="N",
|
|
35
|
+
type=int,
|
|
36
|
+
default=DEFAULT_RECURSION_LIMIT,
|
|
37
|
+
help=(
|
|
38
|
+
"Maximum Stacker function recursion depth "
|
|
39
|
+
f"(1-{MAX_RECURSION_LIMIT}, default {DEFAULT_RECURSION_LIMIT})."
|
|
40
|
+
),
|
|
41
|
+
)
|
|
24
42
|
parser.add_argument("script", nargs="?", default=None, help="Script file to run.")
|
|
25
43
|
argv = parser.parse_args()
|
|
26
44
|
|
|
27
|
-
|
|
45
|
+
if not 1 <= argv.recursion_limit <= MAX_RECURSION_LIMIT:
|
|
46
|
+
parser.error(
|
|
47
|
+
f"--recursion-limit must be between 1 and {MAX_RECURSION_LIMIT}, "
|
|
48
|
+
f"got {argv.recursion_limit}"
|
|
49
|
+
)
|
|
50
|
+
recursion.set_limit(argv.recursion_limit)
|
|
51
|
+
|
|
52
|
+
# Finite backstop replacing the old `1 << 30`: pathological recursion that
|
|
53
|
+
# bypasses the function-call guard stops with RecursionError, not a segfault
|
|
54
|
+
sys.setrecursionlimit(
|
|
55
|
+
MAX_RECURSION_LIMIT * RECURSION_FRAMES_PER_LEVEL + RECURSION_BACKSTOP_MARGIN
|
|
56
|
+
)
|
|
28
57
|
|
|
29
58
|
|
|
30
|
-
def load_stacker_lib(stacker: Stacker, dir_path) -> bool:
|
|
59
|
+
def load_stacker_lib(stacker: Stacker, dir_path: str) -> bool:
|
|
31
60
|
"""Load the Stacker library from the specified directory.
|
|
32
61
|
:param stacker: The Stacker instance to pass to the plugins.
|
|
33
62
|
:param dir_path: The directory to load the Stacker library from.
|
|
@@ -48,7 +77,7 @@ def load_stacker_lib(stacker: Stacker, dir_path) -> bool:
|
|
|
48
77
|
return True
|
|
49
78
|
|
|
50
79
|
|
|
51
|
-
def load_plugins(stacker: Stacker, plugins_dir_path) -> bool:
|
|
80
|
+
def load_plugins(stacker: Stacker, plugins_dir_path: str) -> bool:
|
|
52
81
|
"""Load plugins from the plugins directory.
|
|
53
82
|
:param stacker: The Stacker instance to pass to the plugins.
|
|
54
83
|
:return: None
|
|
@@ -111,7 +140,7 @@ def copy_plugin_to_install_dir(plugin_path: str, debug_mode: bool) -> None:
|
|
|
111
140
|
traceback.print_exc()
|
|
112
141
|
|
|
113
142
|
|
|
114
|
-
def main():
|
|
143
|
+
def main() -> None:
|
|
115
144
|
"""Main entry point for the Stacker CLI."""
|
|
116
145
|
# add plugin
|
|
117
146
|
if argv.addplugin:
|