An
Interpreter defines a concrete protocol
which maps from the numeric value of byte codes (produced by a
Compiler and stored in a
Method) to an ordered set of functions defined in C++ which implement a (hopefully minimal) set of well known functions on those objects. Many concrete protocols are possible, but ColdStore natively provides the
C-- Concrete Protocol in support of the C-- language.
Other concrete protocols can be used to map other interpreted bytecodes (e.g. Python, Java) to a set of interface functions which provide their functionality in terms of the underlying functionality provided by the Virtual Protocol.
C-- is a language which is modelled roughly on C++, and treated in detail elsewhere.
A Concrete Protocol is defined here which is sufficient to permit a byte code to be interpreted relative to a stack, to provide functionality defined by the C-- language, and translated by the C-- compiler.
Pops n items from the top of stack.
Pushes 1 item onto stack.
Duplicates the top of the stack.
Swaps top() and under() on stack.
Non-destructively returns the top of stack.
Non-destructively returns the element under the top of stack.
Complex stack operations are used to modulate the stack, and constrain its Segment endpoints to a subsegment of the whole stack, which then becomes inaccessable via the normal accessor/mutators.
Generally, interpretation of an opcode will commence with a startFrame and end with an endFrame. When direct stack access by untrusted code is necessary, the start/endFrame can enclose a push/popFrame. These enforce the limits implied by the frame.
In interpreting object.fn(arg1,arg2,arg3), the compiler would emit a startFrame, then code to evaluate arg1..arg3, then code to evaluate the expression fn, then code to evaluate the expression object. It would then emit a pushFrame, arrange for the calling of object.fn, then a Method->retMethod to clean up the Method args, then a popFrame to remove constraints, and finally an endFrame to incorporate the function results back into the calling stack frame.
The frame index is intended to cope with the nesting of grouping operators like [] and (). The pushing and popping of frames is intended to be a scope-restriction device, preventing access by lower stackframes to the contents of enclosing stack frames.
All stack indices are interpreted relative to the current start of stack. The current start of stack is, however, an absolute index relative to the allocation Segment of the implementing Vector or List.