Documentation ¶
Overview ¶
Package il implements the intermediate-language for the config-language interpreter of Mixer. The IL is designed as a 32-bit instruction set. The opcode/argument size of the IL is 32-bits and both are modeled as uint32s. Different instructions can have different number of arguments, but a given instruction will always have a well-defined number of arguments. Each argument can be 1 or 2 uint32s, depending on type.
The IL intrinsically supports the following basic primitive types:
- String: represents a string value and maps to the native string Go type. Internally, the strings are interned in a StringTable, thus allowing extremely fast equality comparisons. The id of the string in the StringTable is encoded in the ByteCode, when stored, or during execution.
- Bool: represents a boolean value and maps to the native bool Go type. The boolean values of false and true are represented as uint32(0) and uint32(1), respectively. The VM will consider any non-zero value as true, if it encounters during execution.
- Integer: represents a signed integer value and maps to the native int64 Go type. The integer is stored in 2 uint32s internally.
- Double: represents a signed float value and maps to the native float64 Go type. The double is stored in 2 uint32s internally.
- Record represents a mapping of string-> string and maps to the map[string]string Go Type.
There is no constant representation of Record in il form.
- Void represents no-value. This is typically used in the return type of a function, to indicate
that the function does not return a result.
In addition to these types, the VM inherently supports errors, based on Go errors. It is possible to raise these errors from within the IL. However, it is not possible to trap or return these as values. Once an error is raised, whether as a program instruction, or due to an invalid evaluation step, it bubbles all the way out of the evaluation context.
The execution model is based on an operand stack and registers. Though most operations work on an operand stack to perform calculations, it is possible to transfer data from registers to stack and vice-versa.
The IL supports a stack-based calling-convention. All the parameters to a function need to be pushed onto the stack before the CALL instruction is invoked. Similarly, the return values need to be pushed onto the stack when RET is called.
Typically, an IL based program is created by a compiler by initializing a Program type and by adding Functions to it, whose bodies are built using the Builder type. Once built, programs can be serialized/deserialized into a textual form for ease of use, using Write* and Read* method in this package.
Index ¶
- func BoolToByteCode(b bool) uint32
- func ByteCodeToBool(o uint32) bool
- func ByteCodeToDouble(o1, o2 uint32) float64
- func ByteCodeToInteger(o1, o2 uint32) int64
- func DoubleToByteCode(d float64) (uint32, uint32)
- func IntegerToByteCode(i int64) (uint32, uint32)
- func MapGet(tVal interface{}, tStr string) (ret string, found bool)
- type Builder
- func (f *Builder) AEQBool(v bool)
- func (f *Builder) AEQDouble(v float64)
- func (f *Builder) AEQInteger(v int64)
- func (f *Builder) AEQString(v string)
- func (f *Builder) ALookup(v string)
- func (f *Builder) ANLookup(v string)
- func (f *Builder) APushBool(b bool)
- func (f *Builder) APushDouble(n float64)
- func (f *Builder) APushInt(i int64)
- func (f *Builder) APushStr(s string)
- func (f *Builder) AllocateLabel() string
- func (f *Builder) And()
- func (f *Builder) Build() []uint32
- func (f *Builder) Call(fnName string)
- func (f *Builder) EQBool()
- func (f *Builder) EQDouble()
- func (f *Builder) EQInteger()
- func (f *Builder) EQString()
- func (f *Builder) Jmp(label string)
- func (f *Builder) Jnz(label string)
- func (f *Builder) Jz(label string)
- func (f *Builder) Lookup()
- func (f *Builder) NLookup()
- func (f *Builder) Nop()
- func (f *Builder) Not()
- func (f *Builder) Or()
- func (f *Builder) ResolveBool(n string)
- func (f *Builder) ResolveDouble(n string)
- func (f *Builder) ResolveInt(n string)
- func (f *Builder) ResolveInterface(n string)
- func (f *Builder) ResolveString(n string)
- func (f *Builder) Ret()
- func (f *Builder) SetLabelPos(label string)
- func (f *Builder) TLookup()
- func (f *Builder) TResolveBool(n string)
- func (f *Builder) TResolveDouble(n string)
- func (f *Builder) TResolveInt(n string)
- func (f *Builder) TResolveInterface(n string)
- func (f *Builder) TResolveString(n string)
- func (f *Builder) Xor()
- type Function
- type FunctionTable
- type Opcode
- type OpcodeArg
- type Program
- type StringMap
- type StringTable
- type Type
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BoolToByteCode ¶
BoolToByteCode converts a Go bool to its byte-code form.
func ByteCodeToBool ¶
ByteCodeToBool extracts a Go bool from its byte-code form.
func ByteCodeToDouble ¶
ByteCodeToDouble extracts a Go float64 from its byte-code form.
func ByteCodeToInteger ¶
ByteCodeToInteger extracts a Go int64 from its byte-code form.
func DoubleToByteCode ¶
DoubleToByteCode converts a Go float64 to its byte-code form.
func IntegerToByteCode ¶
IntegerToByteCode converts a Go int64 to its byte-code form.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder is used for building function bodies in a programmatic way.
func NewBuilder ¶
func NewBuilder(s *StringTable) *Builder
NewBuilder creates a new Builder instance. It uses the given StringTable when it needs to allocate ids for strings.
func (*Builder) AEQInteger ¶
AEQInteger appends the "eq_i" instruction to the byte code.
func (*Builder) APushDouble ¶
APushDouble appends the "apush_d" instruction to the byte code.
func (*Builder) AllocateLabel ¶
AllocateLabel allocates a new label value for use within the code.
func (*Builder) Build ¶
Build completes building a function body and returns the accumulated byte code.
func (*Builder) EQBool ¶
func (f *Builder) EQBool()
EQBool appends the "eq_b" instruction to the byte code.
func (*Builder) EQDouble ¶
func (f *Builder) EQDouble()
EQDouble appends the "eq_d" instruction to the byte code.
func (*Builder) EQInteger ¶
func (f *Builder) EQInteger()
EQInteger appends the "eq_i" instruction to the byte code.
func (*Builder) EQString ¶
func (f *Builder) EQString()
EQString appends the "eq_s" instruction to the byte code.
func (*Builder) Lookup ¶
func (f *Builder) Lookup()
Lookup appends the "lookup" instruction to the byte code.
func (*Builder) NLookup ¶
func (f *Builder) NLookup()
NLookup appends the "nlookup" instruction to the byte code.
func (*Builder) ResolveBool ¶
ResolveBool appends the "resolve_b" instruction to the byte code.
func (*Builder) ResolveDouble ¶
ResolveDouble appends the "resolve_d" instruction to the byte code.
func (*Builder) ResolveInt ¶
ResolveInt appends the "resolve_i" instruction to the byte code.
func (*Builder) ResolveInterface ¶
ResolveInterface appends the "resolve_f" instruction to the byte code.
func (*Builder) ResolveString ¶
ResolveString appends the "resolve_s" instruction to the byte code.
func (*Builder) SetLabelPos ¶
SetLabelPos puts the label position at the current bytecode point that builder is pointing at. Panics if the label position was already set.
func (*Builder) TLookup ¶
func (f *Builder) TLookup()
TLookup appends the "tlookup" instruction to the byte code.
func (*Builder) TResolveBool ¶
TResolveBool appends the "tresolve_b" instruction to the byte code.
func (*Builder) TResolveDouble ¶
TResolveDouble appends the "tresolve_d" instruction to the byte code.
func (*Builder) TResolveInt ¶
TResolveInt appends the "tresolve_i" instruction to the byte code.
func (*Builder) TResolveInterface ¶
TResolveInterface appends the "tresolve_f" instruction to the byte code.
func (*Builder) TResolveString ¶
TResolveString appends the "tresolve_s" instruction to the byte code.
type Function ¶
type Function struct { // Parameters is the type of the input parameters to the function. Parameters []Type // ReturnType is the return type of the function. ReturnType Type // ID is the id of the function. It is also the id of the name of the function in the strings table. ID uint32 // Address is the address of the first opcode for the function within the bytecode. Address uint32 // Length is the length of the function, in uint32s, within the bytecode. Length uint32 }
Function contains metadata about an IL-based function that is implemented in a program.
type FunctionTable ¶
type FunctionTable struct {
// contains filtered or unexported fields
}
FunctionTable contains a set of functions, organized by their ids.
func (*FunctionTable) Get ¶
func (t *FunctionTable) Get(name string) *Function
Get returns the function with the given name if it exists, or nil if not found.
func (*FunctionTable) GetByID ¶
func (t *FunctionTable) GetByID(id uint32) *Function
GetByID returns the function with the given id, or nil if not found.
func (*FunctionTable) IDOf ¶
func (t *FunctionTable) IDOf(name string) uint32
IDOf returns the id of a function with the given name, if it exists. Otherwise it returns 0.
func (*FunctionTable) Names ¶
func (t *FunctionTable) Names() []string
Names returns the names of all the functions in the table.
type Opcode ¶
type Opcode uint32
Opcode is the type for the opcodes in the il.
const ( // Halt stops the VM with an error. Halt Opcode = 0 // Nop does nothing. Nop Opcode = 1 // Err raises an error. Err Opcode = 2 // Errz pops a boolean value from stack and check its value. if the value is false, then it // raises an error. Errz Opcode = 3 // Errnz pops a boolean value from stack and check its value. if the value is true, then it // raises an error. Errnz Opcode = 4 // PopS pops a string from the stack. PopS Opcode = 10 // PopB pops a bool from the stack. PopB Opcode = 11 // PopI pops an integer from the stack. PopI Opcode = 12 // PopD pops a double from the stack. PopD Opcode = 13 // DupS pops a string value from the stack and pushes it back into the stack twice. DupS Opcode = 14 // DupB pops a boolean value from the stack and pushes it back into the stack twice. DupB Opcode = 15 // DupI pops an integer value from the stack and pushes it back into the stack twice. DupI Opcode = 16 // DupD pops a double value from the stack and pushes it back into the stack twice. DupD Opcode = 17 // RLoadS pops a string from the stack and stores in the target register. RLoadS Opcode = 20 // RLoadB pops a bool from the stack and stores in the target register. RLoadB Opcode = 21 // RLoadI pops an integer from the stack and stores in the target register. RLoadI Opcode = 22 // RLoadD pops a double from the stack and stores in the target register. RLoadD Opcode = 23 // ALoadS loads its string argument into the target register. ALoadS Opcode = 30 // ALoadB loads its boolean argument into the target register. ALoadB Opcode = 31 // ALoadI loads its integer argument into the target register. ALoadI Opcode = 32 // ALoadD loads its double argument into the target register. ALoadD Opcode = 33 // APushS pushes its string argument to the stack. APushS Opcode = 40 // APushB pushes its boolean argument to the stack. APushB Opcode = 41 // APushI pushes its integer argument to the stack. APushI Opcode = 42 // APushD pushes its double argument to the stack. APushD Opcode = 43 // RPushS reads a string value from the target register and pushes it into stack. RPushS Opcode = 50 // RPushB reads a boolean value from the target register and pushes it into stack. RPushB Opcode = 51 // RPushI reads an integer value from the target register and pushes it into stack. RPushI Opcode = 52 // RPushD reads a double value from the target register and pushes it into stack. RPushD Opcode = 53 // EqS pops two string values from the stack and compare for equality. If the strings are // equal then it pushes 1 into the stack, otherwise it pushes 0. EqS Opcode = 60 // EqB pops two bool values from the stack and compare for equality. If equal, then it // pushes 1 into the stack, otherwise it pushes 0. EqB Opcode = 61 // EqI pops two integer values from the stack and compare for equality. If equal, then it // pushes 1 into the stack, otherwise it pushes 0. EqI Opcode = 62 // EqD pops two double values from the stack and compare for equality. If equal, then it // pushes 1 into the stack, otherwise it pushes 0. EqD Opcode = 63 // AEqS pops a string value from the stack and compare it against its argument for equality. // If equal, then it pushes 1 into the stack, otherwise it pushes 0. AEqS Opcode = 70 // AEqB pops a bool value from the stack and compare it against its argument for equality. // If equal, then it pushes 1 into the stack, otherwise it pushes 0. AEqB Opcode = 71 // AEqI pops an integer value from the stack and compare it against its argument for equality // If equal, then it pushes 1 into the stack, otherwise it pushes 0. AEqI Opcode = 72 // AEqD pops a double value from the stack and compare it against its argument for equality // If equal, then it pushes 1 into the stack, otherwise it pushes 0. AEqD Opcode = 73 // Xor pops two boolean values from the stack, performs logical exclusive-or, then pushes the // result back into stack. Xor Opcode = 80 // And pops two boolean values from the stack, performs logical and, then pushes the // result back into stack. And Opcode = 81 // Or pops two boolean values from the stack, performs logical or, then pushes the // result back into stack. Or Opcode = 82 // AXor pops a boolean value from the stack and performs logical exclusive-or with its // argument, then pushes the result back into stack. AXor Opcode = 83 // AAnd pops a boolean value from the stack and performs logical and with its // argument, then pushes the result back into stack. AAnd Opcode = 84 // AOr pops a boolean value from the stack and performs logical or with its // argument, then pushes the result back into stack. AOr Opcode = 85 // Not pops a boolean value from the stack and performs logical not, // then pushes the result back into stack. Not Opcode = 86 // ResolveS lookups up a string attribute value in the bag, with the given name. // If successful, pushes the resolved string into stack, otherwise raises error. ResolveS Opcode = 90 // ResolveB lookups up a bool attribute value in the bag, with the given name. // If successful, pushes the resolved bool into stack, otherwise raises error. ResolveB Opcode = 91 // ResolveI lookups up an integer attribute value in the bag, with the given name. // If successful, pushes the resolved integer into stack, otherwise raises error. ResolveI Opcode = 92 // ResolveD lookups up a double attribute value in the bag, with the given name. // If successful, pushes the resolved double into stack, otherwise raises error. ResolveD Opcode = 93 // ResolveF lookups up a interface{} attribute value in the bag, with the given name. // If successful, pushes the resolved interface{} into stack, otherwise raises error. ResolveF Opcode = 94 // TResolveS lookups up a string attribute value in the bag, with the given name. // If successful, pushes the resolved string value, then 1 into the stack, // otherwise pushes 0. TResolveS Opcode = 100 // TResolveB lookups up a bool attribute value in the bag, with the given name. // If successful, pushes the resolved bool value, then 1 into the stack, // otherwise pushes 0. TResolveB Opcode = 101 // TResolveI lookups up an integer attribute value in the bag, with the given name. // If successful, pushes the resolved integer value, then 1 into the stack, // otherwise pushes 0. TResolveI Opcode = 102 // TResolveD lookups up a double attribute value in the bag, with the given name. // If successful, pushes the resolved double value, then 1 into the stack, // otherwise pushes 0. TResolveD Opcode = 103 // TResolveF lookups up a interface{} attribute value in the bag, with the given name. // If successful, pushes the resolved interface{} value, then 1 into the stack, // otherwise pushes 0. TResolveF Opcode = 104 // AddI pops two integer values from the stack, adds their value and pushes the result // back into stack. The operation follows Go's integer addition semantics. AddI Opcode = 110 // AddD pops two double values from the stack, adds their value and pushes the result // back into stack. The operation follows Go's float addition semantics. AddD Opcode = 111 // SubI pops two integer values from the stack, and subtracts the second popped value // from the first one, then pushes the result back into stack. // The operation follows Go's integer subtraction semantics. SubI Opcode = 112 // SubD pops two double values from the stack, and subtracts the second popped value // from the first one, then pushes the result back into stack. // The operation follows Go's float subtraction semantics. SubD Opcode = 113 // AAddI pops an integer value from the stack, adds the popped value and its argument, // and pushes the result back into stack. The operation follows Go's integer addition // semantics. AAddI Opcode = 114 // AAddD pops a double value from the stack, adds the popped value and its argument, // and pushes the result back into stack. The operation follows Go's double addition // semantics. AAddD Opcode = 115 // ASubI pops an integer value from the stack, subtracts its argument from the popped value, // then pushes the result back into stack. The operation follows Go's integer subtraction // semantics. ASubI Opcode = 116 // ASubD pops a double value from the stack, subtracts its argument from the popped value, // then pushes the result back into stack. The operation follows Go's double subtraction // semantics. ASubD Opcode = 117 // Jmp jumps to the given instruction address. Jmp Opcode = 200 // Jz pops a bool value from the stack. If the value is zero, then jumps to the given // instruction address. Jz Opcode = 201 // Jnz pops a bool value from the stack. If the value is not 0, then jumps to the given // instruction address. Jnz Opcode = 202 // Call invokes the target function. Call Opcode = 203 // Ret returns from the current function. Ret Opcode = 204 // Lookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap // using the string as the name. If a value is found, then the value is pushed into the // stack. Otherwise raises an error. Lookup Opcode = 210 // TLookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap // using the string as the name. If a value is found, then the value is pushed into the // stack, then 1. Otherwise 0 is pushed to into the stack. TLookup Opcode = 211 // ALookup pops a stringmap from the stack and perform a lookup on the stringmap using the string // parameter as the name. If a value is found, then the value is pushed into the stack // Otherwise raises an error. ALookup Opcode = 212 // NLookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap // using the string as the name. If a value is found, then the value is pushed into the // stack. Otherwise empty string is pushed onto the stack. NLookup Opcode = 213 // ANLookup pops a stringmap from the stack and perform a lookup on the stringmap using the string // parameter as the name. If a value is found, then the value is pushed into the stack // Otherwise empty string is pushed onto the stack. ANLookup Opcode = 214 )
func GetOpcode ¶
GetOpcode finds and returns the opcode that matches the keyword text that is supplied.
type OpcodeArg ¶
type OpcodeArg int
OpcodeArg represents the type of the arguments that opcodes have.
const ( // OpcodeArgRegister represents an argument that references a register. OpcodeArgRegister OpcodeArg = 0 // OpcodeArgString represents an argument that is a string. OpcodeArgString OpcodeArg = 1 // OpcodeArgInt represents an argument that is an integer. OpcodeArgInt OpcodeArg = 2 // OpcodeArgDouble represents an argument that is a double. OpcodeArgDouble OpcodeArg = 3 // OpcodeArgBool represents an argument that is a boolean. OpcodeArgBool OpcodeArg = 4 // OpcodeArgFunction represents an argument that is a function. OpcodeArgFunction OpcodeArg = 5 // OpcodeArgAddress represents an argument that is an address. OpcodeArgAddress OpcodeArg = 6 )
type Program ¶
type Program struct { // Functions is the collection of functions that are contained in the program. Functions *FunctionTable // contains filtered or unexported fields }
Program is a self-contained IL based set of functions that can be executed by an interpreter.
func (*Program) AddExternDef ¶
AddExternDef adds a new external/native function to the program. The actual bodies of functions need to be supplied to the interpreter separately.
func (*Program) AddFunction ¶
AddFunction adds a new IL based function to the program.
func (*Program) Strings ¶
func (p *Program) Strings() *StringTable
Strings returns the strings table of this program.
type StringMap ¶
StringMap defines interface over map[string]string This is used for reference counting.
type StringTable ¶
type StringTable struct {
// contains filtered or unexported fields
}
StringTable is a table that maps uint32 ids to strings and allows efficient storage of strings in IL.
func (*StringTable) Add ¶
func (t *StringTable) Add(s string) uint32
Add adds the given string to the table, if it doesn't exit, and returns its id.
func (*StringTable) GetString ¶
func (t *StringTable) GetString(id uint32) string
GetString returns the string with the given id, or empty string.
func (*StringTable) Size ¶
func (t *StringTable) Size() int
Size returns the number of entries in the table.
func (*StringTable) TryGetID ¶
func (t *StringTable) TryGetID(s string) uint32
TryGetID returns the id of the given string if it exists, or returns 0.
type Type ¶
type Type uint32
Type represents a core type in the il system.
const ( // Unknown represents a type that is unknown. Unknown Type = iota // Void represents the void type. Void // String represents the string type. String // Integer represents a 64-bit signed integer. Integer // Double represents a 64-bit signed floating point number. Double // Bool represents a boolean value. Bool // Duration represents a time.Duration value Duration // Interface represents a generic interface{} value Interface )
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package interpreter implements an interpreter based runtime for the Mixer IL.
|
Package interpreter implements an interpreter based runtime for the Mixer IL. |