libose
Loading...
Searching...
No Matches
Macros | Enumerations | Functions
osevm_lib.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define OSEVM_WRAP_DECL(name)    void osevm_##name(ose_bundle bundle);
 Declare void osevm_<name>(ose_bundle osevm), the VM-level form of the stack operation ose_<name>().
 
#define OSEVM_WRAP_DEFN(name)
 Define the function OSEVM_WRAP_DECL declares.
 
#define OSEVM_WRAP_DEFPRED(name)
 Define osevm_<name>() for a predicate bool ose_<name>(int32_t).
 
#define OSEVM_FRAME_MAGIC   0x2346524D /* "#FRM" */
 The word after #bundle in a frame's header, "#FRM", by which osevm_return tells a frame from anything else on the dump.
 

Enumerations

enum  {
  OSEVM_FRAME_INPUT = 1 , OSEVM_FRAME_ENV = 2 , OSEVM_FRAME_STACK = 4 , OSEVM_FRAME_CONTROL = 8 ,
  OSEVM_FRAME_STACK_BELOW = 16
}
 

Functions

int osevm_pushFrame (ose_bundle osevm, int32_t which, const char *const env, int32_t envlen)
 Save registers to the dump as ONE element – whole, or not at all.
 
void osevm_exec1 (ose_bundle osevm)
 Execute a bundle on the stack.
 
void osevm_exec2 (ose_bundle osevm)
 Execute a bundle on the stack.
 
void osevm_exec3 (ose_bundle osevm)
 Execute a bundle on the stack.
 
void osevm_exec (ose_bundle osevm)
 Synonym for osevm_exec2.
 
void osevm_if (ose_bundle osevm)
 Execute one of two bundles, depending on the value of the int in the last message on the stack.
 
void osevm_dotimes (ose_bundle osevm)
 Execute a bundle repeatedly.
 
void osevm_copyRegisterToElem (ose_bundle osevm)
 Copy a register onto the stack as one element – the /> instruction.
 
void osevm_appendElemToRegister (ose_bundle osevm)
 Append the contents of the top element to a register – /<<.
 
void osevm_replaceRegisterWithElem (ose_bundle osevm)
 Replace a register's contents with the top element's – /<.
 
void osevm_moveElemToRegister (ose_bundle osevm)
 Move the top element into a register – /-.
 
void osevm_copyElemToRegister (ose_bundle osevm)
 Copy the top element into a register.
 
void osevm_apply (ose_bundle osevm)
 Apply the top of the stack – the /! instruction, and the second half of osevm_funcall.
 
void osevm_map (ose_bundle osevm)
 Apply a function to each item of a message, or each element of a bundle – /!/map.
 
void osevm_return (ose_bundle osevm)
 Pop the topmost frame from the dump and restore what it carried – /!/return, and what the VM runs when the control empties inside a call.
 
void osevm_version (ose_bundle osevm)
 Push the library's version – /!/version.
 
void osevm_assignStackToRegister (ose_bundle osevm)
 Gather the stack into the bundle at its bottom, as one message named by the string on top.
 
void osevm_assignStackToEnv_impl (ose_bundle osevm, ose_bundle env, int replace, int new_msg_first, char bundle_typetag)
 Bind everything on the stack, as one message, into a bundle.
 
void osevm_assignStackToEnv (ose_bundle osevm)
 Bind the stack into the environment – the /@ instruction, and the default OSEVM_ASSIGN.
 
void osevm_lookupInEnv_impl (ose_bundle osevm)
 Look a name up – the /$ instruction, and the default OSEVM_LOOKUP.
 
void osevm_lookupInEnv (ose_bundle osevm)
 Call whatever OSEVM_LOOKUP names.
 
void osevm_plookupInEnv_impl (ose_bundle osevm)
 Does nothing.
 
void osevm_plookupInEnv (ose_bundle osevm)
 Does nothing.
 
void osevm_funcall (ose_bundle osevm)
 Look a name up and apply what it finds – the /! instruction on a string, and the default OSEVM_FUNCALL.
 
void osevm_makeRegister (ose_bundle osevm)
 Create a register from a size and a name on the stack; the standard library binds it as /o/make/register.
 
void osevm_quote (ose_bundle bundle)
 Does nothing – the ‘/’` instruction, and the default OSEVM_QUOTE.
 
void osevm_toType (ose_bundle bundle)
 Run ose_toType() on the stack; see OSEVM_WRAP_DECL.
 
void osevm_toInt32 (ose_bundle bundle)
 Run ose_toInt32() on the stack – the /,/i/ instruction on an address; see OSEVM_WRAP_DECL.
 
void osevm_toFloat (ose_bundle bundle)
 Run ose_toFloat() on the stack; see OSEVM_WRAP_DECL.
 
void osevm_toString (ose_bundle bundle)
 Run ose_toString() on the stack; see OSEVM_WRAP_DECL.
 
void osevm_toBlob (ose_bundle bundle)
 Run ose_toBlob() on the stack; see OSEVM_WRAP_DECL.
 
void osevm_appendByte (ose_bundle bundle)
 Run ose_appendByte() on the stack; see OSEVM_WRAP_DECL.
 

Macro Definition Documentation

◆ OSEVM_WRAP_DECL

#define OSEVM_WRAP_DECL (   name)     void osevm_##name(ose_bundle bundle);

Declare void osevm_<name>(ose_bundle osevm), the VM-level form of the stack operation ose_<name>().

The declared function takes the machine rather than a bundle: it fetches the stack register with OSEVM_STACK and runs ose_<name>() on it. See OSEVM_WRAP_DEFN for what it does with errno, which is the only thing the wrapper adds. The functions declared with it below (osevm_toInt32(), osevm_toString(), ...) are the ones the VM dispatches for the /,/i/ family of instructions and the ones the standard library binds.

◆ OSEVM_WRAP_DEFN

#define OSEVM_WRAP_DEFN (   name)
Value:
void osevm_##name(ose_bundle bundle) \
{ \
ose_bundle vm_s = OSEVM_STACK(bundle); \
enum ose_errno e = OSE_ERR_NONE; \
ose_errno_set(vm_s, OSE_ERR_NONE); \
ose_##name(vm_s); \
if((e = ose_errno_get(vm_s))) \
{ \
ose_errno_set(bundle, e); \
ose_errno_set(vm_s, OSE_ERR_NONE); \
} \
}
ose_errno
Definition ose_errno.h:37
@ OSE_ERR_NONE
Definition ose_errno.h:38
#define ose_errno_get(b)
Get the errno for bundle b.
Definition ose_errno.h:169
#define OSEVM_STACK(osevm)
Get the stack bundle.
Definition ose_vm.h:368
Definition ose.h:374

Define the function OSEVM_WRAP_DECL declares.

Clears errno on the stack register, runs ose_<name>() on it, and if that set errno, moves the value to the machine and clears the register again – so a failure is reported where osevm_run() reads it, and a stale value from earlier is not charged to this call. The block comment above says why.

◆ OSEVM_WRAP_DEFPRED

#define OSEVM_WRAP_DEFPRED (   name)
Value:
void osevm_##name(ose_bundle bundle) \
{ \
ose_bundle vm_s = OSEVM_STACK(bundle); \
int32_t i; \
ose_errno_set(vm_s, OSE_ERR_NONE); \
i = ose_popInt32(vm_s); \
enum ose_errno e = OSE_ERR_NONE; \
if((e = ose_errno_get(vm_s))) \
{ \
ose_errno_set(bundle, e); \
ose_errno_set(vm_s, OSE_ERR_NONE); \
} \
bool r = ose_##name(i); \
ose_pushInt32(vm_s, r == true ? 1 : 0); \
}

Define osevm_<name>() for a predicate bool ose_<name>(int32_t).

Pops an int32 from the stack (a wrong type sets errno on the machine, as OSEVM_WRAP_DEFN does), calls the predicate with it, and pushes 1 or 0. Nothing in libose uses this macro today.

Function Documentation

◆ osevm_appendElemToRegister()

void osevm_appendElemToRegister ( ose_bundle  osevm)

Append the contents of the top element to a register – /<<.

With a three-character name on top, /<</_e, the name is dropped and the contents of the element then on top of the stack (a bundle) are appended to the named register, as ose_appendBundle() does. With six characters the second register is the source and the first the destination.

Precondition
As osevm_copyRegisterToElem, and the same errno values on violation. What ose_appendBundle() requires of the source element is not checked here.

◆ osevm_apply()

void osevm_apply ( ose_bundle  osevm)

Apply the top of the stack – the /! instruction, and the second half of osevm_funcall.

What happens depends on what is on top:

  • A bundle is run. A frame holding the input, environment and control is written to the dump with osevm_pushFrame (with /</_e already in the saved control, so that osevm_return hands the callee's environment back), the bundle's elements are moved into the input in reverse, and the control is cleared. If the dump has no room, nothing moves and errno is OSE_ERR_RANGE.
  • A message whose first item is an aligned pointer (OSETT_ALIGNEDPTR) is dropped and the pointer is called as an ose_fn with the machine.
  • A message whose first item is a wild pointer (OSETT_WILDPTR) is left alone and errno is OSE_ERR_WILDPTR_CALLED.
  • A message whose first item is a blob beginning #bundle is turned into a bundle element and applied as above.
  • Any other message is left where it is: applying a value gives the value.
Precondition
The stack has at least one element; otherwise errno is OSE_ERR_ELEM_COUNT and nothing happens. This is the case an unbound /!/name reaches, so it raises rather than asserting.

◆ osevm_assignStackToEnv()

void osevm_assignStackToEnv ( ose_bundle  osevm)

Bind the stack into the environment – the /@ instruction, and the default OSEVM_ASSIGN.

The address is the string on top. If its first OSE_REGISTER_ADDRESS_LEN characters name an existing register (/xy/rest), the rest is bound into that register instead, as ose_addressToRegister() decides. Then osevm_assignStackToEnv_impl with replace set, the message appended last, and bundles stored as blobs. See the registers document in o.se for the convention.

Precondition
As osevm_assignStackToEnv_impl.

◆ osevm_assignStackToEnv_impl()

void osevm_assignStackToEnv_impl ( ose_bundle  osevm,
ose_bundle  env,
int  replace,
int  new_msg_first,
char  bundle_typetag 
)

Bind everything on the stack, as one message, into a bundle.

The top of the stack is a message whose payload is the address to bind. Every element beneath it becomes part of one new message with that address: a message contributes its items, a bundle contributes one item of type bundle_typetag holding the bundle whole. The stack is cleared afterwards. This is osevm_assignStackToEnv without its register handling, for callers that choose the target bundle themselves.

Parameters
osevmThe machine.
envThe bundle to write the message into – the environment, or any other bundle.
replaceIf nonzero, every message already in env with the same address is removed first.
new_msg_firstIf nonzero the message is put at the start of env; otherwise at the end.
bundle_typetagThe typetag a bundle on the stack is stored under, OSETT_BLOB normally.
Precondition
The last element of the stack is a message, else errno is OSE_ERR_ELEM_TYPE and nothing changes. If env cannot grow by the size of the new message, ose_incSize() sets errno on env and the function returns with the stack still holding what it held.

◆ osevm_assignStackToRegister()

void osevm_assignStackToRegister ( ose_bundle  osevm)

Gather the stack into the bundle at its bottom, as one message named by the string on top.

The first element of the stack must be a bundle. Everything above it and below the topmost message is pushed into that bundle (bundles as blobs), then the string on top becomes the address of the message and it is pushed too. With exactly two elements – the bundle and one message – the message is pushed after its string, if it has one, is moved to the address.

Precondition
The first element is a bundle, else errno is OSE_ERR_ELEM_TYPE.
With more than two elements, the last is a message (OSE_ERR_ELEM_TYPE) whose last item is a string (OSE_ERR_ITEM_TYPE).
Todo:
No instruction dispatches to this and nothing in the tree calls it but the standard library's binding. What the bottom bundle is meant to be – a register, or any bundle – and why the two-element case differs is not recorded; no test covers it.

◆ osevm_copyElemToRegister()

void osevm_copyElemToRegister ( ose_bundle  osevm)

Copy the top element into a register.

As osevm_moveElemToRegister, with ose_copyElem() in place of ose_moveElem(): the element stays on the stack. No instruction sigil dispatches to this one; the standard library binds it.

Precondition
As osevm_copyRegisterToElem, and the same errno values on violation.

◆ osevm_copyRegisterToElem()

void osevm_copyRegisterToElem ( ose_bundle  osevm)

Copy a register onto the stack as one element – the /> instruction.

The top of the stack is a message holding one string, a register name. />/_e copies the whole environment onto the stack as a bundle element. Six characters name two registers, source then destination: the first is copied as an element onto the end of the second rather than onto the stack. On success the name is dropped.

Precondition
The last element of the stack is a message whose last item is a string of exactly OSE_REGISTER_ADDRESS_LEN or twice that many characters, naming registers that exist.

Otherwise nothing is moved, the name stays on the stack, and errno on the machine says why: OSE_ERR_ELEM_TYPE (not a message), OSE_ERR_ITEM_TYPE (not a string), OSE_ERR_ITEM_COUNT (wrong length) or OSE_ERR_UNKNOWN_CONTEXT_BUNDLE (no such register).

◆ osevm_dotimes()

void osevm_dotimes ( ose_bundle  osevm)

Execute a bundle repeatedly.

This function causes a bundle in the second to last position to be executed n times, where n is an integer in the last message of the bundle.

Precondition
the stack must contain at least two elements.
The last element of the stack must be a message.
The last message of the stack must contain exactly one non-negative integer.
The second to last element of the the stack must be a bundle.

◆ osevm_exec()

void osevm_exec ( ose_bundle  osevm)

Synonym for osevm_exec2.

Deprecated:

◆ osevm_exec1()

void osevm_exec1 ( ose_bundle  osevm)

Execute a bundle on the stack.

This function copies the current execution context (input, control, environment, and the stack), and executes the bundle on top of the stack.

The environment is not changed: the bundle runs in whatever environment is already current. osevm_exec2 installs a new one; that single difference is all that separates the two.

Precondition
The last element on the stack must be a bundle.
Warning
A binding made by the executed bundle does not survive the return. All three of these save the environment to the dump on the way in and restore it on the way out, so code invoked through them cannot write durably to the environment. That is why /o/finalize/toplevelexec exists, and why a host with re-entrant input needs a finalize hook of its own.

◆ osevm_exec2()

void osevm_exec2 ( ose_bundle  osevm)

Execute a bundle on the stack.

This function copies the current execution context (input, control, environment, and the stack), and executes the last bundle on the stack with the second to last as the environment.

Identical to osevm_exec1 except that the bundle below the one being executed is installed as the environment for the duration.

Precondition
The last two elements on the stack must be bundles.
Warning
A binding made by the executed bundle does not survive the return – see osevm_exec1.

◆ osevm_exec3()

void osevm_exec3 ( ose_bundle  osevm)

Execute a bundle on the stack.

This function copies the current execution context (input, control, environment, and the stack), and executes the last bundle on the stack with the second to last as the environment, and the third to last as the stack.

Identical to osevm_exec2 except that the executed bundle's contents are unpacked onto the stack rather than left packed.

Precondition
The last three elements on the stack must be bundles.
Warning
A binding made by the executed bundle does not survive the return – see osevm_exec1.

◆ osevm_funcall()

void osevm_funcall ( ose_bundle  osevm)

Look a name up and apply what it finds – the /! instruction on a string, and the default OSEVM_FUNCALL.

OSEVM_LOOKUP followed by osevm_apply. If the lookup finds nothing, the name is still on top and apply leaves it there (a message that is not a pointer or a bundle applies to itself), so with the default lookup an unbound call is silent.

Precondition
As osevm_lookupInEnv_impl.

◆ osevm_if()

void osevm_if ( ose_bundle  osevm)

Execute one of two bundles, depending on the value of the int in the last message on the stack.

This function expects three elements on the stack: the last element is the test, which must be a message containing a single integer. If the integer value is non-zero, the second to last bundle will be executed, otherwise the third to last bundle will be executed. The execution of the bundle proceeds according to osevm_exec1.

Precondition
The stack must contain at least three elements.
The last element of the stack must be a message.
The last element of the stack must contain exactly one integer.
The second to last and third to last elements must be bundles.

◆ osevm_lookupInEnv()

void osevm_lookupInEnv ( ose_bundle  osevm)

Call whatever OSEVM_LOOKUP names.

osevm_lookupInEnv_impl unless a build has overridden the hook. This is the one the standard library binds, so a program that calls lookup by name reaches the lookup the host chose.

◆ osevm_lookupInEnv_impl()

void osevm_lookupInEnv_impl ( ose_bundle  osevm)

Look a name up – the /$ instruction, and the default OSEVM_LOOKUP.

The top of the stack is a message holding an address. If the address begins with the name of an existing register, that register is searched first for the remainder; then the environment is searched for the whole address. The first element whose address matches – by ose_getFirstOffsetForMatch(), so OSC pattern matching applies – replaces the name on the stack with a copy of itself. If nothing matches, the name is left on the stack and errno is not set; a host that wants an unbound name to raise supplies its own OSEVM_LOOKUP.

Precondition
The last element of the stack is a message whose last item is a string. Not checked: ose_peekString() on anything else is undefined.

◆ osevm_makeRegister()

void osevm_makeRegister ( ose_bundle  osevm)

Create a register from a size and a name on the stack; the standard library binds it as /o/make/register.

The name is on top and the size beneath it. Calls ose_pushContextMessage() with them and, if it succeeds, drops the name.

Precondition
At least two elements (OSE_ERR_ELEM_COUNT); the second holds an int32 (OSE_ERR_ITEM_TYPE); the top holds a string (OSE_ERR_ITEM_TYPE). The name must be exactly OSE_REGISTER_ADDRESS_LEN characters and the size large enough: ose_pushContextMessage() checks both and refuses with errno set, and the name is then left on the stack so an exception handler can say which register was asked for. ut_ose_preconditions pins the refusal.

◆ osevm_map()

void osevm_map ( ose_bundle  osevm)

Apply a function to each item of a message, or each element of a bundle – /!/map.

The function is on top of the stack and the sequence beneath it. One step is taken per call: the next item (or element) and the function are arranged on the stack, /!/apply and /!/map are pushed onto the control, and the call returns, so the machine's own loop drives the iteration and results accumulate on the stack. When the sequence is exhausted both the sequence and the function are dropped.

Precondition
The stack has at least two elements – asserted under OSE_CONF_DEBUG, unchecked otherwise.
Todo:
For a bundle sequence the code walks the elements taking the first item of each into an accumulator bundle, and an element with no items abandons the whole map, dropping the sequence, the function and the accumulator; what the accumulated result is meant to look like, and whether that abandonment is intended, is not stated anywhere and no test covers this function.

◆ osevm_moveElemToRegister()

void osevm_moveElemToRegister ( ose_bundle  osevm)

Move the top element into a register – /-.

/-/_i drops the name and moves the element then on top of the stack onto the end of the input register, as ose_moveElem() does: the element itself, not its contents, so a bundle stays a bundle. Six characters name source and destination registers.

Precondition
As osevm_copyRegisterToElem, and the same errno values on violation.

◆ osevm_plookupInEnv()

void osevm_plookupInEnv ( ose_bundle  osevm)

Does nothing.

Todo:
The bindable form of osevm_plookupInEnv_impl; also empty. The standard library binds it, so a program that calls it gets no effect and no error.
Todo:
Implement.

◆ osevm_plookupInEnv_impl()

void osevm_plookupInEnv_impl ( ose_bundle  osevm)

Does nothing.

Todo:
A pattern-matching lookup, never implemented: the body is empty and nothing calls it.
Todo:
Implement.

◆ osevm_pushFrame()

int osevm_pushFrame ( ose_bundle  osevm,
int32_t  which,
const char *const  env,
int32_t  envlen 
)

Save registers to the dump as ONE element – whole, or not at all.

Parameters
osevmThe machine.
whichWhich registers to save: any of OSEVM_FRAME_INPUT, OSEVM_FRAME_ENV, OSEVM_FRAME_STACK, OSEVM_FRAME_CONTROL. A register named here but EMPTY is omitted, and a register not named is omitted too; osevm_return restores an omitted register as empty. That is how osevm_exec1 says "the stack slot is the callee's" – it has already moved the top of the stack into the input.
envBytes to put in the environment slot INSTEAD of /_e, as one OSC element – size word first. A client whose frames do not carry the whole environment puts the one binding its own repair needs here. NULL for the usual case. Ignored when OSEVM_FRAME_ENV is in which.
envlenThe length of env, its size word included.
Returns
1 if the frame was written. 0 if the dump had no room, in which case errno is set on the machine to OSE_ERR_RANGE – not on the register, which is a note nobody collects – and the dump is not touched.

Asks ose_spaceAvailable() rather than trying the grow. A refused ose_incSize() sets errno and declines in a release build, and asserts in a debug one, which is right for a size that is already wrong and wrong for a dump that is simply full – and the difference presents as an abort on a desktop and a silent decline on a board.

◆ osevm_quote()

void osevm_quote ( ose_bundle  bundle)

Does nothing – the ‘/’` instruction, and the default OSEVM_QUOTE.

The VM has already pushed the quoted text as a string before calling this; quoting needs nothing more. The hook exists so a host can give it a meaning.

◆ osevm_replaceRegisterWithElem()

void osevm_replaceRegisterWithElem ( ose_bundle  osevm)

Replace a register's contents with the top element's – /<.

/</_e drops the name and makes the environment a copy of the bundle then on top of the stack, as ose_replaceBundle() does; the element is consumed. Six characters name source and destination registers as osevm_appendElemToRegister does.

Precondition
As osevm_copyRegisterToElem, and the same errno values on violation. ut_ose_preconditions pins that a non-address on top sets errno and leaves the environment untouched.

◆ osevm_return()

void osevm_return ( ose_bundle  osevm)

Pop the topmost frame from the dump and restore what it carried – /!/return, and what the VM runs when the control empties inside a call.

The frame is unpacked in place and each register it carried is put back: the control is replaced; the saved stack, if any, goes underneath whatever the callee left; then the callee's environment is copied onto the stack as a bundle, and the saved environment and input are restored. A register the frame did not carry is restored empty. A frame is written whole by osevm_pushFrame, so the shape here is always the shape that was saved.

Precondition
The last element of the dump is a frame: a bundle whose header carries OSEVM_FRAME_MAGIC. Otherwise errno is OSE_ERR_ELEM_TYPE and nothing is touched – not four blind pops. ut_ose_preconditions pins that an empty dump is refused this way.

◆ osevm_version()

void osevm_version ( ose_bundle  osevm)

Push the library's version – /!/version.

Pushes ose_version_string() and ose_date_compiled_string() as two string messages, with ose_debug_string() between them in a build that defines OSE_DEBUG.