Tutorial
What Is a Stack-Oriented Programming Language?
A stack is a data structure that follows the LIFO rule: Last In, First Out.
A stack-oriented programming language is a language that uses a stack to store data and perform operations.
Buyan is a stack-oriented language. Every operation works with values stored on the stack.
Let us look at a simple program step by step. It adds two numbers and leaves the result on the stack. This example uses pseudocode:
2 2 +
There are three stack operations:
2puts the number 2 on the stack. The stack is now[2].2puts another number 2 on the stack. The stack is now[2, 2].+takes the top two numbers, adds them, and puts the result on the stack. The stack is now[4].
Stack Signature
In Buyan, a stack signature describes the types on the stack. Every word describes two stack states: the state it expects before it runs and the state it produces after it runs.
Here is a word that adds two numbers:
def add(usize, usize -- usize) ... end
The -- separates the two stack states. The signature usize, usize -- usize means that the word takes two usize values from the top of the stack and leaves one usize value on top.
Stack Polymorphism
Buyan supports stack polymorphism. It lets one word work with different types or different stack states. There are two syntax features for this:
- Type variable. A type variable lets a stack signature use different types. Add the variable to the word declaration. For example:
def example<T>(T, T -- T). This word takes two values of typeTand leaves one value of typeT. If you call it withusizevalues, it leaves ausize. If you call it withu8values, it leaves au8. - Stack variable. A stack variable represents a stack state. Add it to the word declaration. For example:
def example<...T>(...T, usize -- ...T). This word takes a stack described by...Twith ausizevalue on top. It removes theusizeand leaves the rest of the stack unchanged.
Structure of a Buyan Program
A Buyan program can contain:
- Imports — words or structures from other modules.
- A module name — every module has a unique name.
- Structures — custom data types.
- Words — operations similar to functions in other programming languages.
Control Flow
Control flow uses special words. Like everything else in Buyan, these words work through the stack.
Conditions
Conditions in Buyan work like conditions in other programming languages. They run different code depending on a Boolean value.
The word std.cfg.if expects these values on the stack:
- A
boolcondition. - A lambda to run when the condition is true.
- A lambda to run when the condition is false.
Example:
2u8 2u8 std.u8.add
4u8 std.u8.eq
| -- | { then }
| -- | { else }
std.cfg.if
First, the program adds 2 + 2 and puts 4u8 on the stack. It then compares this value with 4u8 and puts the result on the stack. In this example, the result is true.
Next, it puts the then lambda on the stack. This lambda runs when the condition is true. It then puts the else lambda on the stack. This lambda runs when the condition is false.
After std.cfg.if runs, the stack contains the result of the then or else lambda.
Important: the then and else lambdas must produce the same stack state.
Loops
The word std.cfg.while creates a loop. It expects these values on the stack:
- A condition lambda. It leaves a
boolon top of the stack and runs before every loop iteration. - A body lambda. It runs on every iteration while the condition is true.
Here is a loop that runs 10 times:
0u8
| u8 -- u8, bool | {
std.stack.dup 10u8 std.u8.lt
}
| u8 -- u8 | {
1u8 std.stack.add
}
std.cfg.while
First, the program puts 0u8 on the stack. This value is the counter.
Next, it puts a lambda on the stack. This lambda checks whether the counter is less than 10. It returns true when the counter is less than 10 and false otherwise.
It then puts another lambda on the stack. This lambda adds 1 to the counter and returns the new value.
The loop runs 10 times and leaves 10u8 on the stack.
Data Types
Integers
Buyan has several unsigned integer types:
usize— an unsigned integer. Its size depends on the target platform.u8— an 8-bit unsigned integer.u16— a 16-bit unsigned integer.
You can put integer values on the stack with this syntax:
42puts theusizevalue42on the stack.0x2Aputs the hexadecimalusizevalue42on the stack.42u8puts theu8value42on the stack.0x2Au8puts the hexadecimalu8value42on the stack.'*'puts the character*on the stack as theu8value42.42u16puts theu16value42on the stack.0x2Au16puts the hexadecimalu16value42on the stack.
You can learn more about each type in the standard library documentation:
Str
The Str type stores a sequence of characters. At this time, strings can contain only ASCII characters.
Use this syntax to put a string on the stack:
"Hello, World!"
When you create a string, the compiler reserves space in static memory. It stores the string as a packed array of ASCII bytes with the string length at the beginning. The string stays in memory until the program ends.
You can learn more in the standard library documentation for Str.
Structures
Structures are custom data types with one or more fields. They group stack values into one logical value.
Use this syntax to define a structure:
struct Point(u8, u8);
Use Point< to pack values into a structure. The required field values must be on top of the stack. A Point needs two u8 values. Its pack operation has this signature: u8, u8 -- Point.
Use Point> to unpack a structure. It removes the structure from the stack and puts its fields on the stack. Its signature is Point -- u8, u8.
Use Point.field to get a structure field. For example, use Point.0 to get the first field of Point. This operation removes the Point structure from the stack and puts its first field on top. Its signature is Point -- u8.
Lambda
A lambda is an anonymous word. You can pass it to another word or return it from another word.
Use this syntax to define a lambda:
| A -- B | { ops }
Here, A is the stack state before the lambda runs, B is the stack state after it runs, and ops is the list of operations in the lambda body.
A lambda signature looks like this:
| A -- B |
It looks like a lambda declaration, but it has no body.