HertzScript Systems Specification
WORK IN PROGRESS
1High-Level Synopsis
HertzScript (abbreviated “HzScript”) automatically transforms JavaScript functions into stackless coroutines which can be preempted, and provides a degree of concurrency which is more fine‐grained than what you get with traditional JavaScript. Normally functions must run from beginning to end due to the single‐threaded nature of JavaScript, but HertzScript automatically pauses and context switches between several functions mid‐execution. Software developers may utilize HertzScript’s concurrency via a new spawn
keyword. If you call a function which is preceded by the spawn
keyword, then the function will run concurrently alongside any other functions and the caller function.
Coroutines are normally reserved for cooperative multitasking and have to be manually implemented by software developers, requiring them to manage control yielding and reentry points. HertzScript implements voluntary preemptive multitasking which is a compiler‐managed variant of cooperative multitasking, and it does not require the developer to manually implement control yielding or reentry points.
2Reference Systems & Supporting Technologies
3Overview of Components
HertzScript is composed of layered abstracting and interoperating systems including a compiler, virtual machine, multitasking dispatcher, and programming environment. Each component can be used either independently or as part of a higher‐level abstracting component. The lowest‐level foundational components are the compiler and the virtual machine.
4Literal Value Notation & Data Types
Specific conventions for the notation of typed literal values are defined here and are used throughout this specification. Some special characters indicated within this section are Markdown terminal characters.
Notating a literal value with a specific data type may require the prefixing and/or postfixing of specific characters.
When contributing to this specification’s Markdown documents via a text editor, each reference to a literal value requires grave accents to be the outermost prefix and postfix: ` (U+0060
)
The below table illustrates the following for each data type:
- The name of the data type.
- Special characters and their Unicode charcodes in parentheses.
- The positions at which special characters should be located relative to the literal value.
- An unformatted Markdown example which a reader would observe in a plain‐text editor.
- A formatted example which a reader would observe when viewing the rendered distribution of this specification.
Type | Characters | Position of Characters | Unformatted Example | Formatted Example |
---|---|---|---|---|
Identifier | None | None | `name` | name |
Object | Object | Prefix | Object `name` | Object name |
Nested Property Key Value | Full Stop: . (U+002E ) | Between Property Keys | `name1.name2` | name1.name2 |
Symbol | Commercial At: @ (U+0040 ) | Prefix | `@name` | @name |
TokenLib Symbol | 2x Commercial At: @@ (U+0040 ) | Prefix | `@@name` | @@name |
String | Quotation Mark: " (U+0022 ) | Prefix & Postfix | `“string”` | "string" |
Boolean | None | None | `true` | true |
Integer | None | None | `123` | 123 |
Float | Full Stop: . (U+002E ) | Anywhere | `12.34` | 12.34 |
Negative Integer | Minus Sign: - (U+2212 ) | Prefix | `-123` | -123 |
Negative Float | Minus Sign: - (U+2212 ) | Prefix | `-12.34` | -12.34 |
Null | None | None | `null` | null |
Undefined | None | None | `undefined` | undefined |
4.1Object
Objects are logical collections of properties. Each property associates a key value with an arbitrary value of any data type.
Property key values can be used to access or assign properties and their associated arbitrary values.
Dynamic property key values are equal to any value referred to by an Identifier, and can be used to access or assign properties and their associated arbitrary values.
Nested properties may be notated in short‐form such that a Full Stop or period may be placed between each property key value.
Objects must be prefixed with the word “Object”.
4.2Symbol
Symbols are uniqueness types, meaning every symbol is immutable and unique. Symbols are used as dynamic property keys for Objects.
Symbols are prefixed by a single “commercial at” characer.
A Symbol that is created by and is a member of TokenLib.symbols
is prefixed by two “commercial at” characters.
4.3String
Strings are finite ordered sequences of zero or more 16‐bit unsigned integer values.
Strings must be both prefixed and postfixed by quotation marks.
4.4Boolean
Booleans must be equal to one of two different values: true
or false
.
4.5Integer
Integers are whole numbers represented by double‐precision 64‐bit binary format IEEE 754‐2008 values.
Integers which are negative must be notated with a minus sign prefix. Integers which both non‐terminating and infinitely large must be notated with Infinity
, or -Infinity
for negative numbers.
4.6Float
Floats are non‐whole numbers which are represented by double‐precision 64‐bit binary format IEEE 754‐2008 values.
Floats which are negative must be notated with a minus sign prefix.
4.7Null
null
is unchangeable and is always equal to null
.
4.8Undefined
undefined
is unchangeable and is always equal to undefined
.
5Compiler
The HertzScript compiler transforms function calls into yielded instances of InstructionToken
such that all transformed function calls are made in reverse upon script execution.
The HertzScript compiler uses a multi‐stage source‐to‐source compilation process to transform JavaScript functions into instruction streams; all functions within a HzScript program are GeneratorFunctions which yield instructions. Residing the bottom abstraction level of the system, the HertzScript compiler serves as a fundamental mechanism in the creation of re‐entrant programs.
The first stage in the compilation process consists of Acorn, an Acorn parser plugin, and Acorn‐Walk, which are used to parse and transform any SpawnExpression
to a regular method call for Babel to recognize in the second stage. spawn
is a contextual keyword which could also be a regular method call and not a SpawnExpression
, so the parser looks for any instance of the spawn
keyword followed by any number of spaces and an identifier character.
The second stage consists of Babel and a Babel transformation plugin which is used to transform all function expressions/statements into GeneratorFunctions, and wrap all functions in detour hooking functions. Within the new GeneratorFunctions all CallExpressions, NewExpressions, ReturnStatements, YieldExpressions, and SpawnExpressions are transformed into yielded instruction tokens. A special token named loopYield
is added to the beginning of each loop to ensure that they are interruptable.
5.1Transformation Functions
5.1.1HzCoroutine
5.2Visitor Functions
5.2.1CallExpression
6VirtualMachine
The VirtualMachine
class sequentially executes a single InstructionToken
stream originating from a coroutine, and implements computational behaviors as indicated by each InstructionToken
. VirtualMachine
may consume both InstructionToken
Object instances and context‐sensitive data.
Most behaviors and Functions within VirtualMachine
are managed and executed by an AspectWeaver
class instance.
VirtualMachine
changes how the JavaScript virtual machine call stack is utilized. When a new coroutine is started, a new ControlBlock
class instance is created for it which contains a virtual call stack, and the HertzScript instruction set corresponds with operations which push and pop the coroutines in that stack. Only the currently executing coroutine will reside within the JavaScript VM call stack. The JavaScript VM call stack does not grow past the currently running coroutine except during function calls which were initiated by many of JavaScript’s standard operators which are not the invocation operator, loosely limiting the VM call stack to a set length. The end result of this size reduction is that all coroutines are generally able to perform a context switch with O(1)
time complexity, significantly reducing any possible jitter that would critically impact multitasking operations.
6.1Error Handling
6.2Execution Cycle
The core execution cycle is called the Fetch‐Coerce‐Execute cycle, or FCE cycle. The FCE cycle’s programming style and construction is that of Aspect‐Oriented Programming. The FCE Functions are cycle
, fetchInstruction
, coerceInstruction
, and executeInstruction
; the VirtualMachine
constructor submits the three FCE Functions to an AspectWeaver
instance. The AspectWeaver
instance is given three Pointcuts labaled with the Strings "fetch"
, "coerce"
, and "execute"
. The labeled Pointcuts expose six Joinpoints in total, such that Functions may be added or removed at six logical points in the control flow before or after each of the three FCE Functions.
6.3Preemption
VirtualMachine
is able to interrupt a coroutine which has been compiled by the HertzScript Compiler. Preemption may be performed within cycle
before each FCE cycle or via adding a Function after the execute
Joinpoint or before the cycle
Joinpoint.
6.4Constructor
VirtualMachine(uTokenLib = null) :
- If
uTokenLib
is strictly equal tonull
, then- Let
this.tokenLib
beuTokenLib
.
- Let
- Else let
this.tokenLib
be a new instance of classTokenLib
; - Let
this.detourLib
be a new instance of classDetourLib
with argumentsVirtualMachine
andthis.tokenLib
. - Let
this.userLib
be a new instance of classUserLib
with argumentsthis.tokenLib
andthis.detourLib
. - Let
this.controlBlock
be a new instance of classControlBlock
with argumentsthis.tokenLib
. - Let
this.lastError
bethis.tokenLib.symbols.nullSym
. - Let
this.lastRemit
bethis.tokenLib.symbols.nullSym
. - Let
this.lastInstruction
benull
. - Let
this.terminated
befalse
. - Let
instructions
be new instance of classObject
.- Let
instructions.enqueue
bethis._enqueue
. - Let
instructions.import
be Array<this._import
>. - Let
instructions.terminate
bethis._terminate
. - Let
instructions.vmError
bethis._vmError
. - Let
instructions.programError
bethis._programError
. - Let
instructions.fetch
bethis._fetch
. - Let
instructions.coerce
bethis._coerce
. - Let
instructions.execute
bethis._execute
. - Let
instructions.cycle
bethis._cycle
. - Let
instructions.cycleAsync
bethis._cycleAsync
.
- Let
- Let
this.weaver
be a new instance of classAspectWeaver
with argumentsthis
andinstructions
.
6.5Prototype Members
6.5.1executors
6.6Prototype Methods
6.6.1fetchInstruction
6.6.2foerceInstruction
6.6.3executeInstruction
6.7AspectWeaver
The AspectWeaver
class is an Aspect‐oriented program control system which is designed to allow the sequential execution, addition, mutation, and removal of Functions during run‐time. Points at which functions may be added or removed are called Joinpoints, whereas the problem domains which Joinpoints implement are called Pointcuts.
6.8DetourLib
The Babel transformation plugin wraps all function declarations and expressions in detouring functions, and the detour library is a collection of function hooks designed to detour specific types of functions.
Detour functions insert a hooking function which replaces the original function with a special invocation adapter. Upon invoking the adapter a new HertzScript virtual machine is started in‐place, and the original function is run from within it. The original function is assigned to a Symbol property named tokenSym
. Each hooking function marks the detour function and original function with special marker Symbols which allow the virtual machine to observe information which would originally only be visible at compile‐time.
The below figure illustrates the path of control flow from a caller function to the original function after it has been detoured.
6.8.1Detour Hooking Functions
Name|Arguments|Description -------------------------- hookCoroutine
| | Detours a function. hookArrowCoroutine
detours an ArrowFunctionExpression
. hookGenerator
detours a GeneratorFunction
. hookIterator
detours an iterator interface object’s next
, return
, and throw
methods.
6.9Kernelizer
The Kernelizer
class is a very simple object which assigns arbitrary values directly to itself. This class serves as the base class for the InstructionToken
class.
Strings given as an argument list to the constructor indicate the labels of arguments given in an Array via the set
method, and can be reset with an arbitrary value via the reset
method.
6.9.1Constructor
Assigns undefined to all properties ordered via an argument list of Strings spread to Array argsArray
.
Kernelizer(...argsArrray) :
- Let value of property
argSlots
ofthis
beargsArray
. - Invoke
this.reset()
.
6.9.2Prototype Methods
6.9.2.1reset
Assigns an arbitrary value resetValue
to all properties ordered via Strings in Array this.argSlots
.
Kernelizer.prototype.reset(resetValue) :
- If
this.argSlots.length
is strictly equal to0
, then- Return
this
.
- Return
- For each
argName
of Arraythis.argSlots
, do- Let value of dynamic property
argName
ofthis
beresetValue
.
- Let value of dynamic property
- Return
this
.
6.9.2.2set
Assigns arbitrary values in Array argsArray
to properties ordered via Strings in Array this.argSlots
Kernelizer.prototype.set(argsArray) :
- If
this.argSlots.length
is strictly equal to0
, then- Return
this
. - Let
loc
be0
.
- Return
- For each
argName
ofthis.argSlots
, do- If Number
loc
is less than or equal to NumberargsArray.length
, then- Let value of dynamic property
argName
ofthis
be the value of dynamic propertyloc
ofargsArray
.
- Let value of dynamic property
- Else let value of dynamic property
argName
ofthis
be undefined. - Increment Number
loc
by1
.
- If Number
- Return
this
.
6.10InstructionToken
The InstructionToken
class extends the Kernelizer
class by assigning String type
and Symbol kernSym
to itself.
6.10.1Constructor
InstructionToken(type, kernSym, ...argsArrray) :
- Let
kern
be a new instance of classKernelizer
. - Let
kern.type
betype
. - Let value of dynamic property
kernSym
ofkern
betrue
. - Return
kern
.
6.11TokenLib
TokenLib
is a class which creates and contains InstructionToken
instances and marker Symbols.
InstructionToken
instances are designed to safely encapsulate userspace data such as functions and their input operands, return/yield values, or no data. All InstructionToken
instances are marked by having a special symbol assigned to them called kernSym
; if VirtualMachine
determines that an object has the symbol as a property, then it assumes that the object is an InstructionToken
and attempts to process it.
Each InstructionToken
is a single‐instance uniqueness type to reduce memory overhead, because all instances are gauranteed to be thread‐safe and free of race conditions. Because the virtual machine executes in a single thread, each unique InstructionToken
instance will be used atomically during a single VirtualMachine
fetch‐decode‐execute cycle.
6.11.1Object Methods
6.11.1.1isKernelized
Returns a Boolean which indicates whether or not input
is an Object instance of either the InstructionToken
class or the Kernelizer
class.
- If the data type of
input
is Object, then- If dynamic property
@@kernSym
exists withininput
, returntrue
.
- If dynamic property
- Else return
false
.
6.11.2Object Properties
6.11.2.1tokens
Name | Arguments | Description |
---|---|---|
loopYield | None | Yield control flow to VirtualMachine . |
call | Array< Function functor , Boolean isTailCall > | Invoke a function. |
callArgs | Array< Function functor , Array args , Boolean isTailCall > | Invoke a function with arguments. |
callMethod | Array< Object object , Any property , Boolean isTailCall > | Invoke an Object method function. |
callMethodArgs | Object object , Any property , Array args , Boolean isTailCall > | Invoke an Object method function with arguments. |
new | Array< Function functor > | Invoke a constructor. |
newArgs | Array< Function functor , Array args > | Invoke a constructor with arguments. |
newMethod | Array< Object object , Any property > | Invoke a constructor Object method function. |
newMethodArgs | Array< Object object , Any property , Array args > | Invoke a constructor Object method function with arguments. |
spawn | Array< Function functor > | Queue a coroutine for later execution. |
spawnArgs | Array< Function functor , Array args > | Queue a coroutine for later execution with arguments. |
spawnMethod | Array< Object object , Any property > | Queue an Object method coroutine for later execution. |
spawnMethodArgs | Array< Object object , Any property , Array args > | Queue an Object method coroutine for later execution with arguments. |
return | None | Perform a return statement. |
returnValue | Array< Any arg > | Perform a return statement with a value. |
yield | None | Perform a yield expression. |
yieldValue | Array< Any arg > | Perform a yield expression with a value. |
6.11.2.2symbols
Name | Value | Description |
---|---|---|
tokenSym | Function | Is assigned to the userspace Function of a coroutine. |
crtSym | Any | Marks the function it is assigned to as being a coroutine. |
conSym | Any | Marks the function it is assigned to as being coroutine. |
genSym | Any | Marks the function it is assigned to as being generator. |
iterSym | Any | Marks the function it is assigned to as being assigned to an iterator interface object. |
6.12UserLib
7Dispatcher
The HertzScript dispatcher is a concurrency control system and preemptive multitasking kernel. The dispatcher is responsible for the supervision, scheduling, dispatchment, preemption, and context switching of multiple different HertzScript virtual machines within a single thread.
8Programming Environment
TBD