Numbers
Paradigm(s) | imperative |
---|---|
Designed by | User:Xorol |
Appeared in | Category:2021 |
Memory system | Two stacks |
Computational class | Turing complete |
Major implementations | [1] |
File extension(s) | .nums , .nmod |
Numbers is an esoteric programming language created by User:Xorol. The main gimmick is that all of the commands (with some exceptions) are numbers. It uses two stacks, but only one can be used at a time.
Data storage
Numbers stores its data in two stacks: the main stack and the control stack. Most commands that perform operations on the stack are indifferent as to which stack they're using. But, most of the commands starting with 4
will only use the control stack.
Toggling stacks
You can toggle between stacks with the command 21
. The program starts with the main stack selected.
Commands
Commands are split into four groups: arithmetic, stack manipulation, IO, and control flow. Arithmetic commands start with 1, stack commands with 2, etc.
Command | Arguments | Description |
---|---|---|
Arithmetic | ||
10 | 2 | Adds a + b |
11 | 2 | Subtracts a - b |
12 | 2 | Multiplies a * b |
13 | 2 | Divides a / b |
14 | 2 | Floor divides a // b |
15 | 2 | Modulos a % b |
16 | 1 | Increments a++ |
17 | 1 | Decrements a-- |
18 | 1 | 1 if a is negative, else 0
|
19 | 1 | Factorial a! |
Stack manipulation | ||
20 | Syntactic | Pushes the number after it to the stack. Alias: *
|
21 | 0 | Toggles which stack is selected |
22 | 2 | Swaps a and b |
23 | 1 | Pops a |
24 | 1 | Moves a to the unselected stack |
25 | 1 | Moves a (from the unselected stack) to the selected stack |
26 | 1 | Duplicates a |
27 | 0 | Clears the stack |
IO | ||
30 | 1 | Prints a as it is |
31 | 1 | Prints a as a character |
32 | entire stack | Prints the entire stack as integers, separated by spaces |
33 | entire stack | Prints the entire stack as a string |
34 | 0 | Gets input as an integer |
35 | 0 | Gets input as a character, pushing its Unicode representation |
36 | 0 | Gets input as a string, pushing each character's Unicode representation |
Control flow | ||
40 | 1 | Only executes the next command if a is not 0
|
41 | 1 | Only executes the next command if a is 0
|
42 | 1 | Sets the pointer to a |
44 | 1 | Defines a function |
45 | 1, and syntactic args | Maps a as a function onto all following numbers |
46 | entire stack | Loads the file specified by the stack as a module |
There's also a special command: ~
which ends the program.
Further explanation
20
Pushes the number after it to the stack. Examples:
20 5 *5
Both of these push 5
to the stack and are interchangeable.
40
& 41
These will only execute the command after them if the top value on the stack is (or, in the case of 40
is not) 0
. Examples:
This will print 1
*1 40 30
This won't do anything
*0 40 30
But this will
*0 41 30
44
Defines a function, with the following syntax:
*function_name 44 mapping_compatibility function_code 44
Replacing function_name
with the name of the function, mapping_compatibility
with either a 0
or 1
depending on whether the function is to be compatible with mapping (45
), and function_code
with the code for the function. For example:
*6 44 0 *6 30 44
Defines a function 6
, that is incompatible with mapping, and that prints a 6
whenever run.
45
Maps the top value on the stack as a function onto all of its arguments. For example:
*16 45 1 2 3 4 5 6 7 8 9 45
Maps 16
(increment) onto 1 2 3 4 5 6 7 8 9
and puts the results on the stack, in this case 2 3 4 5 6 7 8 9 10
.
Built-in functions
Numbers has a number of built-in functions. All built-in functions are accessible using 10.x
, replacing x
with the name of the function.
Command | Arguments | Description |
---|---|---|
10 | 2 | 1 if a == b else 0
|
11 | 2 | 1 if a > b else 0
|
12 | 2 | 1 if a < b else 0
|
Comments
Comments in Numbers are done using a ;
. For example:
; This is a comment *10 30 ; this is a comment *10 30 ;this is a comment *10 30; error: 30; is not a command
Block comments are done with a double semicolon (;;
) at the start of the opening and closing lines:
;; Start of a block comment inside still inside ;; End of the block comment
Meta-comments
Meta-comments start with ;!
and must be on their own line. They are special comments and affect how the program runs. Here are the ones that are required for a Numbers implementation:
Comment | Arguments | Description |
---|---|---|
NOBUILTINS |
0 | Disables built-in functions |
USE |
1 | Used for modules. Defines the namespace into which the module's contents should be loaded |
The main implementation linked at the top also implements these meta-comments:
Comment | Description |
---|---|
NOILC |
Disables the interpreter's infinite loop checker |
DEBUG |
Activates debug mode |
TOOLS |
Opens the tool menu instead of running the program. |
These are explained in full in the interpreter's README
Stack references
Stack references act as a way to use values that are not on top of the stack. They use the syntax $x
, replacing x
with the index from the top that is being referenced. These can be used as syntactic arguments only; if used as stand-alone commands, an error will be thrown. Examples:
*$1 ; push the second item on the stack to the top 44 $3 ... 44 ; using the fourth item as mapping compatibility $2 ; Error: stack references cannot be used as commands.
Namespaces
Namespaces are containers for functions. All functions within a namespace can be accessed using x.y
, replacing x
with the namespace's name and y
with the function's name. Namespaces can also contain other namespaces, nesting infinitely. They can also be empty. To define one, use the following syntax:
15 { 1 : 0 : *1 30 2 : {} }
This defines a namespace 15
with two things inside it: a function 1
(accessible as 15.1
) and an empty namespace 2
(accessible as 15.2
). Note how the syntax is different inside namespaces: functions use colons instead of the normal 44
syntax, and namespaces have a colon before the opening brace.
Notes
- Make sure you don't have a function spread across two or more lines; functions may only occupy a single line.
- Comments must be on separate lines.
Modules
Modules are just namespaces, but loaded in from a different file, all module files have the extension .nmod
. For example, the code from earlier as a module would look like this:
;!USE 15 1 : 0 : *1 30 2 : {}
That ;!USE 15
defines the namespace the module's contents should be loaded as, besides that, the syntax is exactly the same as for namespaces. Once the module is loaded, the functions inside are accessible as if it were a normal namespace.
To load a module, you have to get its filepath first. The filepaths are all relative to the location of the script. Here's an example filesystem with the corresponding filepaths beside them:
root |-a.nmod (^^a) |--utils | |-b.mod (^b) | |--other | |-c.nmod (c) | |-script.nums |--math |-d.nmod (^^math/d) |--complex |-e.nmod (^^math/complex/e)
As you can see, /
is used to go down a level and ^
is for going up a level. To load it, push the corresponding unicode representation to the stack and run 46
.
Example programs
Hello, world!
The Hello World! program pushes each letter's corresponding ASCII values onto the stack, then prints the stack as a string.
*20 45 72 101 108 108 111 32 87 111 114 108 100 33 45 33
Truth-machine
The truth-machine takes input from the user, if it is a "1" it outputs "1"s indefinitely, if it's a "0" it outputs a singular "0"
34 26 26 30 41 ~ *2 42
Cat program
A cat program outputs whatever the user inputs.
36 33
An infinite version:
36 33 *0 42