/path
- This is still a work in progress. It may be changed in the future.
Designed by | Nazalassa |
---|---|
Appeared in | 2024 |
Memory system | Stack of stacks |
Computational class | Unknown |
Reference implementation | /path/refimpl |
File extension(s) | None |
/path (or: slash-path) is a minimalistic, filename-based language, created by User:Nazalassa in 2024, in which the program is contained not in the file, but in the file path, effectively wasting no disk space.
Overview
Disk space is precious and rare, so /path programs are stored in file paths, rather than files; as a result, /path files never occupy any disk space (except if they contain comments). This makes /path programs very efficient in disk usage.
Program structure and memory
/path programs are structured around 'blocks'. Blocks are separated by '/' characters. Each block contains instructions that will be executed in sequence when the block is executed. Once a block is done, the next one is executed. Some instruction allow to move to other blocks.
There are no empty blocks: //
is equivalent to /
.
Memory in /path is represented by a stack of stacks (the stack stack, or stack²), and any operation that affect a stack other than the stack stack affects only the top stack in the stack stack. Stacks contain integers of arbitrary size.
- Convention: a "stack" always refers to a stack inside the stack stack; the stack stack is to be explicitely referred to as the "stack stack" or the "stack²". The stack refers to the top stack from the stack stack.
The program ends when there are no more blocks to read, i.e when the end of the file path is reached.
Instruction list
Ins. | Description |
---|---|
/
|
Block separator |
\
|
Alternate block separator (for MS-DOS compatibility) |
Stack stack operations | |
v
|
Push a new stack into the stack stack |
k
|
Pop a value from the stack, then create a new stack with this number of values pulled from the previous stack; these values are removed from the previous stack If the number of values is 0, duplicate the stack; if there are not enough values, this is an error |
^
|
Pop the top stack from the stack stack; its values are lost forever |
'
|
Pop the top stack from the stack stack, pushing its values into the next stack |
`
|
Pop the top stack from the stack stack, outputting its values (without trailing newline), which are discarded |
=
|
Duplicate top stack (the two top stacks) |
S
|
Swap the top two stacks, or do nothing if there is less than 2 stacks |
C
|
Clear stack stack (delete everything), and push a new empty stack |
Stack operations | |
0-9
|
Push corresponding number to the stack |
x
|
Pop top of the stack and discard it |
:
|
Duplicate top of the stack |
s
|
Swap the values on top of the stack, or do nothing if there is less than 2 values |
r
|
Reverse the stack |
c
|
Clear stack (delete contents) |
#
|
Push stack length to the stack |
Input/Output | |
<
|
Pop top of the stack and output as character; behaviour is undefined if top of the stack isn't a valid character |
>
|
Push character from input to the stack |
Flow control | |
j
|
Jump: pop a number from the stack, and jump forwards this number of blocks (which can be negative) |
b
|
Branch: pop two numbers a , b from the stack, and jump a blocks if b is not null
|
B
|
Null branch: pop two numbers a , b from the stack, and jump a blocks if b is null
|
Arithmetics | |
+
|
Addition: pop a and b from the stack, and push back b+a
|
-
|
Substraction: pop a and b from the stack, and push back b-a
|
*
|
Multiplication: pop a and b from the stack, and push back b*a
|
d
|
Integer division: pop a and b from the stack, and push back b/a , rounded down; error if a = 0
|
%
|
Modulo: pop a and b from the stack, and push back b%a
|
_
|
Unary minus: inverts the sign of the number on top of the stack |
Logic | |
&
|
AND: pop a and b from the stack, and push back their bitwise AND
|
|
|
OR: pop a and b from the stack, and push back their bitwise OR
|
!
|
NOT: pop top of the stack and push back the bitwise NOT of that value |
q
|
Equal: pop a and b from the stack, and push back 1 if b = a, else 0
|
l
|
Less than: pop a and b from the stack, and push back 1 if b < a, else 0
|
g
|
Greater than: pop a and b from the stack, and push back 1 if b > a, else 0
|
Everything else -> Push character ascii value into the stack (ex. 0 is 48, e is 65, line feed is 10...)
|
- Attempting to pop the last stack will cause the creation of a new, empty stack.
- Attempting to perform an operation (except a swap operation) that requires more values/stacks than there is in the stack will cause an error.
For filesystems that take away the liberty of putting anything in file names, the following equivalences are defined:
Instruction | ^
|
'
|
`
|
=
|
:
|
#
|
<
|
>
|
+
|
-
|
*
|
%
|
_
|
&
|
|
|
!
|
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Equivalent character | P
|
M
|
o
|
D
|
u
|
L
|
O
|
I
|
a
|
R
|
t
|
m
|
n
|
A
|
R
|
N
|
Examples
In the following examples, ...
denotes an arbitrarily long part of the file name.
Clear whatever the beginning of the path made:
/path/to/file/.../.../.../C...
Hello world:
.../C/52*48*1+554**:8+:6+:3-w /,3349**+:3-:eH/<<<<<<<<<<<<<<
Cat:
.../C/><0j
Cat with EOF handling:
.../C/>:1_q2b<0j/0
Quine: (there is nothing in the file, so nothing to print)
...
Decimal number printer:
.../<compute-some-number>1k`
Alternate decimal number printer:
.../<compute-some-number>/1k/:25*%68*+s25*d:0bx/#1B<0j/^/...
Any base [BASE]:
.../<compute-some-number>/1k/:[BASE]%68*+s[BASE]d:0bx/#1B<0j/^/...
Decimal number input, assumes only digits, terminated by newline:
.../v/>:25*q1b68*-0j/xr/#1g1B25**+0j/'/...
Decimal number input, with checking: (0 if non-digits in input, and also prints 'E')
.../v/>:25*q2b68*-::0ls9g|1b0j/E<c03j/xr/#1g1B25**+0j/'/...
.../C/>:25*q2b68*-::0ls9g|1b0j/E<c03j/xr/#1g1B25**+0j/0/:2%4b=l5b^:1k/:25*%68*+s25*d:0bx/#1B<0j/25*<^/1+4_j/0 Note: iteration variable gets incremented by 1 only ^^
99 bottles of beer:
.../C/
- More examples will be added once I figure how to use /path
Implementation
The reference interpreter in python can be found on [|no current link] and at /path/refimpl.
Limits
- /path takes full advantage of the fact that most filesystems can have almost any character in filenames (even LFs!), and can have file paths of arbitrary length. Filesystems that do not support that may not be /path-compatible. For example, NTFS (Windows default filesystem) doesn't accept certain characters in file names when used with Windows, such as
<
or>
, but that's an implementation error from Microsoft. - Note that the maximum length for a filename (between two
/
s, so a /path block) is around 255 characters for most filesystems, so a programmer using long blocks will have to split them in smaller blocks.