Clyx is a concatenative, stack-oriented programming language designed for simplicity, minimalism, and metaprogramming capabilities. It uses postfix notation (aka Reverse Polish Notation, RPN), where operations are performed on a global stack. Clyx features homoiconicity: code is structured as Q-forms (special forms to represent data similar to Python or Tcl lists), which can be manipulated as data and executed dynamically.
This document describes the stack effects and behavior of the **50 primitive core words**, **3 bootstrapped core words**, and **42 standard library words** present in the reference implementation.
The Clyx runtime itself allows the programmer to redefine any already defined word, including the core ones and the ones from the standard library. Unlike e.g. Forth, where words are resolved at compile-time, Clyx words are resolved at runtime, so such redefinitions may affect all previously established behavior. That's why, as a rule, any **predefined** Clyx word, both in the language core and the standard library, must not exceed 6 characters. This is done to encourage programmers to define their own human-readable words (7+ characters long) without any risk of overwriting existing word definitions.
The conventional source file suffix for Clyx code is `.clx`.
The Clyx interpreter accepts one or more `.clx` source files as command-line arguments. If multiple files are specified, the interpreter executes them in the order they are passed.
After running all specified source files, the interpreter checks if a word named `_main` is defined in the workspace. If `_main` is present, it is automatically executed as the program's entry point. If no arguments are passed, it runs the standard interactive REPL.
With the reference implementation installed in a POSIX-compatible environment, Clyx program sources may be made executable if they start with a `#!/usr/bin/env clyx` shebang.
-`c` represents a boolean flag (`1` for true, `0` for false).
---
## Syntax and Data Types
Clyx supports three basic data types:
1.**Numbers**: Integers (e.g., `42`) and Floating-point numbers (e.g., `3.14`).
2.**Strings**: Sequences of characters enclosed in double quotes. Escaping double quotes (`\"`), backslashes (`\\`), and whitespace characters (`\n` for newline, `\t` for tab, `\r` for carriage return, `\s` for space, `\b` for backspace, `\f` for form feed) is supported inside strings using a backslash (e.g., `"hello \"world\""`, `"a\\b"`, or `"hello\nworld"`).
In Clyx, the evaluation engine executes any string token that matches a defined word name. This means that double-quoted string literals that match a registered word name (such as `"dup"`, `"+"`, or `"."`) **will be executed as that word** when evaluated, rather than being pushed as a literal string.
For example:
- Running `"ok"` pushes the string `"ok"` onto the stack.
- Running `"."` executes the print/output primitive `.`, popping the top element of the stack instead of pushing a dot string.
#### Workaround: Constructing Colliding Strings
To push a string literal that collides with a word name onto the stack, you can construct it dynamically using ASCII codes and the `chr` primitive.
For example, to pass the current directory path `.` to `listd`:
```clx
46 chr listd
```
Where `46` is the ASCII value for `.`. This pushes the string `.` onto the stack without invoking the print primitive, allowing `listd` to consume it.
### Comments
Any line fragment starting with `#` to the end of the physical source line is regarded as a comment in Clyx.
---
## 1. Stack Manipulation Primitives
### `dup` (DUPlicate)
- **Stack Effect**: `( x -- x x )`
- **Description**: Duplicates the top element of the stack.
### `drop`
- **Stack Effect**: `( x -- )`
- **Description**: Discards the top element of the stack.
### `swap`
- **Stack Effect**: `( x y -- y x )`
- **Description**: Exchanges the top two elements of the stack.
- **Description**: Deconstructs a Q-form or string. If it is non-empty, it pushes the remaining Q-form/string, the first element/character code, and a success flag `1`. If it is empty, it pushes the empty Q-form/string and a failure flag `0`.
- **Description**: Sets the element at index `idx` in the Q-form `[q]` to the value `x`, returning the modified Q-form. Pushes `None` if the operand is not a Q-form.
- **Description**: Converts the value `val` (if it is a string) to a Q-form of its byte values/integers. If `val` is already a Q-form, it does nothing.
- **Description**: Pops `y`, pops `x`, and pushes the integer division quotient `div` followed by the modulo remainder `mod` onto the stack.
### `shl` (Shift Left)
- **Stack Effect**: `( x f -- res )`
- **Description**: Pops the shift factor `f`, pops the argument `x`. Performs bit shift left `x << f` if `f` is positive (or zero), and bit shift right `x >> abs(f)` if `f` is negative.
### `^` (Power)
- **Stack Effect**: `( x y -- x^y )`
- **Description**: Pops `y`, pops `x`, and pushes `x` raised to the power of `y`.
### `sin` (Sine)
- **Stack Effect**: `( x -- sin(x) )`
- **Description**: Computes the sine of `x` (in radians).
### `cos` (Cosine)
- **Stack Effect**: `( x -- cos(x) )`
- **Description**: Computes the cosine of `x` (in radians).
### `atan` (Arctangent)
- **Stack Effect**: `( x -- atan(x) )`
- **Description**: Computes the arctangent of `x` (in radians).
### `exp` (Natural Exponent)
- **Stack Effect**: `( x -- exp(x) )`
- **Description**: Computes the exponential of `x` ($e^x$).
### `log` (Natural Logarithm)
- **Stack Effect**: `( x -- log(x) )`
- **Description**: Computes the natural logarithm of `x` ($\ln(x)$).
---
## 5. Logic & Control Flow
### `0=` (Equals to Zero)
- **Stack Effect**: `( x -- c )`
- **Description**: Pushes `1` if `x` is equal to `0`; otherwise pushes `0`.
### `0<` (Less than Zero)
- **Stack Effect**: `( x -- c )`
- **Description**: Pushes `1` if `x` is less than `0`; otherwise pushes `0`.
### `nand` (Bitwise NAND)
- **Stack Effect**: `( x y -- ~(x&y) )`
- **Description**: Pops `y`, pops `x`, and pushes the bitwise NAND of `x` and `y`.
- **Description**: Pops the condition `c`, the true branch Q-form `t`, and the false branch Q-form `f`. If `c` is non-zero, executes `t`; otherwise executes `f`.
- **Description**: Repeatedly executes the condition Q-form `[cond]`. If the top element of the stack after `[cond]` is non-zero, executes `[body]` and loops again; otherwise terminates.
- **Description**: Defines a new word associated with `name`. If the next token in the interpreter stream is `[`, parses it as a Q-form and defines `name` to execute that Q-form. Otherwise, defines `name` to represent the top stack value `x`.
- **Description**: Inspects the top element of the stack `x` (without popping it) and pushes its type code: `0` if it's a number, `1` if it's a string, or `2` if it's a Q-form.
- **Description**: Outputs the top stack element `x` to standard output, followed by a newline.
### `emit` (Emit Character)
- **Stack Effect**: `( code -- )`
- **Description**: Prints the character represented by the ASCII/Unicode character code integer to standard output without a newline.
### `fopen` (File Open)
- **Stack Effect**: `( filename mode -- fd )`
- **Description**: Opens the file at `filename` with the specified `mode` string (e.g., `"r"` or `"w"`). Pushes the file descriptor/object onto the stack. If `filename` is `0` or `"0"`, it returns standard input (`sys.stdin`) or standard output (`sys.stdout`) depending on the mode.
### `nopen` (Network Open)
- **Stack Effect**: `( host port -- fd )`
- **Description**: Creates a TCP connection.
- If `host` is `"0.0.0.0"`, it starts a listening server TCP socket on `port` and pushes the server socket descriptor onto the stack.
- Otherwise, it creates a client TCP connection to `host` on `port` and pushes the connection file-like descriptor onto the stack.
- Sets `SO_REUSEADDR` to ensure the socket is instantly released upon termination.
- **Description**: Writes the string/bytes `data` to the descriptor `fd`. Returns the number of characters/bytes written. Automatically flushes standard/socket buffers if possible.
### `read`
- **Stack Effect**: `( fd -- data )` or `( fd -- conn_fd )`
- **Description**: Reads from the descriptor `fd`.
- If `fd` is a listening server socket (created by `nlstn`), it accepts the incoming connection and returns the connection file-like descriptor.
- If `fd` is standard input or a socket connection wrapper, it reads a single line (up to a newline character) and returns it with trailing newlines stripped.
- Otherwise (for standard files), it reads the entire contents of the file until EOF.
### `close`
- **Stack Effect**: `( fd -- )`
- **Description**: Closes the file/socket descriptor `fd`. Safe against closing standard streams (`stdin`, `stdout`, `stderr`).
### `delf` (Delete File)
- **Stack Effect**: `( filename -- )`
- **Description**: Deletes the file named `filename` from the file system.
### `maked` (Make Directory)
- **Stack Effect**: `( path -- )`
- **Description**: Creates a new directory at the specified `path`.
- **Description**: Lists the contents of the directory at `path`. Pushes a Q-form of strings representing the names of the files and directories inside the directory.
**Warning**: relying upon the primitives from this group reduces your Clyx application's portability and the amount of platforms it can potentially run on, so they should be used very carefully.
- **Description**: Exits the program/interpreter process with the specified exit code.
**N.B.**: on the platforms that don't support specifying process exit codes, this primitive may either do nothing, exit the program the usual way supported by the platform or trigger a global interpreter restart.
- **Description**: Pops the string `expr` from the stack and evaluates or executes it in the host environment.
- In the Python implementation, it evaluates `expr` as a Python expression and pushes the resulting value back onto the stack.
- In the Go implementation, it executes `expr` as a system shell command, redirects its stdin/stdout/stderr to the current process, and pushes the command's exit code back onto the stack.
**N.B.**: this primitive may not be supported on all targets, and its behavior varies by implementation. Only use as a last resort in controlled and/or sandboxed environments. Never pass unvalidated user input to this primitive.
- **Description**: Reads the file `filename` using `readf`, converts the Q-form of bytes to a string using `q2s`, and runs the resulting Clyx code in real-time using `i`.
These words are defined in the standard library file `lib.clx` and loaded dynamically during interpreter initialization. They are categorized below by domain and purpose:
- **Description**: Loops repeatedly. The body `actions` is executed, and must leave the next condition value on the stack. If the condition is non-zero, the loop repeats; otherwise it terminates.
- **Description**: Writes the `content` string to the file `filename`. Pushes the number of characters written onto the stack.
#### `nlstn` (Network Listen)
- **Stack Effect**: `( port -- fd )`
- **Description**: Creates a server TCP socket listening on all interfaces (`"0.0.0.0"`) on the specified `port`. Pushes the server socket descriptor onto the stack.
- **Description**: Pushes the length of `val`. If `val` is a Q-form, it returns the number of elements; if it is a string, it returns the number of characters.
- **Description**: Pops `s2`, pops `s1`, and pushes `1` if the two strings `s1` and `s2` (or their character Q-form equivalents) are equal; otherwise pushes `0`.
- **Description**: Concatenates `s1` and `s2` (which can be strings or Q-forms of character codes) and pushes the result as a Q-form of character codes representing the concatenated string.