Files

3.4 KiB

Error output

When a runtime error occurs, the VM prints its state at the time it stopped. The output includes:

  1. The instruction pointer;
  2. The data stack;
  3. The environment stack;
  4. The call stack.

Instruction pointer (IP)

The instruction pointer is useful for debugging alongside the program's opcode listing. Run the VM with the --debug (-d) flag and the path to a compiled program to print its opcodes without running it.

The output looks roughly like this:

0000: MK_ENVTABLE
0001: JMP IP: 53
0003: MK_ENVTABLE
0004: LOADCONST #0 ('a')
0006: STORE
0007: LOADCONST #0 ('a')
0009: WRITE
0010: MK_ENVTABLE
0011: LOADCONST #0 ('a')
0013: LOOKUP_ENV
0014: GET_FIELD #0
...

The instruction index helps you find the instruction where the exception occurred. See the opcode reference for the complete list and descriptions.

Data stack

The data stack is printed as a list of values in the form [T] V, where T is the type number and V is the value. Strings and objects are prefixed with str: V and ref: V, respectively.

Example:

> Data stack:
        > [2] str: 'this'

Values are printed from top to bottom, so the most recent values appear first.

Environment stack

The environment stack is printed as two lists: objects owned by the environment and names local to it.

Example environment:

> Environments:
        > [1] 0x55a9d8196a20:
                > Owned objects (0/2):
                > Local entries (3/4):
                        > [14] b = 4
                        > [1] a = ref 0x55a9d81969e0
                        > [0] this = 0
        > [0] 0x55a9d8196930:
                > Owned objects (1/2):
                        > ref: 0x55a9d81969e0 (entries: 1)
                > Local entries (1/2):
                        > [1] sum = ref 0x55a9d81969e0

> [N] A identifies the environment table itself. N is the table's nesting level (larger values mean a deeper environment), and A is its memory address.

The first list is Owned objects; it shows the number of elements and the allocated array size as (<count>/<capacity>). Objects are listed as ref: A (entries: N), where A is the object's memory address and N is the number of fields it contains.

The second list is Local entries, with the number of entries and allocated capacity. Each entry has the form [T] N = V, where T is the type number, N is the entry name, and V is its value.

Call stack

The call stack contains return addresses. An address is pushed when the CALL opcode runs and popped by RET.

> Call stack:
        > [0] 53

Each entry has the form [L] IP, where L is the nesting level (larger means deeper) and IP is the instruction index to jump to after returning.

Complete output

A complete error report looks like this:

===== ERROR =====
> Caused on IP: 21

> Data stack:
        > [2] str: 'this'

> Environments:
        > [1] 0x55a9d8196a20:
                > Owned objects (0/2):
                > Local entries (3/4):
                        > [14] b = 4
                        > [1] a = ref 0x55a9d81969e0
                        > [0] this = 0
        > [0] 0x55a9d8196930:
                > Owned objects (1/2):
                        > ref: 0x55a9d81969e0 (entries: 1)
                > Local entries (1/2):
                        > [1] sum = ref 0x55a9d81969e0

> Call stack:
        > [0] 53
Error: runtime error - expected 2 values in data stack