Metadata-Version: 2.4
Name: pystacker
Version: 1.25.1
Summary: Stacker: RPN Calculator in Python
Author: remokasu
License: MIT License
        
        Copyright (c) 2023 @remokasu
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/remokasu/stacker
Keywords: reverse-polish-calculator,rpn,terminal-app
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: prompt-toolkit>=3.0.0
Dynamic: license-file

# Stacker: An RPN Calculator and Extensible Programming Language

[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)

Stacker is a powerful Reverse Polish Notation (RPN) calculator built with Python, featuring basic mathematical operations and extensibility through plugins.

The user manual lives in [docs/](docs/README.md) (Japanese; it covers the syntax, every built-in word, scripts, the REPL and the plugin API).

## Table of Contents

- [Installation](#installation)
- [Dependencies](#dependencies)
- [Feedback and Contributions](#feedback-and-contributions)
- [Usage](#usage)
- [Running Scripts](#running-scripts)
- [VSCode Syntax Highlighting](#vscode-syntax-highlighting)
- [Command Line Execution](#command-line-execution)
- [Settings](#settings)
- [Configuration File](#configuration-file)
- [Creating Plugins](#creating-plugins)
- [Running on Python](#running-on-python)
- [Supported Operations](#supported-operations)
- [Constants](#constants)

## Installation

```bash
git clone git@github.com:remokasu/stacker.git
cd stacker
pip install .
```

### Optional: VSCode Syntax Highlighting

For syntax highlighting support in VSCode:

```bash
mkdir -p ~/.vscode/extensions/stacker-language-0.1.0
cp -r .vscode-extension/* ~/.vscode/extensions/stacker-language-0.1.0/
```

Reload VSCode (Ctrl+Shift+P → "Developer: Reload Window") and `.stk` files will be highlighted. 


## Dependencies

Python Prompt Toolkit is required for Stacker. Install it using the following command:
```bash
pip install prompt_toolkit
```

## Feedback and Contributions

Feedback and contributions are welcome. Please submit issues or suggestions on the [Issues page](https://github.com/remokasu/stacker/issues).


## Usage

Run Stacker:
```bash
stacker
```
Or:
```bash
python -m stacker
```

Stacker supports standard arithmetic operations (+, -, *, /) and advanced functions (sin, cos, tan, etc.). Users can input commands in RPN format and extend functionality using custom plugins.

### Input Examples

Stacker allows for straightforward RPN input. For example:

- Single-line input:
  ```bash
  stacker:0> 3 4 +
  [7]
  ```

- Multi-line input:
  ```bash
  stacker:0> 3
  [3]
  stacker:1> 4
  [3 4]
  stacker:2> +
  [7]
  ```

- ### Numbers:
  The Stacker command allows you to directly push integers, floating-point numbers, and complex numbers onto the stack. This facilitates easy management of various types of numerical data.

  - Integers:
    ```bash
    stacker:0> 3
    [3]
    ```
    In this example, the integer 3 is added to the stack.

  - Floating-Point Numbers:
    ```bash
    stacker:1> 3.14
    [3.14]
    ```
    Here, the floating-point number 3.14 is added to the stack.

  - Complex Numbers:
    ```bash
    stacker:2> 1+2j
    [(1+2j)]
    ```
    In this case, the complex number 1+2j (with a real part of 1 and an imaginary part of 2) is added to the stack. Complex numbers are denoted by combining the real and imaginary parts with a +, and the imaginary part is indicated using j.

- ### Strings:
  - syntax:
    ```bash
    "Hello, World!"
    ```
  - example:
    ```bash
    stacker:0> "Hello, World!"
    ['Hello, World!']
    ```
    In this example, the string "Hello, World!" is added to the stack. Strings are written with double quotes and shown on the stack with single quotes. A backslash starts an escape: `\n` `\t` `\r` `\0` `\\` `\"` `\'` `\xNN` `\uNNNN`.
    ```bash
    stacker:0> "say \"hi\"\tnow" echo
    say "hi"	now
    ```


- ### Variables:
  - syntax:
    ``` bash
    value :name set
    # or
    value :name =
    ```
  - example:
    ```bash
    stacker:0> 3 :x set
    stacker:1> x
    [3]

    # Using = operator (equivalent to set)
    stacker:0> 5 :y =
    stacker:1> y
    [5]
    ```
    In this example, we assign `3` to `x` using `set`, and `5` to `y` using `=`. Both operators work identically.

    **Note:** The `=` operator is an alias for `set` and can be used interchangeably. Use whichever feels more natural for your coding style.

    **Three ways to write a name.** A name can be written bare (`x`), as a symbol (`:x`) or quoted (`{x}`).
    The rule is short: a bare name is a *reference*, `:x` and `{x}` are the *name itself*, and `"x"` is a
    string, never a name.

    - A bare name is looked up: as a macro, then a variable, then a function or operator. A macro is expanded,
      a variable's value is pushed (a lambda too; call it with `eval`), a function or operator is run. A name
      that is none of these is an error right there, so a typo stops where it is written.
    - `:x` pushes the symbol `x` itself as a value, whatever a variable `x` holds. A symbol is a type of its
      own: `:x "x" ==` is false, `symbol?` tells it from a string, `str` gives its text and `symbol` makes one
      from text (`"x" symbol`). `:` must be followed by a name (`:1` and `:{x}` are errors). Symbols are how a
      name is handed to any word that takes one (`set`, `defun`, `alias`, a macro, ...), and `[:a :b]` is a
      list of names.
    - `{x}` (a block holding only the name) means "this name" everywhere a name is read, and as code it means
      the same as `:x`: `:x eval` and `{x} eval` both do what writing `x` does.
    - Tokens are read one at a time, left to right, and nothing looks ahead: a bare name is a reference
      wherever it stands, even right before `set`. So the name a word binds is always written `:name` or
      `{name}`: `3 :x set`, `0 10 :i {i echo} do`, `{a b} {a b +} :add defun`,
      `[1 2 3] 0 :acc :x {acc x +} reduce`. Written bare, `3 x set` looks `x` up and stops with "`x` is not
      defined", and `3 dup set` runs `dup` and then `set` complains that it got `3` instead of a name. The
      same spelling rebinds any name, a built-in word's included (`3 :dup set`), and redefining a prelude
      word such as `alias` logs a warning, as does a `defun` that redefines a word of your own from another
      file. A bare name that holds a name binds that name: after `:y :x set`,
      `7 x set` binds `y`. A literal is never a name (`5 3 set` and `5 true set` are errors) and neither is
      a string (`5 "x" set` is an error too).

- Lists:
  - Single-line list:
    ```bash
    stacker:0> [1 2 3; 4 5 6]
    [[[1 2 3] [4 5 6]]]
    ```

  - Multi-line list:
    ```bash
    stacker:0> [1 2 3;
    ... > 4 5 6]
    [[[1 2 3] [4 5 6]]]
    ```


- ### Code Blocks

  Code blocks are fundamental structures in Stacker that enable deferred evaluation and control flow management. They are enclosed in curly braces `{}`.

  **Syntax:**
  ```bash
  {code_elements}
  ```

  **Key Characteristics:**
  1. **Deferred Evaluation**: Code blocks are not executed immediately when encountered
  2. **Stack Interaction**: Pushed onto the stack as single units in their raw form
  3. **Delayed Execution**: Can be executed later when needed (via `eval`, `if`, `times`, etc.)

  **Common Use Cases:**
  - Conditional statements (`if`, `ifelse`)
  - Loop controls (`times`, `do`, `dolist`)
  - Function definitions (`defun`, `lambda`)
  - Lazy evaluation patterns

  **Examples:**
  ```bash
  # Create a code block
  stacker:0> {1 2 +}
  [{1 2 +}]

  # Execute with eval
  stacker:0> {1 2 +} eval
  [3]

  # Use in function definitions
  stacker:2> {x y} {x y *} :multiply defun
  ```

  **Note**: Code blocks are stored but not executed until explicitly triggered. This allows for flexible program control, lazy evaluation, and higher-order programming patterns.

  **Quoted names:** a block holding a single name, such as `{double}`, is the way to pass a *name* as a value.
  Every word that takes a name (`set`, `=`, `global`, `defun`, `defmacro`, `alias`) accepts `{name}` as well as
  `:name`. Macros that define things take their names in this form. This is also how a *variable name* is passed to
  a macro: `{n} incr!` and `:n incr!` both hand over the name `n`, whereas `n incr!` hands over the variable's
  current value.

- ### Arrays and Dictionaries:
  A list never changes. When you need to change elements in place, make an array or a dictionary.
  Words that change them end in `!`.
  ```bash
  stacker:0> [1 2 3] array :a set
  []
  stacker:1> 9 a 0 at!
  []
  stacker:2> 4 a append!
  []
  stacker:3> a
  [[9 2 3 4]]
  stacker:4> dict :d set
  [[9 2 3 4]]
  stacker:5> 1 d "x" put!
  [[9 2 3 4]]
  stacker:6> d "x" get
  [[9 2 3 4] 1]
  ```
  An array is shown like a list (the REPL gives it a color of its own; `array?` tells for sure) and a
  dictionary as `{'x' 1}`. An array or a dictionary is one thing wherever it goes: `dup`, a variable, a
  function argument or a list element refers to the same one, so a change made through one is seen through all. `a b same?` tells
  whether two are the same one; `==` compares contents. Words that only read take an array as they take
  a list, and the ones that make a new sequence (`map`, `sorted`, `cdr`, ...) make a list.

- ### Control Structures in Stacker

  Stacker provides two main types of control structures: conditionals and loops. These allow for dynamic program flow based on conditions and repetitive execution of code blocks.

  - #### Conditionals

    Conditionals in Stacker enable execution of code based on specified conditions.

  - ##### if Statement

    The `if` statement executes a code block if a condition is true.

    Syntax:
    ```bash
    condition <true-expr> if
    ```

    The condition is a value, or a block that runs on the current stack and leaves the value to test on top (so
    `7 {0 >} {...} if` tests `7 0 >`, and an empty block leaves the top as it is). A block that leaves nothing is
    an error.

    Example:
    ```bash
    stacker:0> 0 :x set
    stacker:1> x 0 == {3 4 +} if
    [7]
    ```

    Result: Pushes `7` onto the stack as `x` equals `0`.

  - ##### ifelse Statement

    The `ifelse` statement provides branching based on a condition, executing one of two code blocks.

    Syntax:
    ```bash
    condition <true-expr> <false-expr> ifelse
    ```

    Example:
    ```bash
    stacker:0> 0 :x set
    stacker:1> x 0 == {3 4 +} {3 4 -} ifelse
    [7]
    ```

    Result: Pushes `7` onto the stack as `x` equals `0`.

  - ##### cond Statement

    The `cond` statement evaluates condition-result pairs in order and executes the first matching branch.

    Syntax:
    ```bash
    {condition1} {result1} {condition2} {result2} ... n cond
    ```

    `n` is the number of condition-result pairs.

    Example:
    ```bash
    stacker:0> 5 :x set
    stacker:1> {x 0 >} {"positive"} {x 0 <} {"negative"} {true} {"zero"} 3 cond
    ['positive']
    ```

    Result: Pushes `"positive"` onto the stack as `x` is greater than `0`. Use `{true}` as the last condition to provide a default branch.

  - #### Loops

    Loops in Stacker allow for repeated execution of code blocks.

  - ##### do Loop

    The `do` loop iterates over a range of values.

    Syntax:
    ```bash
    start_value end_value :name {body} do
    ```

    Example:
    ```bash
    stacker:0> 1 10 :i {i echo} do
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ```

    Result: Prints numbers from 1 to 10.

  - ##### dolist

      The `dolist` loop iterates over a list of values.

      Syntax:
      ```bash
      [value1 value2 ... valueN] :name {body} dolist
      ```

      Example:
      ```bash
      stacker:0> [1 2 3 4 5] :i {i echo} dolist
      1
      2
      3
      4
      5
      ```

      Result: Prints numbers 1 through 5.

      Note:
        When expressing a list of consecutive values, the concise notation value1 valueN `seq` can be used instead of `[value1 value2 ... valueN]` to efficiently describe a sequence with a constant step size.

  - ##### times

    The `times` loop repeats a code block a specified number of times.

    Syntax:
    ```bash
    {body} n times
    ```

    Example:
    ```bash
    stacker:0> 1 {dup ++} 10 times
    [1 2 3 4 5 6 7 8 9 10 11]
    ```

    Result: Pushes numbers 1 through 11 onto the stack by repeatedly duplicating and incrementing.

  - ##### while Loop

    The `while` loop repeats a code block while a condition is true.

    Syntax:
    ```bash
    {condition} {body} while
    ```

    Example:
    ```bash
    stacker:0> 1 :i set 0 :s set
    stacker:2> {i 6 <=} {s i + :s set i ++ :i set} while
    stacker:2> s
    [21]
    ```

    Result: Sums numbers from 1 to 6.

    Note: Use `{condition}` as a code block that leaves a boolean on the stack. The loop terminates when the condition evaluates to false.

  - ##### loop

    `loop` repeats a code block forever until `break` is executed. It is the primitive every other loop
    can be built from; the body runs on the current stack, in the current scope.

    Syntax:
    ```bash
    {body} loop
    ```

    Example:
    ```bash
    stacker:0> 0 {1 + dup 10 > {break} if} loop
    [11]
    ```

  - #### break

    `break` immediately exits the innermost loop (`do`, `dolist`, `times`, `while`, `loop`).

    Syntax:
    ```bash
    {break}
    ```

    Example:
    ```bash
    stacker:0> 0 :s set 1 10 :i {i 5 == {break} if s i + :s set} do s
    [10]
    ```

    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.

- ### Define a function:
  - syntax:
    ```bash
    {arg1 arg2 ... argN} {body} :name defun
    ```
  - example:
    ```bash
    stacker:0> {x y} {x y *} :multiply defun
    stacker:1> 10 20 multiply
    [200]
    ```
    This defines a function named `multiply` that takes two arguments `x` and `y` and multiplies them together.
    The function pushes every value its body leaves, in order; a body that leaves nothing pushes nothing:
    ```bash
    stacker:0> {a b} {b a} :swap2 defun
    stacker:1> 1 2 swap2
    [2 1]
    ```

- ### Define an alias:
  - syntax:
    ```bash
    {body} {name} alias
    ```
  - example:
    ```bash
    stacker:0> {2 ^ 3 * 5 +} {calculatePowerAndAdd} alias
    stacker:1> 5 calculatePowerAndAdd
    [80]
    ```
    An alias names a code snippet. Calling the name runs the body right there, on the caller's stack and in
    the caller's scope, exactly as if the body had been written in place. (Before 1.15.0 this was what
    `defmacro` did.)

- ### Define a macro:
  - syntax:
    ```bash
    {args} {body} :name defmacro
    ```
  - example:
    ```bash
    stacker:0> {cond body} { {cond eval not {body eval} if} } {unless} defmacro
    stacker:1> -3 {0 >} {"not positive" echo} unless
    not positive
    ```
    A macro receives its arguments as *code* (blocks are not evaluated) and runs its body when it is called
    to build the code that will actually run. Inside a block literal of the body, an argument name is
    replaced by the argument passed in, so the body above produces
    `{{0 >} eval not {{"not positive" echo} eval} if}`, which is then evaluated on the caller's stack.
    This lets you define new control structures in Stacker itself.

    The rules:
    - The body runs on its own stack, in a scope of its own where the arguments are bound. It must leave
      exactly one value: a code block is evaluated in the caller's context, any other value is pushed as is.
    - Every name bound in that scope (the arguments, and variables assigned with `=` / `set` inside the body)
      is substituted into the body's block literals at the moment each literal is pushed: a symbol (`:name`,
      a `gensym` name) becomes a bare name in the generated code, a string becomes a string literal, a block
      stays a block and any other value is spliced as a value. A `:name` written in the body is replaced by
      the symbol of the name that `name` holds (`:t` for a `gensym` name held in `t`, `:double` for the quoted
      name `{double}`), which is how a generated temporary is bound: `{ x eval :t set t t + }`. The substituted
      values are not scanned again; string literals, list literals and unbound `:name`s are left untouched.
    - Assignments inside the body are local to the macro; they never change the caller's variables.
    - Argument names may be anything, including built-in names; every occurrence in the block literals is
      replaced, so choose them with care.
    - `gensym` returns a fresh unique name (prefixed `__g`; do not use that prefix yourself) for temporaries
      in generated code:
      ```bash
      stacker:0> {x} { gensym :t = { x eval :t set t t + } } {double!} defmacro
      stacker:1> {3 4 +} double!
      [14]
      ```
    - `{name} macroexpand` pushes the expansion without running it, which is the easiest way to debug a macro.

- ### Lambda Functions
  Lambda functions are anonymous functions that can be defined and executed on the fly. They are useful for creating temporary functions without the need for a formal definition.

  - syntax:
    ```bash
    {arg1 arg2 ... argN} {body} lambda
    ```
  - example:
    ```bash
    stacker:0> {x y} {x y *} lambda
    [λxλy.{x y *}]
    ```

  - example:
    ```bash
    stacker:0> {x y} {x y *} lambda :multiply set
    stacker:1> 3 4 multiply
    [3 4 λxλy.{x y *}]
    stacker:3> eval
    [12]
    ```
    This example defines a lambda function that multiplies two numbers and assigns it to the variable `multiply`.
    A lambda held in a variable is a value: writing `multiply` pushes it, and `eval` calls it with the arguments
    `3` and `4` (`3 4 multiply eval`). To call a function by its bare name, define it with `defun` instead.
    Like a function, a lambda pushes every value its body leaves when it is called.


- ### Include Scripts
  `"file.stk" include` runs another script right here, in the interpreter and the scope it is written in, as if
  its text stood in place: the variables, functions and macros it defines are the ones you see afterwards, and
  its functions can call yours. It runs every time it is included. What the file leaves on its stack is dropped.

  ``` bash
  stacker:0>  "my_script.stk" include
  ```

  `"file.stk" require` does the same the first time, and nothing when the same file is required again. Read a
  library that keeps state with `require`, so that reading it from a second file does not set it up again.

  Relative paths are looked up next to the including file first, then in the current directory. An error inside
  an included file is reported at its own line, followed by the lines that included it (`included from ...`).

- ### The prelude
  Some words are written in Stacker itself and loaded into every interpreter at start-up (`alias` and `mean`
  for now). They behave like any other word; `macros` and `funcs` mark them with `(prelude)`.


## Running Scripts
Stacker scripts can be created in `.stk` files. To run a script, simply execute it with Stacker. For example:

- my_script.stk:
  ```bash
  0 :p set
  0 100000 :k {
      -1 k ^ 2 k * 1 + / p + :p set
  } do
  4 p * :p set
  p echo
  ```

  Running the script:
  ```bash
  stacker my_script.stk
  ```


## VSCode Syntax Highlighting

Stacker provides syntax highlighting support for `.stk` files in Visual Studio Code, making it easier to read and write Stacker code.

### Installation

Install the syntax highlighting extension by copying it to your VSCode extensions directory:

```bash
# For VSCode Server (Remote SSH)
mkdir -p ~/.vscode-server/extensions/stacker-language-0.1.0
cp -r .vscode-extension/* ~/.vscode-server/extensions/stacker-language-0.1.0/

# For local VSCode
mkdir -p ~/.vscode/extensions/stacker-language-0.1.0
cp -r .vscode-extension/* ~/.vscode/extensions/stacker-language-0.1.0/
```

Then reload VSCode (Ctrl+Shift+P → "Developer: Reload Window").

### Features

- Comments (`#` and `#| ... |#`), strings (`"..."`, `'...'`, triple quotes), numbers (`42`, `3.14`, `1.5e3`, `0xFF`, `0b1010`, `2+3j`)
- Symbols (`:x`)
- Every word of the language, by kind: control flow (`if`, `do`, `while`, ...), definitions (`defun`, `defmacro`, `lambda`, `alias`), assignment (`set`, `=`, `global`), code words (`eval`, `parse`, `macroexpand`, ...), arithmetic, comparison, logic, bit operations, math, stack words, list words, string words, type words, I/O and files, system words, prelude words and constants
- Auto-closing brackets (`{`, `[`, `(`, `"`, `'`) and code folding

The grammar is generated from the interpreter's own word lists by `scripts/generate_vscode_grammar.py`, so it lists exactly the words the interpreter knows. The colors come from your VSCode theme.


## Command Line Execution
You can directly execute a specified RPN expression from the command line.

```bash
stacker -e "3 4 + echo"
```


## Settings
- disable_plugin
  Disable a specified plugin:
  ```bash
  stacker:0> "hoge" disable_plugin
  ```
  This command deactivates the `hoge` operator added as a plugin.
  Note that it cannot be used on non-plugin operators.

- disable_all_plugins
  Disable all plugins at once.
  ```bash
  stacker:0> disable_all_plugins
  ```

- enable_disp_ans
  Enables the display of the last result (ans) at the end of the stack.
  ```bash
  stacker:0> enable_disp_ans
  stacker:1> 3 4 +
  7
  [7]
  ```

- disable_disp_ans
  Disables the display of the last result (ans) at the end of the stack.
  ```bash
  stacker:0> disable_disp_ans
  stacker:1> 3 4 +
  [7]
  ```

- enable_disp_stack
  Enables the setting to display the stack contents each time. By default, this setting is already active.
  ```bash
  stacker:0> enable_disp_stack
  ```

- disable_disp_stack
  Sets the display of stack contents to be disabled. When this setting is enabled, only the latest element of the stack is displayed.
  ```bash
  stacker:0> disable_disp_stack
  ```

- disable_disp_logo
  Disables the display of the logo at startup.
  ```bash
  stacker:0> disable_disp_logo
  ```



## Configuration File
You can automatically load settings at startup. The configuration file should be placed in ~/.stackerrc. For example, if you write the following contents in ~/.stackerrc, the disable_disp_logo and disable_disp_stack will be automatically activated at startup.
```bash
disable_disp_logo
disable_disp_stack
enable_disp_ans
```

## Creating Plugins

Create custom plugins for Stacker using Python:

1. **Creating the Plugin**:
 In the `plugins` directory, create a new Python file for your plugin (e.g., `my_plugin.py`). 

    ``` 
    stacker/
    │
    ├── stacker/
    │   ├── plugins/
    │   │   ├── my_plugin.py
    │   │   └── ...
    │   │
    │   ├── data/
    │   ├── stacker.py
    │   └── ...
    │
    └── ...
    ```

    Adding your plugin here and reinstalling Stacker will apply the plugin permanently.

2. **Defining Functions and Classes**:
   Define the necessary functions and classes in `my_plugin.py`.

3. **Defining the `setup` Function**:
   In `my_plugin.py`, define a `setup` function that takes `stacker` as its only argument.

4. **Registering Custom Commands and Parameters**:

    Within the `setup` function, use the `register_plugin` method of `stacker` to register custom commands. Additionally, you can also register custom parameters using the `register_parameter` method. This allows for greater flexibility and customization in your plugin's behavior.

    Here's an example that registers a custom command:

    Example:
    ```python
    from stacker.stacker import Stacker

    def function(a, b):
        return a + b

    def setup(stacker: Stacker):
        stacker.register_plugin("command", function, desc="Add two numbers")
    ```

    You can specify the command description for the help command using desc. This field is optional.

    A plugin word takes precedence over a built-in word of the same name: registering `+` replaces the built-in `+`. This is how a plugin can give an operator a new meaning, for example for matrices.

    The register_parameter method is used to add a custom parameter to the Stacker environment, allowing for additional customization and control within your plugin.

5. **Reinstalling Stacker**:
   Run the following command to reinstall Stacker:
    ```
    > pip install .
    ```

    **Note**: If you want to apply the plugin only temporarily, create a `plugins` directory in the directory where Stacker is executed and add your plugin there. The method for creating it is the same as described above. This method does not require reinstalling Stacker.


6. **Using the Plugin**:
   When Stacker is launched, the plugin will automatically be loaded, and the custom commands will be available for use.

7. **Disabling Plugins**:
Use operatorName disable_plugin to disable a specific plugin.<br>
Use disable_all_plugins to disable all plugins.<br>


## Running on Python
You can also run Stacker as a Python module. For example:
```python
from stacker import Stacker
stacker = Stacker()
print(stacker.eval("3 4 +"))
```
`Stacker()` loads the prelude like the command line does. Pass `Stacker(prelude=False)` for a bare interpreter.

## Supported Operations

### Basic Operators

| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| +        | Add                                                   | `3 5 +`                    |
| -        | Subtract                                              | `10 3 -`                   |
| *        | Multiply                                              | `4 6 *`                    |
| /        | Divide                                                | `12 4 /`                   |
| //       | Integer divide                                        | `7 2 //`                   |
| %        | Modulus                                               | `9 2 %`                    |
| ^        | Power                                                 | `3 2 ^`                    |
| ==       | Equal                                                 | `1 1 ==`                   |
| !=       | Not equal                                             | `1 0 !=`                   |
| <        | Less than                                             | `1 2 <`                    |
| <=       | Less than or equal to                                 | `3 3 <=`                   |
| >        | Greater than                                          | `2 1 >`                    |
| >=       | Greater than or equal to                              | `3 3 >=`                   |
| neg      | Negate                                                | `5 neg`                    |
| and      | Logical and                                           | `true false and`           |
| or       | Logical or                                            | `true false or`            |
| not      | Logical not                                           | `true not`                 |
| band     | Bitwise and                                           | `3 2 band`                 |
| bor      | Bitwise or                                            | `3 2 bor`                  |
| bxor     | Bitwise xor                                           | `3 2 bxor`                 |
| >>       | Right bit shift                                       | `8 2 >>`                   |
| <<       | Left bit shift                                        | `2 2 <<`                   |
| bit-length | The bits needed to write an integer                   | `255 bit-length`           |
| popcount | The number of one bits in an integer                   | `255 popcount`             |
| trailing-zeros | Zero bits below the lowest one bit               | `40 trailing-zeros`        |
| ~        | Bitwise not                                           | `5 ~`                      |
| bin      | Binary representation (result is a string)            | `5 bin`                    |
| oct      | Octal representation (result is a string)             | `10 oct`                   |
| dec      | Decimal representation (result is an integer)         | `0b101010 dec`             |
| hex      | Hexadecimal representation (result is a string)       | `255 hex`                  |


### Math Operator

| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| abs      | Absolute value                                        | `-3 abs`                   |
| exp      | Exponential                                           | `3 exp`                    |
| real     | Real part (a real number is its own)                  | `3+4j real`                |
| imag     | Imaginary part (0 for a real number)                  | `3+4j imag`                |
| conj     | Complex conjugate                                     | `3+4j conj`                |
| arg      | Angle of a number, from -pi to pi                     | `1j arg`                   |
| polar    | Complex number of length r and angle t: `r t polar`   | `1 pi 2 / polar`           |
| log      | Natural logarithm                                     | `2 log`                    |
| log10    | Common logarithm (base 10)                            | `4 log10`                  |
| log2     | Logarithm base 2                                      | `4 log2`                   |
| sin      | Sine (argument in radians)                            | `pi 2 / sin`               |
| cos      | Cosine (argument in radians)                          | `pi cos`                   |
| tan      | Tangent (argument in radians)                         | `pi 4 / tan`               |
| asin     | Arcsine (result in radians)                           | `0.5 asin`                 |
| acos     | Arccosine (result in radians)                         | `0.5 acos`                 |
| atan     | Arctangent (result in radians)                        | `1 atan`                   |
| sinh     | Hyperbolic sine                                       | `1 sinh`                   |
| cosh     | Hyperbolic cosine                                     | `1 cosh`                   |
| tanh     | Hyperbolic tangent                                    | `1 tanh`                   |
| asinh    | Inverse hyperbolic sine                               | `1 asinh`                  |
| acosh    | Inverse hyperbolic cosine                             | `2 acosh`                  |
| atanh    | Inverse hyperbolic tangent                            | `0.5 atanh`                |
| sqrt     | Square root                                           | `9 sqrt`                   |
| ceil     | Ceiling                                               | `3.2 ceil`                 |
| floor    | Floor                                                 | `3.8 floor`                |
| round    | Round                                                 | `3.5 round`                |
| roundn   | Round to specified decimal places                     | `3.51 1 roundn`            |
| gcd      | Greatest common divisor                               | `4 2 gcd`                  |
| !        | Factorial                                             | `4 !`                      |
| radians  | Convert degrees to radians                            | `180 radians`              |
| rand     | Generate a random floating-point number between 0 and 1| `rand`                    |
| randint  | Generate a random integer within a specified range    | `1 6 randint`              |
| uniform  | Generate a random floating-point number within a specified range | `1 2 uniform`   |
| frac     | Fraction                                              | `3 6 frac`                 |
| dice     | Roll dice (e.g., 3d6)                                 | `3 6 dice`                 |


### Stack Operators
| Operator | Description                                               | Example                |
|----------|-----------------------------------------------------------|------------------------|
| drop     | Drops the top element of the stack.                       | `drop`                 |
| drop2    | Drops the top two elements of the stack.                  | `drop2`                |
| dropn    | Drops the top n elements of the stack.                    | `2 dropn`              |
| dup      | Duplicate the top element of the stack.                   | `dup`                  |
| dup2     | Duplicate the top two elements of the stack.              | `dup2`                 |
| dupn     | Duplicate the top n elements of the stack.                | `2 dupn`               |
| swap     | Swap the top two elements of the stack.                   | `swap`                 |
| rev      | Reverse the stack.                                        | `rev`                  |
| rot      | Move the third element to the top of the stack.           | `rot`                  |
| unrot    | Move the top element to the third position of the stack.  | `unrot`                |
| roll     | Moves the nth element to the top of the stack.            | `2 roll`               |
| over     | Copy the second element from the top of the stack.        | `over`                 |
| pick     | Copies the nth element to the top of the stack.           | `2 pick`               |
| nip      | Remove the second element from the top of the stack.      | `nip`                  |
| depth    | Returns the depth of the stack.                           | `depth`                |
| ins      | Insert a value below the top n elements: `n value ins` | `1 2 3 2 99 ins`       |
| count    | Pop a value and count its occurrences in the rest of the stack. | `5 5 7 5 count` |
| clear    | Clear the stack.                                          | `clear`                |
| disp     | Display the stack.                                        | `disp`                 |


### Control Operators
| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| if       | Conditional statement                                 | `true {...} if`            |
| ifelse   | Conditional statement with an else block              | `true {"yes"} {"no"} ifelse`  |
| iferror  | Run the catch block if the first block raises an error, with the stack put back as it was | `{1 0 /} {"caught"} iferror` |
| try      | Like iferror, with the error pushed as a dictionary ('kind', 'message', 'stack') before the handler runs | `{1 0 /} {"kind" get} try` |
| throw    | Raise your own error: `kind message throw`            | `{"E" "boom" throw} {"message" get} try` |
| cond     | Multi-branch conditional (first matching pair wins)   | `5 :x set {x 0 >} {"pos"} {true} {"other"} 2 cond` |
| do       | Loop                                                  | `0 10 :i {i echo} do`      |
| dolist   | Loop over the elements of a list                      | `[1 2 3] :x {x echo} dolist` |
| times    | Loop a specified number of times                      | `{dup ++} 10 times`        |
| while    | Loop while a condition is true                        | `0 :i set {i 10 <} {i ++ :i set} while` |
| loop     | Repeat a block until `break`                          | `0 {1 + dup 10 > {break} if} loop` |
| break    | Break out of a loop                                    | `break`                   |


### Function, Macro, Lambda, and Variable Operators
| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| defun    | Define a function                                     | `{x y} {x y *} :multiply defun` |
| alias    | Name a code snippet (prelude)                         | `{2 ^ 3 * 5 +} {calculatePowerAndAdd} alias` |
| defmacro | Define a macro                                        | `{c b} {{c eval not {b eval} if}} {unless} defmacro` |
| macroexpand | Push a macro's expansion without running it        | `{0 >} {"neg" echo} {unless} macroexpand` |
| code-text | The text of a block, without running it (`parse eval` reads it back) | `{1 2 +} code-text` |
| code=    | Whether two blocks are the same code, token by token, without running them | `{1 2 +} {3} code=` |
| gensym   | Push a fresh unique name for macro temporaries        | `gensym :t =`               |
| symbol   | Make a symbol from a string or a quoted name          | `"x" symbol`               |
| lambda   | Create a lambda function                              | `{x y} {x y *} lambda`    |
| set      | Assign a value to a variable                          | `3 :x set`                |
| =        | Assign a value to a variable (alias for `set`)        | `3 :x =`                  |
| global   | Assign a value to a global variable                   | `42 :answer global`      |


### List Operators
| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| map      | Apply a function to each element of a list            | `[1 2 3] {2 *} map`        |
| zip      | Pair up the elements of two lists: `[[1 4] [2 5] [3 6]]` | `[1 2 3] [4 5 6] zip` |
| filter   | Filter a list based on a condition                    | `[1 2 3 4 5] {2 % 0 ==} filter` |
| at       | Push element i, taking the container off (`nth` leaves it) | `[10 20 30] 1 at`     |
| slice    | Elements a up to b as a new value of the same kind (list, array or string) | `[10 20 30 40] 1 3 slice` |
| all      | Check if all elements of a list are true              | `[true true false] all`    |
| any      | Check if any element of a list is true                | `[true false false] any`   |
| car      | Return the first element of a list                    | `[1 2 3] car`              |
| cdr      | Return the list without its first element             | `[1 2 3] cdr`              |
| cons     | Prepend an element to a list                          | `1 [2 3] cons`             |
| pair?    | Return true if the value is a non-empty list          | `[1 2 3] pair?`            |
| apply    | Expand list elements onto the stack and apply a function | `[3 4] {+} apply`       |
| collect  | Run a block on an empty stack and push what it left as one list | `{1 2 3} collect` |
| expand   | Push the elements of a list, or each token of a code block as a one-token block | `[1 2 3] expand`, `{a b} expand` |
| concat-block | Join two code blocks                              | `{a b} {c} concat-block`   |

### Array and Dictionary Operators
| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| array    | Make an array (changeable in place) from a list, a string or a block | `[1 2 3] array` |
| array-of | Make an array of n slots that all hold x              | `5 0 array-of`             |
| at!      | Store v at index i of an array: `v a i at!`           | `9 [1 2 3] array 0 at!`    |
| append!  | Add v at the end of an array: `v a append!`           | `4 [1 2 3] array append!`  |
| pop!     | Take the last element off an array and push it        | `[1 2 3] array pop!`       |
| dict     | Make an empty dictionary                              | `dict`                     |
| get      | Value of key k, or null when k is not there: `d k get` | `dict "k" get`            |
| put!     | Store v under key k: `v d k put!`                     | `1 dict "k" put!`          |
| has?     | True if the dictionary has key k                      | `dict "k" has?`            |
| del!     | Remove key k (an error when it is not there)          | `dict :d set 1 d "k" put! d "k" del!` |
| keys     | The keys as a list, in the order they were added      | `dict keys`                |
| values   | The values as a list                                  | `dict values`              |
| same?    | True if two arrays or dictionaries are the same one   | `dict dup same?`           |

Note: Blocks, lambdas and functions passed to `map` and `filter` must leave exactly one value for each element, and the block of `reduce` / `fold` exactly one value per step (collect several with `listn`). For side-effect-only iteration (e.g. printing each element), use `dolist` instead.


### Type Operators
| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| int      | Convert to int                                        | `3.7 int`                  |
| float    | Convert to float                                      | `3 float`                  |
| str      | Convert to string                                     | `42 str`                   |
| bool     | Convert to bool                                       | `1 bool`                   |
| complex  | Convert to complex number                             | `3 complex`                |
| type     | The kind of a value as a symbol (`:int`, `:str`, `:array`, `:null`, ...) | `42 type`                  |
| int?     | Returns true if the value is an int (not bool)        | `42 int?`                  |
| float?   | Returns true if the value is a float                  | `3.14 float?`              |
| str?     | Returns true if the value is a string                 | `"hello" str?`             |
| symbol?  | Returns true if the value is a symbol                 | `:x symbol?`               |
| bool?    | Returns true if the value is a bool                   | `true bool?`               |
| complex? | Returns true if the value is a complex number         | `1+2j complex?`            |
| list?    | Returns true if the value is a list (an array is not) | `[1 2 3] list?`            |
| array?   | Returns true if the value is an array                 | `[1 2 3] array array?`     |
| dict?    | Returns true if the value is a dictionary             | `dict dict?`               |
| code?    | Returns true if the value is a code block, without running it (a lambda is not) | `{1 2 +} code?` |
| null?    | Returns true if the value is null (an empty list is not) | `null null?`           |
| empty?   | Returns true if a list, an array, a string or a dictionary has no elements | `[] empty?` |
| number?  | Returns true if the value is a number (int, float, or complex) | `42 number?`    |


### Other Operators
| Operator | Description                                           | Example                    |
|----------|-------------------------------------------------------|----------------------------|
| sub      | Wrap the top value in a one-token code block          | `:x sub`                   |
| subn     | Wrap the top n values in one code block               | `1 2 2 subn`               |
| ans      | Push again the result of the last input that left one | `ans`                      |
| include  | Run another script here, in this scope, every time    | `"file.stk" include`       |
| require  | Run another script once per interpreter               | `"file.stk" require`       |
| eval     | Run a code block, a symbol or a lambda (text: `parse` first) | `{3 5 +} eval`, `'3 5 +' parse eval` |
| echo     | Print the specified value to stdout without adding it to the stack | `3 4 + echo`  |
| echo-err | Print the specified value to standard error, shown as `echo` shows it | `"warning" echo-err` |
| print-err | The same as `echo-err`                               | `"warning" print-err`      |
| printc-err | Print the specified value to standard error without a newline | `"." printc-err` |
| read     | Read one line from the console and push it as a code block | `read`                |
| read-line | Read one line of standard input as a string (null at the end) | `read-line`        |
| read-stdin | Read the rest of standard input as one string | `read-stdin`                 |
| args     | The command-line arguments after the script name, as strings | `args`            |
| script-path | The absolute path of the running file (null in the REPL) | `script-path`      |
| script-dir | Its directory | `script-dir`                                                  |
| main-script-path | The absolute path of the script the command line ran (null in the REPL) | `main-script-path` |
| main?    | Whether the running code is that script (false inside an included file) | `main?`       |
| read-stdin-bytes | The rest of standard input as a list of bytes (0 to 255) | `read-stdin-bytes`  |
| write-stdout-bytes | Write a list of bytes to standard output | `[72 105 10] write-stdout-bytes` |
| write-stderr-bytes | Write a list of bytes to standard error | `[72 105 10] write-stderr-bytes` |
| write-to-file | Write the top element of the stack to a file       | `3 "output.txt" write-to-file` |
| append-to-file | Append the top element of the stack to a file      | `3 "output.txt" append-to-file` |
| read-from-file | Read the contents of a file and push it to the stack | `"input.txt" read-from-file` |
| file-exists | Check if a file exists                                | `"file.txt" file-exists`    |
| read-bytes | Read a whole file as a list of bytes (0 to 255)      | `"image.png" read-bytes`    |
| write-bytes | Write a list of bytes to a file                     | `[72 105] "out.bin" write-bytes` |
| path-join | Join two parts of a path (the right one may be a list) | `"data" ["in" "x.txt"] path-join` |
| list-dir | The names inside a directory, in name order            | `"." list-dir`              |
| path-base | The last part of a path                               | `"a/b/c.txt" path-base`    |
| path-dir | The directory part of a path                           | `"a/b/c.txt" path-dir`     |
| encode   | The bytes of a string in an encoding                   | `"hi" "utf-8" encode`     |
| decode   | The string a list of bytes spells in an encoding       | `[104 105] "utf-8" decode` |



## Constants
| Constants | Description      |
|-----------|------------------|
| e         | Euler's number   |
| pi        | Pi               |
| phi       | Golden ratio     |
| tau       | Tau              |
| nan       | Not a number     |
| inf       | Infinity         |

`true`, `false` and `null` are literals rather than constants: they are values, never names, and cannot be redefined.
