Pile
Introduction
Pile is an esoteric, concatenative, stack-based and compiled programming language made for educational purposes.
How Pile works
Pile's compiler uses LLVM to compile the source code and execute it. You can compile it to an executable or use the JIT compiler to execute the code directly. One problem I ran into throughout early Pile compiler development is that LLVM is not Stack-based. So I had to solve the problem by having stack processed at compile time! I know it might sound weird but that's one of the main reasons this language is esoteric!
Pile’s compiler is 100% written in the Python programming language. The entire implementation of Pile is at the official Github repository: https://github.com/marc-dantas/pile/
Familiarizing with Pile
Here’s a simple “hello world” program in Pile:
// simple comment ... "hello world" dump
Because it’s a stack-based language, Pile uses the Reverse Polish Notation to represent stack operations. So, a simple mathematical operation like 1 + 1
turns into 1 1 +
.
Pile’s typing system
Pile is also a statically typed language and it has 4 types:
integer
: Represents a signed 32-bit integer value.bool
: Represents a 1-bit integer value (1 or 0).float
: A floating point value.string
: Character pointer (i8*
orchar*
)
Each operation has it’s own typing, and if you disrespect them, you’ll get an error like this:
pile: error at ...: | type mismatch: | `/` operation got mismatched types (float, | integer) but operation expects (float, float)
All operations in Pile are type-checked during compile-time.
Operations
Operations in pile are basically every word in a Pile program. Except literals and some control flow words. > Words are every token in a Pile program
Pile has a very small list of built-in operations:
Operation | Description |
---|---|
+ |
mathematical addition operation |
- |
mathematical subtraction operation |
* |
mathematical multiplication operation |
/ |
mathematical division operation |
% |
mathematical remainder (modulo) operation |
> |
“greater than” comparison operation |
< |
"less than” comparison operation |
>= |
“greater than or equal” comparison operation |
<= |
“less than or equal” comparison operation |
!= |
“not equal” comparison operation |
= |
“equal” comparison operation |
| |
bitwise OR operation |
& |
bitwise AND operation |
>> |
bitwise shift right operation |
<< |
bitwise shift left operation |
drop |
drops a value from the top of the stack (a -- )
|
dup |
duplicates the last element to the top of the stack (a -- a a )
|
over |
copies the 2nd last element on top of the stack (a b -- a b a )
|
rot |
moves the 3rd last element to the top of the stack (a b c -- b c a )
|
swap |
swaps the top two values on top of the stack (a b -- b a )
|
dump |
prints the last element (of any type) on top of the stack to stdout |
Here's a simple demonstration of all operations in Pile programming language:
// math 1 1 + dump // Sums 1 + 1 3 1 - dump // Subtracts 3 by 1 2 2 * dump // Multiplies 2 by 2 1.0 2.0 / dump // Divides 1 by 2 (half) 1 2 % dump // Gets the remainder of the division 1/2 // comparison 1 1 = dump // Compares 1 == 1 3 1 != dump // Compares 3 != 1 2 2 > dump // Compares 2 > 2 2 2 >= dump // Compares 2 >= 2 1 2 < dump // Compares 1 < 2 1 2 <= dump // Compares 1 <= 2 // bitwise 1 1 | dump // 0001 | 0001 3 1 & dump // 0011 & 0001 2 2 >> dump // 0010 >> 0010 2 2 << dump // 0010 << 0010 // stack operations 1 drop // There's nothing here anymore :( 1 dup dump dump // There are two values here now :) 1 2 over dump dump dump // Now it's 1 2 1 1 2 3 rot dump dump dump // Rotated numbers: 2 3 1 69 96 swap dump dump // They even swapped the digits!
Control flow
In Pile you can control the flow of your program using two statements:
If conditions
If conditions are very simple in Pile, here’s it’s syntax:
condition if ... [else ...] end
and Here’s a simple example of how to use it:
10 10 = if 1 dump 1 1 = if 3 dump else 4 dump end else 2 dump end
While loops
While loops are a little bit different. Here’s it’s syntax:
while condition do ... end
and here’s a simple example of how to use it:
0 while dup 10 <= do dup dump dup 2 % 0 = if 2 + end end drop
Strings
strings in Pile are C-styled strings. That means that every string in Pile is null-terminated (it has a NULL character at the end). Here it is an example of how to work with strings:
"hello" dump // Pushes a char pointer to the stack and prints "world" dump