Layer 2: Instructions
This chapter looks at the lowest level of the WIR, which implements a simply assembly-like instruction language for manipulating the stack that determines the graph control flow.
The edges of the graph themselves are defined in the previous chapter, and the chapter before that talks about the toplevel of the WIR representation tying the edges together.
We use the same conventions as in the previous chapters. We recommend you read them before continuing to understand what we wrote down.
EdgeInstrs
A Linear
-edge may be annotated with zero or more EdgeInstr
uctions, which are assembly-like instructions that manipulate a workflow-wide stack. Some Edge
s manipulate the stack too, most often reading from it, but most work is done by explicitly stating the instructions.
As discussed in the introduction chapter
, the instructions essentially implement a second layer of computation. Where the edges mostly related to "on-graph" computation, the edge instructions can be thought of as "off-graph" computation that typically matters less for reasoners.
As far as the specification goes, the the following fields are shared by all instructions:
kind
(string): Denotes which variant of theEdgeInstr
this object describes. The identifiers used are given below in each subsections.
A convenient index of all instructions:
Cast
: Casts a value to another type.Pop
: Discards the top value on the stack.PopMarker
: Pushes an invisible value that is used by...DynamicPop
: Pops values off the stack until the invisible value pushed byPopMarker
is popped.Branch
: Conditionally jumps to another instruction within the same stream.BranchNot
: Conditionally jumps to another instruction within the same stream but negated.Not
: Performs logical negation.Neg
: Performs arithmetic negation.And
: Performs logical conjunction.Or
: Performs logical disjunction.Add
: Performs arithmetic addition / string concatenation.Sub
: Performs arithmetic subtraction.Mul
: Performs arithmetic multiplication.Div
: Performs arithmetic division.Mod
: Performs arithmetic modulo.Eq
: Compares two values.Ne
: Compares two values but negated.Lt
: Compares two numerical values in a less-than fashion.Le
: Compares two numerical values in a less-than-or-equal-to fashion.Gt
: Compares two numerical values in a greater-than fashion.Ge
: Compares two numerical values in a greater-than-or-equal-to fashion.Array
: Pushes an array literal onto the stack (or rather, creates one out of existing values).ArrayIndex
: Takes an array and an index and pushes the element of the array at that index.Instance
: Pushes a new instance of a class onto the stack by popping existing values.Proj
: Projects a field on an instance to get that field's value.VarDec
: Declares the existance of a variable.VarUndec
: Releases the resources of a variable.VarGet
: Gets the value of a variable.VarSet
: Sets the value of a variable.Boolean
: Pushes a boolean constant.Integer
: Pushes a integer constant.Real
: Pushes a floating-point constant.String
: Pushes a string constant.Function
: Pushes a function handle on top of the stack.
Cast
Identifier: "cst"
The Cast
takes the top value off the stack and attempts to perform a type conversion on it. Then, the result is pushed back on top of the stack.
Specification-wise, the Cast
needs one additional field:
t
(DataType
): Defines the datatype the top value on the stack to.
Stack-wise, the Cast
manipulates the stack in the following way:
- pops
DataType::Any
from the stack; and - pushes An object of type
t
on top of the stack representing the same value but as another type.
Note that this conversion may fail, since not all types can be converted into other types. Specifically, the following convertions are defined, where T
and U
represent arbitrary types and Ts
and Us
represents lists of arbitrary, possibly heterogenously typed values:
bool
toint
creates a 1 if the input value is true or a 0 otherwise.bool
tostr
creates a "true" if the input value is true, or a "false" if the input value is false.int
tobool
creates true if the input value is non-zero, or false otherwise.int
toreal
creates an equivalent floating-point number.int
tostr
writes the integer as a serialized number.real
toint
writes the floating-point value rounded down to the nearest integer.real
tostr
writes the floating-point number as a serialized number.arr<T>
tostr
casts the elements in the array fromT
tostr
and then serializes them within square brackets ([]
), separated by comma's (,
) (e.g.,"[ 42, 43, 44 ]"
).arr<T>
toarr<U>
casts every element in the array fromT
toU
.func(Ts) -> T
tofunc(Us) -> U
is a no-op but only ifTs == Us
andT == U
.func(Ts) -> T
tostr
casts the values inTs
tostr
andT
tostr
and then writes the name of the function followed by the arguments in parenthesis (()
) followed by->
and the return type (e.g.,"foo(int, real) -> str"
). If the function is a class method, then the class name and::
are prefixed to the function name (e.g.,Foo::foo(Foo, int, real) -> str
).func(Ts) -> T
toclss
is a no-op, even keeping the same type, but only if the function is a method and belongs to the class it is casted to. This can be used to assert that a method is part of a class(?).clss<Ts>
tostr
casts the values inTs
tostr
and then serializes it as the class name followed by the values in the class serialized as name:=
value separated by comma's in between curly brackets ({}
) (e.g.,Foo { foo := 42, bar := "test" }
).Data
tostr
writesData
, and then the name of the data in triangular brackets (<>
) (e.g.,"Data<Foo>"
).Data
toIntermediateResult
is a no-op.IntermediateResult
tostr
writesIntermediateResult
, and then the name of the data in triangular brackets (<>
) (e.g.,"IntermediateResult<Foo>"
).T
toT
performs a no-op.T
toAny
performs a no-op and just changes the type.
Any convertion not mentioned here is defined to be illegal.
As such, the Cast
can throw the following errors:
Empty stack
when popping;Stack overflow
when pushing; orIllegal cast
when the value cannot be casted to typet
.
The following is an example Cast
-instruction:
{
"kind": "cst",
"t": "str"
}
Pop
Identifier: "pop"
Pops the top value off the stack and discards it.
This instruction does not require any additional fields.
Stack-wise, the Pop
does the following:
- pops
DataType::Any
from the stack.
It may throw the following error:
Empty stack
when popping.
An example:
{
"kind": "pop"
}
PopMarker
Identifier: "mpp"
Pushes a so-called pop marker onto the stack, which can then be popped using the DynamicPop
-instruction. This combination can be used when popping an unknown number of values off the stack.
This instruction does not require any additional fields.
Stack-wise, the PopMarker
does the following:
- pushes a special value onto the stack that is invisible to most operations except
DynamicPop
.
It may throw the following error:
Stack overflow
when pushing.
An example:
{
"kind": "mpp"
}
DynamicPop
Identifier: "dpp"
Dynamically pops the stack until a PopMarker
is popped. This combination can be used when popping an unknown number of values off the stack.
This instruction does not require any additional fields.
Stack-wise, the PopMarker
does the following:
- pops a dynamic amount of values off the stack until
PopMarker
's special value is popped.
Doing so may make it throw the following error:
Empty stack
when popping.
An example:
{
"kind": "dpp"
}
Branch
Identifier: "brc"
Not to be confused with the Branch
-edge, this instruction implements a branch in the instruction stream only. This is only allowed when it's possible to do this within the same linear edge, implying the branch does not influence directly which nodes are executed.
The branch is taken when the top value on the stack is true; otherwise, it is ignored and implements a no-op.
The Branch
defines the following fields:
n
(number): The relative offset to jump to. This can be thought of as "number of instructions to skip", where a value of -1 points to the previous instruction, 0 points to theBranch
-instruction itself and 1 points to the next instruction.
Stack-wise, the Branch
does the following:
- pops
DataType::Boolean
from the stack.
As such, it can throw the following errors:
Empty stack
when popping; orType error
when the popped value is not abool
.
Note that skipping outside of the sequence of instructions belonging to a Linear
-edge means the VM simply stops executing.
An example Branch
-instruction:
{
"kind": "brc",
"n": 5
}
BranchNot
Identifier: "brn"
Counterpart to the Branch
-instruction that behaves the same except that it branches when the value on the stack is false instead of true.
The BranchNot
defines the following fields:
n
(number): The relative offset to jump to. This can be thought of as "number of instructions to skip", where a value of -1 points to the previous instruction, 0 points to theBranchNot
-instruction itself and 1 points to the next instruction.
Stack-wise, the Branch
does the following:
- pops
DataType::Boolean
from the stack.
As such, it can throw the following errors:
Empty stack
when popping; orType error
when the popped value is not abool
.
Note that skipping outside of the sequence of instructions belonging to a Linear
-edge means the VM simply stops executing.
An example Branch
-instruction:
{
"kind": "brn",
"n": 5
}
Not
Identifier: "not"
Implements a logical negation on the top value on the stack.
The Not
does not need additional fields to do this.
Stack-wise, the Not
does the following:
- pops
DataType::Boolean
from the stack; and - pushes
DataType::Boolean
on top of the stack.
As such, it can throw the following errors:
Empty stack
when popping;Type error
when the popped value is not abool
; orStack overflow
when pushing.
Example:
{
"kind": "not"
}
Neg
Identifier: "neg"
Implements a arithmetic negation on the top value on the stack.
The Neg
does not need additional fields to do this.
Stack-wise, the Neg
does the following:
- pops
DataType::Numeric
from the stack; and - pushes
DataType::Numeric
on top of the stack.
As such, it can throw the following errors:
Empty stack
when popping;Type error
when the popped value is not anint
orreal
; orStack overflow
when pushing.
Example:
{
"kind": "neg"
}
And
Identifier: "and"
Performs logical conjunction on the top two values on the stack.
No additional fields are needed to do this.
Stack-wise, the And
does the following:
- pops
DataType::Boolean
for the righthand-side; - pops
DataType::Boolean
for the lefthand-side; and - pushes
DataType::Boolean
that is the conjunction of the LHS and RHS.
The following errors can occur during this process:
Empty stack
when popping;Type error
when the popped values are not abool
; orStack overflow
when pushing.
Example:
{
"kind": "and"
}
Or
Identifier: "or"
Performs logical disjunction on the top two values on the stack.
No additional fields are needed to do this.
Stack-wise, the Or
does the following:
- pops
DataType::Boolean
for the righthand-side; - pops
DataType::Boolean
for the lefthand-side; and - pushes
DataType::Boolean
that is the disjunction of the LHS and RHS.
The following errors can occur during this process:
Empty stack
when popping;Type error
when the popped values are not abool
; orStack overflow
when pushing.
Example:
{
"kind": "or"
}
Add
Identifier: "add"
Performs arithmetic addition or string concatenation on the top two values on the stack. Which of the two depends on the types of the popped values.
The Add
does not introduce additional fields.
Stack-wise, the Add
does the following:
- pops
DataType::Integer
,DataType::Real
orDataType::String
for the righthand-side; - pops
DataType::Integer
,DataType::Real
orDataType::String
for the lefthand-side; and - pushes
DataType::Integer
,DataType::Real
orDataType::String
depending on the input types:- If both arguments are
DataType::Integer
, then a new integer is pushed that is the arithmetic addition of the LHS and RHS; - If both arguments are
DataType::Real
, then a new real is pushed that is the arithmetic addition of both the LHS and RHS; and - If both arguments are
DataType::String
, then a new string is pushed that is the concatenation of the LHS and then the RHS.
- If both arguments are
The following errors may occur when processing an Add
:
Empty stack
when popping;Type error
when the popped values do not match any of the three cases above;Overflow error
when the addition results in integer/real addition; orStack overflow
when pushing.
Example:
{
"kind": "add"
}
Sub
Identifier: "sub"
Performs arithmetic subtraction on the top two values on the stack.
The Sub
does not introduce additional fields.
Stack-wise, the Sub
does the following:
- pops
DataType::Integer
orDataType::Real
for the righthand-side; - pops
DataType::Integer
orDataType::Real
for the lefthand-side; and - pushes
DataType::Integer
orDataType::Real
depending on the input types:- If both arguments are
DataType::Integer
, then a new integer is pushed that is the arithmetic subtraction of the LHS and RHS; and - If both arguments are
DataType::Real
, then a new real is pushed that is the arithmetic subtraction of both the LHS and RHS.
- If both arguments are
The following errors may occur when processing an Add
:
Empty stack
when popping;Type error
when the popped values do not match any of the two cases above;Overflow error
when the subtraction results in integer/real underflow; orStack overflow
when pushing.
Example:
{
"kind": "sub"
}
Mul
Identifier: "mul"
Performs arithmetic multiplication on the top two values on the stack.
The Mul
does not introduce additional fields.
Stack-wise, the Mul
does the following:
- pops
DataType::Integer
orDataType::Real
for the righthand-side; - pops
DataType::Integer
orDataType::Real
for the lefthand-side; and - pushes
DataType::Integer
orDataType::Real
depending on the input types:- If both arguments are
DataType::Integer
, then a new integer is pushed that is the arithmetic multiplication of the LHS and RHS; and - If both arguments are
DataType::Real
, then a new real is pushed that is the arithmetic multiplication of both the LHS and RHS.
- If both arguments are
The following errors may occur when processing an Add
:
Empty stack
when popping;Type error
when the popped values do not match any of the two cases above;Overflow error
when the multiplication results in integer/real overflow; orStack overflow
when pushing.
Example:
{
"kind": "mul"
}
Div
Identifier: "div"
Performs arithmetic division on the top two values on the stack.
The Div
does not introduce additional fields.
Stack-wise, the Div
does the following:
- pops
DataType::Integer
orDataType::Real
for the righthand-side; - pops
DataType::Integer
orDataType::Real
for the lefthand-side; and - pushes
DataType::Integer
orDataType::Real
depending on the input types:- If both arguments are
DataType::Integer
, then a new integer is pushed that is the integer division of the LHS and RHS (i.e., rounded down to the nearest integer); and - If both arguments are
DataType::Real
, then a new real is pushed that is the floating-point division of both the LHS and RHS.
- If both arguments are
The following errors may occur when processing an Add
:
Empty stack
when popping;Type error
when the popped values do not match any of the two cases above;Overflow error
when the division results in real underflow; orStack overflow
when pushing.
Example:
{
"kind": "div"
}
Mod
Identifier: "mod"
Computes the remainder of dividing one value on top of the stack with another.
The Mod
does not introduce additional fields to do so.
Stack-wise, the Mod
does the following:
- pops
DataType::Integer
for the righthand-side; - pops
DataType::Integer
for the lefthand-side; and - pushes
DataType::Integer
that is the remainder of dividing the LHS by the RHS.
The following errors may occur when processing a Mod
:
Empty stack
when popping;Type error
when the popped values are notint
s; orStack overflow
when pushing.
Example:
{
"kind": "mod"
}
Eq
Identifier: "eq"
Compares the top two values on the stack for equality. This is first type-wise (their types must be equal), and then value-wise.
No additional fields are introduced to do so.
Stack-wise, the Eq
does the following:
- pops
DataType::Any
for the righthand-side; - pops
DataType::Any
for the lefthand-side; and - pushes
DataType::Boolean
with true if the LHS equals the RHS, or false otherwise.
The following errors may occur when processing an Eq
:
Empty stack
when popping; orStack overflow
when pushing.
Example:
{
"kind": "eq"
}
Ne
Identifier: "ne"
Compares the top two values on the stack for inequality. This is first type-wise (their types must be unequal), and then value-wise.
No additional fields are introduced to do so.
Stack-wise, the Ne
does the following:
- pops
DataType::Any
for the righthand-side; - pops
DataType::Any
for the lefthand-side; and - pushes
DataType::Boolean
with true if the LHS does not equal the RHS, or false otherwise.
The following errors may occur when processing an Eq
:
Empty stack
when popping; orStack overflow
when pushing.
Example:
{
"kind": "ne"
}
Lt
Identifier: "lt"
Compares the top two values on the stack for order, specifically less-than. This can only be done for numerical values.
No additional fields are introduced to do so.
Stack-wise, the Lt
does the following:
- pops
DataType::Numeric
for the righthand-side; - pops
DataType::Numeric
for the lefthand-side; and - pushes
DataType::Boolean
with true if the LHS is stricly less than the RHS, or false otherwise.
The following errors may occur when processing an Lt
:
Empty stack
when popping;Type error
when either argument is not anum
or they are not of the same type (i.e., cannot compareint
withreal
); orStack overflow
when pushing.
Example:
{
"kind": "lt"
}
Le
Identifier: "le"
Compares the top two values on the stack for order, specifically less-than-or-equal-to. This can only be done for numerical values.
No additional fields are introduced to do so.
Stack-wise, the Le
does the following:
- pops
DataType::Numeric
for the righthand-side; - pops
DataType::Numeric
for the lefthand-side; and - pushes
DataType::Boolean
with true if the LHS is less than or equal to the RHS, or false otherwise.
The following errors may occur when processing an Le
:
Empty stack
when popping;Type error
when either argument is not anum
or they are not of the same type (i.e., cannot compareint
withreal
); orStack overflow
when pushing.
Example:
{
"kind": "le"
}
Gt
Identifier: "gt"
Compares the top two values on the stack for order, specifically greater-than. This can only be done for numerical values.
No additional fields are introduced to do so.
Stack-wise, the Gt
does the following:
- pops
DataType::Numeric
for the righthand-side; - pops
DataType::Numeric
for the lefthand-side; and - pushes
DataType::Boolean
with true if the LHS is strictly greater than to the RHS, or false otherwise.
The following errors may occur when processing an Gt
:
Empty stack
when popping;Type error
when either argument is not anum
or they are not of the same type (i.e., cannot compareint
withreal
); orStack overflow
when pushing.
Example:
{
"kind": "gt"
}
Ge
Identifier: "ge"
Compares the top two values on the stack for order, specifically greater-than-or-equal-to. This can only be done for numerical values.
No additional fields are introduced to do so.
Stack-wise, the Ge
does the following:
- pops
DataType::Numeric
for the righthand-side; - pops
DataType::Numeric
for the lefthand-side; and - pushes
DataType::Boolean
with true if the LHS is greater than or equal to the RHS, or false otherwise.
The following errors may occur when processing an Ge
:
Empty stack
when popping;Type error
when either argument is not anum
or they are not of the same type (i.e., cannot compareint
withreal
); orStack overflow
when pushing.
Example:
{
"kind": "ge"
}
Array
Identifier: "arr"
Consumes a number of values from the top off the stack and creates a new Array with them.
The Array
specifies the following additional fields:
l
(number): The number of elements to pop, i.e., the length of the array.t
(DataType
): The data type of the array. Note that this includes thearr
datatype and its element type.
Stack-wise, the Array
does the following:
- pops
l
values of typet
; and - pushes
DataType::Array
withl
elements of typet
. Note that the order of elements is reversed (i.e., the first element popped is the last element of the array).
Doing so may trigger the following errors:
Empty stack
when popping;Type error
when a popped value does not have typet
; orStack overflow
when pushing.
Example:
// Represents an array literal of length 5, element type `str`
{
"kind": "arr",
"l": 5,
"t": { "kind": "arr", "t": { "kind": "str" } }
}
ArrayIndex
Identifier: "arx"
Indexes an array value on top of the stack with some index and outputs the element at that index.
The ArrayIndex
specifies the following additional fields:
t
(DataType
): The data type of the element. This is the type of the pushed value.
Stack-wise, the ArrayIndex
does the following:
- pops
DataType::Integer
for the index; - pops
DataType::Array
for the array to index, which must have element typet
; and - pushes a value of type
t
that is the element at the specified index.
Doing so may trigger the following errors:
Empty stack
when popping;Type error
when any of the popped values are incorrectly typed;Array out-of-bounds
when the index is too large for the given array, or if it's negative; orStack overflow
when pushing.
Example:
/// Indexes an array of string elements
{
"kind": "arx",
"t": { "kind": "str" }
}
Instance
Identifier: "ins"
Consumes a number of values on top of the stack in order to construct a new instance of a class.
To do so, the Instance
defines additional fields:
d
(number): Identifier of the type which we are constructing. This definition is given in the parent symbol table.
Stack-wise, the Instance
does the following:
- pops
N
values of varying types from the top off the stack, whereN
is the number of fields (which may be 0) and the types are those matching to the fields. Note that they are popped in reverse alphabetical order, e.g., fielda
is below fieldz
on the stack; and - pushes a value of the type referred to by
d
.
Doing so may trigger the following errors:
Unknown definition
ifd
is not known in the symbol tables;Empty stack
when popping;Type error
when any of the popped values are incorrectly typed; orStack overflow
when pushing.
Example:
{
"kind": "ins",
"d": 42
}
Proj
Identifier: "prj"
The Proj
instruction takes an instance and retrieves the value of the given field from it.
The field is embedded in the instruction. As such, it adds the following specification fields:
f
(string): The name of the field to project.
Stack-wise, the Proj
does the following:
- pops an instance value; and
- pushes the value of field
f
in that instance.
The projection ducktypes the instance, and as such can trigger the following errors:
Empty stack
when popping;Unknown field
when the popped instance has no field by the name described inf
; orStack overflow
when pushing.
Example:
{
"kind": "prj",
"f": "foo"
}
VarDec
Identifier: "vrd"
Declares a new variable, giving an opportunity to the underlying execution context to reserve space for it.
The following fields are added by a VarDec
:
d
(number): The identifier of the variable definition in the parent symbol table of the variable we're declaring. Note that, because definitions are scoped to functions, this is a unique identifier for specific variable instances the current scope.
Stack-wise, the VarDec
doesn't do anything, as it fully acts on the underlying variable system.
The following errors may occur when working with the VarDec
:
Unknown definition
ifd
is not known in the symbol tables; orVariable error
if the underlying context finds another reason to crash.
Example:
{
"kind": "vrd",
"d": 42
}
VarUndec
Identifier: "vru"
Explicitly undeclares a new variable, giving an opportunity to the underlying execution context to claim back space for it.
The following fields are added by a VarUndec
:
d
(number): The identifier of the variable definition in the parent symbol table of the variable we're undeclaring.Note that, because definitions are scoped to functions, this is a unique identifier for specific variable instances the current scope.
Stack-wise, the VarUndec
doesn't do anything, as it fully acts on the underlying variable system.
The following errors may occur when working with the VarUndec
:
Unknown definition
ifd
is not known in the symbol tables; orVariable error
if the underlying context finds another reason to crash.
Example:
{
"kind": "vru",
"d": 42
}
VarGet
Identifier: "vrg"
Retrieves the value of a variable which was previously VarSet
.
The following fields are added by a VarGet
:
d
(number): The identifier of the variable definition in the parent symbol table of the variable we're undeclaring.Note that, because definitions are scoped to functions, this is a unique identifier for specific variable instances the current scope.
Stack-wise, the VarGet
does the following:
- pushes the value stored in the variable on top of the stack.
The following errors may occur when working with the VarGet
:
Unknown definition
ifd
is not known in the symbol tables;Variable error
if the underlying context finds another reason to crash; orStack overflow
when pushing.
Example:
{
"kind": "vrs",
"d": 42
}
VarSet
Identifier: "vrs"
Moves the value on top of the stack to a variable so it may be VarGet
.
The following fields are added by a VarSet
:
d
(number): The identifier of the variable definition in the parent symbol table of the variable we're undeclaring.Note that, because definitions are scoped to functions, this is a unique identifier for specific variable instances the current scope.
Stack-wise the VarSet
does the following:
- pops
DataType::Any
from the stack to put in the variable.
The following errors may occur when working with the VarGet
:
Unknown definition
ifd
is not known in the symbol tables;Variable error
if the underlying context finds another reason to crash;Empty stack
when popping; orType error
when the type of the popped value does not match the type of the variable.
Example:
{
"kind": "vrs",
"d": 42
}
Boolean
Identifier: "bol"
Pushes a boolean constant on top of the stack.
The following fields are added by a Boolean
:
v
(bool): The boolean value to push.
Stack-wise, the Boolean
does the following:
- pushes
DataType::Boolean
on top of the stack.
The following errors may occur when executing a Boolean
:
Stack overflow
when pushing.
Example:
{
"kind": "bol",
"v": true
}
Integer
Identifier: "int"
Pushes an integer constant on top of the stack.
The following fields are added by a Integer
:
v
(number): The integer value to push.
Stack-wise, the Integer
does the following:
- pushes
DataType::Integer
on top of the stack.
The following errors may occur when executing a Integer
:
Stack overflow
when pushing.
Example:
{
"kind": "int",
"v": -84
}
Real
Identifier: "rel"
Pushes a floating-point constant on top of the stack.
The following fields are added by a Real
:
v
(number): The floating-point value to push.
Stack-wise, the Real
does the following:
- pushes
DataType::Real
on top of the stack.
The following errors may occur when executing a Real
:
Stack overflow
when pushing.
Example:
{
"kind": "rel",
"v": 0.42
}
String
Identifier: "str"
Pushes a string constant on top of the stack.
The following fields are added by a String
:
v
(string): The string value to push.
Stack-wise, the String
does the following:
- pushes
DataType::String
on top of the stack.
The following errors may occur when executing a String
:
Stack overflow
when pushing.
Example:
{
"kind": "str",
"v": "Hello, world!"
}
Function
Identifier: "fnc"
Pushes a function handle on top of the stack so it may be called.
The following fields are added by a Function
:
d
(number): The ID of the function definition which to push on top of the stack.
Stack-wise, the Function
does the following:
- pushes
DataType::Function
on top of the stack.
The following errors may occur when executing a Function
:
Unknown definition
ifd
is not known in the symbol tables; orStack overflow
when pushing.
Example:
{
"kind": "fnc",
"v": 42
}
Next
This chapter concludes the specification of the WIR.
If you are intending to discover the WIR bottom-up, continue to the previous chapter to see how the graph overlaying the instructions is represented.
Otherwise, you can learn other aspects of the framework or the specification by selecting a different topic in the sidebar on the left.