feat: translate doc to en, add index files
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Internals
|
||||
|
||||
Implementation details of the FZLang virtual machine and compiled programs.
|
||||
|
||||
- [Object layout](./object_layout.md)
|
||||
- [Opcodes](./opcodes.md)
|
||||
- [Virtual machine stacks](./stacks.md)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Object layout
|
||||
|
||||
This page is a placeholder for documentation of the in-memory layout of FZLang objects.
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# Opcodes
|
||||
|
||||
FZLang programs run on the virtual machine included in the FZLang toolchain, which is built alongside the compiler. The FZC compiler can emit the following opcodes, which the VM understands and executes.
|
||||
|
||||
## Loading data and working with the stack
|
||||
|
||||
Codes: `0xF00001`..`0xF00004`
|
||||
|
||||
| Number | Name | Purpose | Argument |
|
||||
| ------ | ---- | ------- | -------- |
|
||||
| 0xF00001 | FZL_OPCODE_LOADCONST | Push constant `N` onto the stack | `N` — constant index |
|
||||
| 0xF00002 | FZL_OPCODE_CALL_BUILTIN | Call built-in function `N` | `N` — function index |
|
||||
| 0xF00003 | FZL_OPCODE_PUSHNUM | Push number `N` onto the stack | `N` — value |
|
||||
| 0xF00004 | FZL_OPCODE_PUSHBOOL | Push boolean `B` onto the stack | `B` — value |
|
||||
|
||||
## Context and environment
|
||||
|
||||
Codes: `0xF10001`..`0xF10005`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xF10001 | FZL_OPCODE_MK_ENVTABLE | Create a new environment |
|
||||
| 0xF10002 | FZL_OPCODE_RM_ENVTABLE | Destroy an environment |
|
||||
| 0xF10003 | FZL_OPCODE_STORE | Create a name in the environment from the value at the top of the stack |
|
||||
| 0xF10004 | FZL_OPCODE_LOOKUP_ENV | Take a name from the stack, look it up in the environment, and push its value |
|
||||
| 0xF10005 | FZL_OPCODE_WRITE | Take a name and value from the stack and write the value to the environment |
|
||||
|
||||
## Control flow
|
||||
|
||||
Codes: `0xF20001`..`0xF20002`
|
||||
|
||||
| Number | Name | Purpose | Argument |
|
||||
| ------ | ---- | ------- | -------- |
|
||||
| 0xF20001 | FZL_OPCODE_JMP | Jump to address `IP` | `IP` — target address |
|
||||
| 0xF20002 | FZL_OPCODE_JZ | Jump to address `IP` if the value at the top of the stack is zero | `IP` — target address |
|
||||
|
||||
## Function calls
|
||||
|
||||
Codes: `0xF30001`..`0xF30002`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xF30001 | FZL_OPCODE_CALL | Push the current address onto the call stack and jump to the start of a function |
|
||||
| 0xF30002 | FZL_OPCODE_RET | Pop the last address from the call stack and jump to it |
|
||||
|
||||
## Objects
|
||||
|
||||
Codes: `0xFA0001`..`0xFA0005`
|
||||
|
||||
| Number | Name | Purpose | Argument |
|
||||
| ------ | ---- | ------- | -------- |
|
||||
| 0xFA0001 | FZL_OPCODE_ALLOC_OBJECT | Allocate an object for `N` values and push it onto the stack | `N` — number of values |
|
||||
| 0xFA0002 | FZL_OPCODE_GET_FIELD | Pop an object reference from the stack and get field `N` | `N` — field index |
|
||||
| 0xFA0003 | FZL_OPCODE_SET_FIELD | Pop an object reference and a value, then write the value to field `N` | `N` — field index |
|
||||
| 0xFA0004 | FZL_OPCODE_ESCAPE_OBJECT | Move an object (including its children) to the parent environment | none |
|
||||
|
||||
## Arithmetic operations
|
||||
|
||||
Codes: `0xA00001`..`0xA00007`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xA00001 | FZL_OPCODE_ADD | Pop two numbers, add them, and push the result |
|
||||
| 0xA00002 | FZL_OPCODE_SUB | Pop two numbers, subtract the first from the second, and push the result |
|
||||
| 0xA00003 | FZL_OPCODE_MUL | Pop two numbers, multiply them, and push the result |
|
||||
| 0xA00004 | FZL_OPCODE_DIV | Pop two numbers, divide the first by the second, and push the result |
|
||||
| 0xA00005 | FZL_OPCODE_POW | Pop two numbers, raise the second to the power of the first, and push the result |
|
||||
| 0xA00006 | FZL_OPCODE_MOD | Pop two numbers and push the remainder of the second divided by the first |
|
||||
| 0xA00007 | FZL_OPCODE_NEG | Pop a number, negate it, and push it back onto the stack |
|
||||
|
||||
## Numeric comparisons
|
||||
|
||||
Codes: `0xB00001`..`0xB00006`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xB00001 | FZL_OPCODE_CMP_EQ | Pop two numbers, compare them for equality, and push the result |
|
||||
| 0xB00002 | FZL_OPCODE_CMP_NEQ | Pop two numbers, compare them for inequality, and push the result |
|
||||
| 0xB00003 | FZL_OPCODE_CMP_LT | Pop two numbers, check whether the second is less than the first, and push the result |
|
||||
| 0xB00004 | FZL_OPCODE_CMP_LTEQ | Pop two numbers, check whether the second is less than or equal to the first, and push the result |
|
||||
| 0xB00005 | FZL_OPCODE_CMP_GT | Pop two numbers, check whether the second is greater than the first, and push the result |
|
||||
| 0xB00006 | FZL_OPCODE_CMP_GTEQ | Pop two numbers, check whether the second is greater than or equal to the first, and push the result |
|
||||
|
||||
## String comparisons
|
||||
|
||||
Codes: `0xB10001`..`0xB10002`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xB10001 | FZL_OPCODE_CMP_EQ_STR | Pop two strings, compare them for equality, and push the result |
|
||||
| 0xB10002 | FZL_OPCODE_CMP_NEQ_STR | Pop two strings, compare them for inequality, and push the result |
|
||||
|
||||
## Object comparisons
|
||||
|
||||
Codes: `0xB20001`..`0xB20002`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xB20001 | FZL_OPCODE_CMP_EQ_OBJ | Pop two objects, compare them for equality, and push the result |
|
||||
| 0xB20002 | FZL_OPCODE_CMP_NEQ_OBJ | Pop two objects, compare them for inequality, and push the result |
|
||||
|
||||
## Binary logical operations
|
||||
|
||||
Codes: `0xC00001`..`0xC00002`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xC00001 | FZL_OPCODE_AND | Pop two values and push their logical AND |
|
||||
| 0xC00002 | FZL_OPCODE_OR | Pop two values and push their logical OR |
|
||||
|
||||
## Unary logical operations
|
||||
|
||||
Code: `0xD00001`
|
||||
|
||||
| Number | Name | Purpose |
|
||||
| ------ | ---- | ------- |
|
||||
| 0xD00001 | FZL_OPCODE_NOT | Pop a value and push its inverted boolean result |
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# Virtual machine stacks
|
||||
|
||||
While running, the FZLang virtual machine relies on three stacks: the data stack, the environment stack, and the call stack. Each stack is initialized as an array of 256 values and then zeroed. All three share the same basic property: the most recently added value is at the top and is the first one removed, decrementing the stack-top pointer.
|
||||
|
||||
## Data stack
|
||||
|
||||
The data stack is an array of 256 `fzl_value_t` elements. The `fzl_value_t` structure is a container for values used while a program runs.
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
fzl_type_t type;
|
||||
|
||||
union
|
||||
{
|
||||
void *obj;
|
||||
|
||||
struct
|
||||
{
|
||||
const char *value;
|
||||
size_t length;
|
||||
} s;
|
||||
|
||||
char c;
|
||||
bool b;
|
||||
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
|
||||
int64_t i64;
|
||||
uint64_t u64;
|
||||
|
||||
intptr_t i;
|
||||
uintptr_t u;
|
||||
} as;
|
||||
} fzl_value_t;
|
||||
```
|
||||
|
||||
The VM uses this stack to store and retrieve intermediate values while the program runs. The stack should be empty when execution finishes.
|
||||
|
||||
## Environment stack
|
||||
|
||||
The environment stack tracks the lexical environment in which evaluation and instructions are currently taking place. It is an array of 256 `fzl_vm_env_t` elements.
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
size_t remainder;
|
||||
|
||||
fzl_vm_env_entry_t *table;
|
||||
|
||||
fzl_vm_object_t **owned_objects;
|
||||
size_t owned_objects_remainder;
|
||||
size_t owned_objects_count;
|
||||
} fzl_vm_env_t;
|
||||
```
|
||||
|
||||
Each stack element stores a table of local names (`fzl_vm_env_entry_t`) and the objects owned by the current environment. A local name is a container that wraps an `fzl_value_t` and gives it a name:
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
fzl_value_t value;
|
||||
} fzl_vm_env_entry_t;
|
||||
```
|
||||
|
||||
An object is an array of its fields. The number of fields is set when the object is allocated by the `FZL_OPCODE_ALLOC_OBJECT N` opcode (see the [opcode reference](./opcodes.md) for details).
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
fzl_value_t *values;
|
||||
size_t values_count;
|
||||
} fzl_vm_object_t;
|
||||
```
|
||||
|
||||
An environment is created or removed by the `FZL_OPCODE_MK_ENVTABLE` and `FZL_OPCODE_RM_ENVTABLE` opcodes, respectively. If the compiler sees a value of type `FZL_TYPE_OBJECT` being returned from a function, it inserts `FZL_OPCODE_ESCAPE_OBJECT` before `FZL_OPCODE_RET` and `FZL_OPCODE_RM_ENVTABLE`. This moves ownership of the object to the parent environment.
|
||||
|
||||
## Call stack
|
||||
|
||||
The call stack stores instruction addresses when entering a function through the `FZL_OPCODE_CALL` opcode. `FZL_OPCODE_RET` pops an address from the call stack and jumps to it.
|
||||
|
||||
The stack itself is an array of 256 `size_t` elements.
|
||||
|
||||
Reference in New Issue
Block a user