OneScript
  • Welcome to OneScript
  • OneScript Overview
    • Dates and Times
    • Sets
    • Types
    • Fields
      • Helper Fields
      • Labels
      • Standard Text
    • Snapshots
    • State Management
    • Future Features
  • Get OneScript
  • Macro Overview
    • Macro Virtual Machine
    • Code Instructions
  • Standard Libraries
    • Core
    • Data
    • Interview Model
  • Linker Overview
    • Objects
  • Contact Us
Powered by GitBook
On this page
  • Instruction Structure
  • Type
  • Action
  • Operands
  • Immediate Operands
  • Registers
  • Processor Status
  • Referenced
  • Indexed
  • Deferred
  • Combinations
  • Fast Instructions
  • Conversion Instructions
  • Conditional Instructions
  • Unconditional Branching Instructions
  • Goto Instruction
  • Call and Return
  • Gosub and Ret
  • Transferring Data
  • Accessing External Libraries
  • Stack Management
  • Error Handling
  • Exceptions
  • Process Control
  • Threads
  1. Macro Overview

Code Instructions

Code instructions are made up of an operator and operands. For example:

iload #0

The above shows the operator to load an integer. This particular operator expects only one operand and in this instance is the immediate value '0'.

Instructions usually denote the type of data it is operating upon (integer, boolean, etc.) with a prefix of the type. For example:

iload #0                // An integer to be loaded onto the stack
bload #true             // A boolean value to be loaded onto the stack
sstore localStringValue // The string on the stack to be stored in the 
                        // table declaration referenced by localStringValue

Instructions are not type safe. It is up to the programmer to ensure the code is made type safe. Poorly developed code will result in unpredictable results.

Instruction Structure

Instructions are usually structured in the following way:

{type}{action}

Type

The type can be one of the followings:

Type

Description

b

Boolean

by

byte

d

date/time

i

integer

e

set

f

float

s

string

Action

Depending on the type the action can be one of the following:

Action

Description

load

Load a value onto the stack

store

Store a value in a program location. This could be in a local, or global entry.

return

Return a frame off the stack returning to the current program counter location.

add

Add a value to another value and store the result.

sub

Subtract one value from another and store the result.

div

Divide one value by another and store the result.

mul

Multiply one value by another and store the result.

cvt

Convert one value to another.

return

Return a value from a method

or

Perform a logical or binary or and store the result.

and

Perform a logical or binary and and store the result.

Operands

Operands fall into the following types:

Immediate Operands

Immediate operands refer to constants or values that can be assessed at compile time. They are prefixed with a # unless it is a string which is automatically interpreted as a literal:

sload "This is a string"
byload #23

Registers

Macro has 12 registers that allow provide an alternative to storing temporary data in a table or on the stack and access to processor status values. For example:

loads "This is a string"
store r0

Name

Description

r0 - r9

Registers that can hold any object

pc (r10)

The program counter of the current instruction. Any changes made to this must be handled with care.

sp (r11)

The stack pointer for the current stack. Any changes made to this must be handled with care.

ps (r12)

The processor status. Any changes to this must be handles with care.

Processor Status

The process Status is an integer that indicates the status of the current processor thread. Each bit has a certain function:

Position

Description

0

Floating Overflow has occurred in the last instruction

1

Divide By Zero has occurred in the last instruction

2

Zero result has occurred with the last instruction.

3

Null result has occurred with the last instruction.

4

Boolean

Referenced

Referenced operands refer to a position in a local table or to an external address. For example:

sload AReallyBigString
store r0

The above will load a string from a local reference (AReallyBigString) and store the value in the register r0. To access an external value the following modification to the reference can be applied:

sload G^AReallyBigString
store r0

In the above the reference to AReallyBigString will be searched for in referenced external libraries referred to in the import directives.

Indexed

Where appropriate it is possible to extend an operand by an index. For example:

byload bytearray[#0]
store r0

This will assume the bytearray is an array and load the element from it referred to by the immediate operand #0. The index can be any type of operand that returns a number for an index relevant to array is is referring to. This means only operands that result ina byte or int value can be used.

Deferred

An operand can sometimes point to the actual operand. For example:

sload (aStringReference)

Combinations

Combining instructions and operands is where the real power of Macro coding resides. Consider a basic instruction to add two integers together and store the result in another value:

iadd #2, #3, result

The basic iadd instruction combines one instruction and three operands together to achieve this process. However, it is possible to use a combination of operands and stack to push the result onto the stack for further use (if it not required to be stored). This would be achieved in the following way:

iadd #2, #3

By missing the third operand off it is assumed that the result should be pushed onto the stack. To complete the initial instruction using this approach:

iadd #2, #3
store result

This can be taken further so that none, some or all of the operands for an add action (or similar type of instruction) can be removed and the stack can be used. Taking the initial add instruction to have no operands the same process could be achieved in the following way:

iload #3
iload #2
iadd
store result

In this example the two values are popped off the stack added and the result is pushed onto the stack. Then the result is popped off the stack and stored in result.

Not all instructions provide this capability.

Fast Instructions

Some more common instructions have been combined into single instructions to save time. These are as follows:

Instruction

Description

bload_n

Load a boolean value where n can be true or false onto the stack.

byload_n

Load a byte value where n can be 0 to 3 onto the stack.

iload_n

Load an integer value where n can be 0 to 3 onto the stack

Conversion Instructions

These instructions convert one type to another. They take the form:

{base}cvt{destination}

For example:

icvtb

It is possible to convert types based on the table:

?

bool (b)

byte(by)

int (i)

date (d)

set (e)

float (f)

string (s)

bool (b)

.

x

.

.

.

.

x

byte (by)

x

.

x

.

.

.

x

int (i)

x

x

.

x

x

x

x

date (d)

.

.

.

.

.

.

x

float (f)

x

x

x

.

.

.

x

string (s)

x

x

x

x

x

x

.

Conditional Instructions

It is possible to branch from one location to another based on that value on te top of the stack.

Instruction

Description

ifeq

If equal to zero then branch

ifne

If not equal to zero then branch

ifgt

If greater than zero then branch

iflt

If less than zero then branch

ifge

If greater than or equal to zero then branch

ifle

If less than or equal to zero then branch

iftrue

If true then branch

iffalse

If false then branch

ifnull

If there is a null value on the stack then branch

ifnotnull

If there if not a null value on the stack then branch

Each on of the conditional instructions has a boolean push stack version. this is achieved by adding a b to the instruction. For example:

ifeqb

The above instruction pops the integer value from the stack and converts it to a boolean value (if value equals zero then push true else push false).

Unconditional Branching Instructions

Goto Instruction

To support this there is also the goto instruction that you can use to branch unconditionally to a position in the instructions. For example:

    ...
    load questions
    invokevirtual InitialiseLooping()
a10$:
    load questions
    invokevirtual Next()
    iffalse a20$
    load questions
    invokevirtual GetItem()
    store question
    load question
    invokevirtual Ask()
    goto a10$
a20$:
    ...

Call and Return

To support code that you want to repeat it is possible to call a method and return from it.

    ...
    load question
    call testQuestion(IQuestion)
    ...

    ...
.method testQuestion(IQuestion question)
    load question
    invokevirtual Ask()
    return
    ...

Gosub and Ret

It is possible to run a subroutine of code that is not a specially declared method, but simply referred to by a label in the gosub instruction:

    iload_0
    iload #1
    gosub 10$
    iload #2
    gosub 10$
    ireturn
10$:
    add
    ret

Whilst the example could be better, the benefit of this approach is that no call stack is created for what could be a repetitive task and therefore save time.

Transferring Data

The move instruction is one untyped instruction that allows a reference to be moved from one location to another.

    move #1, r0

The move instruction will take any operands that make sense to transfer a value from one location to another.

Accessing External Libraries

It is possible to access static and dynamic instances of classes and access its methods and properties through a set of instructions.

To create an instance of an object use the new instruction:

    ...
    sload #jsonString
    new IQuestion(string)
    store q1
    ...

To access a method in the object:

    ...
    sload #jsonString
    new IQuestion(string)
    store q1
    load q1
    invokeVirtual Ask()
    ...

To access a property it is possible to access the direct method if it known or the general property:

    ...
    sload #jsonString
    new IQuestion(string)
    store q1
    load q1
    invokeVirtual get_Label()
    ...

Most properties are accessible through a getter which is identified by the get_ prefix. Setting a property is achieved through the setter which is identified by the set_ prefix:

    ...
    sload #jsonString
    new IQuestion(string)
    store q1
    load q1
    load label1
    invokeVirtual set_Label(label)
    ...

Accessing static classes is also easy with Macro. These do no need to instantiated, but can simply be accessed directly:

    new InterviewContext()
    invokestatic InterviewState.set_Context(InterviewContext)
    getstatic InterviewState.get_Context

Stack Management

Just in case you want to mange the stack independently of the rest of the instructions set you can also use the pop instruction to remove unwanted items from the stack.

Error Handling

It is possible to define error management using the pushh, throw and poph instructions. For example:

    ...
    pushh Exception,x30$ NullException,x40$
    load questions
    invokevirtual InitialiseLooping()
a10$:
    load questions
    invokevirtual Next()
    iffalse a20$
    load questions
    invokevirtual GetItem()
    store question
    load question
    invokevirtual Ask()
    goto a10$
a20$:
    ...
x30$:
    // general exception
    ...
x40$:
    // Null exception
    ...

The pushh instruction pushes a handler onto the handler stack. The handler stack operates as a cascading exception handler, so if the error is not picked up by the handler on top of the stack the next handler is used.

The throw instruction will cause an exception to be thrown and the handler stack to be accessed for in search for an exception handler that will support the error. If a handler is available then the stack will have the exception details on it if you wish to use them. For example:

10$:
    store error
    return

The above example assumes (as performed by the runtime error handling) that the error has been pushed onto the stack for use by the error handler.

The poph instruction will remove the handler off the top of the handler stack.

These three instructions allow the Macro Virtual Machine to mimic most language try, catch type error handlers.

Exceptions

It is possible that an instruction itself can cause an exception. If this happens it will trigger access to the handler stack. An exception is based on the following list:

Exception

Description

Exception

A general exception and a catchall.

NullException

A null value was detected.

DivideByZero

Division by zero detected.

More exceptions will be made available over time to support the standard libraries.

Process Control

The Macro Virtual Machine includes the ability to pass control back to the calling environment. This can be achieved through the Show and Ask methods of the Interview Models Standard Library. But it is also possible to pass back control using the wait instruction:

wait [ operand ]

The operand can be any operand which is passed back to the calling environment. It is up to the calling environment to expect and process it.

Threads

There are a set of instructions that make it possible to create threads for asynchronous programming. Threads can be created using the follwoing approach:

.method void Test()
.table
    Thread threada
.code
    thread ThreadTest, threada
    start threada
    return
    
.method void ThreadTest()
.code
    load #0, r0
10$:
    add #1, r0, r0
    sub r0, #10
    bneq 10$
    return

In the above example a thread is created and started. To stop a thread before it is completed you can use the kill instruction.

.method void Test()
.table
    Thread threada
.code
    thread ThreadTest, threada
    start threada
    kill threada
    return
    
.method void ThreadTest()
.code
    load #0, r0
10$:
    add #1, r0, r0
    sub r0, #10000
    bneq 10$
    return

To wait for a thread to complete you can use the join instruction.

.method void Test()
.table
    Thread threada
.code
    thread ThreadTest, threada
    start threada
    join threada
    return
    
.method void ThreadTest()
.code
    load #0, r0
10$:
    add #1, r0, r0
    sub r0, #10
    bneq 10$
    return

To paused a thread the wait instruction can be used, specifying an operand that refers to the number of milliseconds to pause.

.method void Test()
.table
    Thread threada
.code
    thread ThreadTest, threada
    start threada
    return
    
.method void ThreadTest()
.code
    load #0, r0
10$:
    add #1, r0, r0
    sub r0, #10
    wait #30000
    bneq 10$
    return

To support multi threaded code it is possible to queue threads up to run the same code using the lock and unlock instructions.

Locking an object will add it to a thread watchlist and any other threads attemping to lock the same object will placed into a wait state until the object is freed up to be locked again. Unlocking an object will make available for the next thread to lock and continue with the code.

PreviousMacro Virtual MachineNextStandard Libraries

Last updated 2 years ago