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 is a simple, dynamically-typed, imperative language.
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);
}
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 is a stack-based virtual machine designed to execute bytecode generated by the Quartz compiler.
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.
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. |
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.