Quartz
Quartz & Zircon form an end-to-end toolchain for a custom programming language. It includes Quartz, a high-level, imperative language, and Zircon, a cross-platform, stack-based virtual machine that runs the compiled Quartz bytecode.
Quartz
Quartz is a simple, dynamically-typed, imperative language.
Example
A program to calculate the 10th Fibonacci number:
fib(n) {
if (n <= 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
main() {
return fib(10);
}
Compilation Pipeline
The Quartz compiler transforms source code into Zircon bytecode through the following stages:
- Lexing & Parsing: The source code is tokenized and parsed into an Abstract Syntax Tree (AST).
- Lowering to IR: The AST is converted into a lower-level Intermediate Representation (IR) for analysis and optimization.
- Bytecode Emission: The IR is translated into Zircon bytecode, ready for execution by the virtual machine.
Zircon
Zircon is a stack-based virtual machine designed to execute bytecode generated by the Quartz compiler.
Zircon Bytecode
Bytecode File Format
A compiled .zirc
file has the following binary structure:
- Magic Number: A 4-byte sequence (
ZRCN
) to identify the file type. - Version: A single byte indicating the bytecode version.
- Constant Pool: A table of constants (numbers, strings) used by the program.
uint32
: Number of constants.- For each constant:
byte
: Type of the constant....
: The constant’s value.
- Functions: A table of all functions defined in the program.
uint32
: Number of functions.- For each function:
int32
: Number of arguments.uint32
: Number of instructions.- For each instruction:
byte
: The opcode.ushort
(optional): The operand, if the opcode requires one.
Bytecode Reference
Opcode | Hex | Operand(s) | Description |
---|---|---|---|
Stack Operations | |||
PushConst |
0x01 |
2-byte const index | Pushes a constant from the constant pool onto the stack. |
Pop |
0x02 |
None | Pops the top value from the stack. |
Dup |
0x03 |
None | Duplicates the value at the top of the stack. |
Swap |
0x04 |
None | Swaps the top two values on the stack. |
PushNil |
0x05 |
None | Pushes a nil value onto the stack. |
Arithmetic | |||
Add |
0x10 |
None | Pops two numbers, adds them, and pushes the result. |
Subtract |
0x11 |
None | Pops two numbers, subtracts the top from the second, and pushes the result. |
Multiply |
0x12 |
None | Pops two numbers, multiplies them, and pushes the result. |
Divide |
0x13 |
None | Pops two numbers, divides the second by the top, and pushes the result. |
Modulo |
0x14 |
None | Pops two numbers, performs modulo, and pushes the result. |
Negate |
0x15 |
None | Pops a number, negates it, and pushes the result. |
Logical Operations | |||
And |
0x20 |
None | Pops two booleans, performs a logical AND, and pushes the result. |
Or |
0x21 |
None | Pops two booleans, performs a logical OR, and pushes the result. |
Not |
0x22 |
None | Pops a boolean, inverts it, and pushes the result. |
Comparison Operations | |||
Equal |
0x30 |
None | Pops two values, checks for equality, and pushes the boolean result. |
GreaterThan |
0x31 |
None | Pops two numbers, compares them (> ), and pushes the boolean result. |
LessThan |
0x32 |
None | Pops two numbers, compares them (< ), and pushes the boolean result. |
Control Flow | |||
Jump |
0x40 |
2-byte address | Sets the instruction pointer to the specified address. |
JumpIfTrue |
0x41 |
2-byte address | Pops a value; if true, jumps to the specified address. |
JumpIfFalse |
0x42 |
2-byte address | Pops a value; if false, jumps to the specified address. |
I/O | |||
Print |
0x60 |
None | Pops a value and prints its string representation to the console. |
Variables | |||
GetLocal |
0x70 |
2-byte local index | Pushes the value of a local variable onto the stack. |
SetLocal |
0x71 |
2-byte local index | Pops a value and assigns it to a local variable. |
GetGlobal |
0x72 |
2-byte global index | Pushes the value of a global variable onto the stack. |
SetGlobal |
0x73 |
2-byte global index | Pops a value and assigns it to a global variable. |
Functions | |||
Call |
0x80 |
2-byte function index | Calls a function, setting up a new call frame. |
Return |
0x81 |
None | Returns from the current function. |
Array Operations | |||
NewArray |
0x90 |
None | Pops a size, creates an array, and pushes it onto the stack. |
GetElement |
0x91 |
None | Pops an index and an array, and pushes the element at that index. |
SetElement |
0x92 |
None | Pops a value, an index, and an array, and sets the element. |
ArrayLength |
0x93 |
None | Pops an array and pushes its length. |
Object Operations | |||
NewObject |
0xA0 |
None | Creates a new, empty object (dictionary) and pushes it. |
GetProperty |
0xA1 |
2-byte const index | Pops an object, gets a property by name (from const pool), and pushes it. |
SetProperty |
0xA2 |
2-byte const index | Pops a value and an object, and sets a property by name. |
VM Control | |||
Halt |
0xFF |
None | Stops the virtual machine. |
Source
The source for Quartz is available on GitHub.