Instruction reference
All 199 instructions of bytecode format 9, with their operands and stack effect, in the order and groups the VM source lists them.
The bytecode is a stack machine. Every entry below gives the instruction as it is spelled in a disassembly, its operands (the values carried in the instruction itself), and its stack effect as [before] -> [after] with the top of the stack on the right, where the source states one. Jump targets are absolute program counters. The magic is FXVM and the format version is 9.
The prose is the doc comment from crates/foxvm/src/bytecode.rs, verbatim. The bytecode page explains the module around these and shows what real programs compile to.
statements
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Stmt | u32 | Statement boundary: records the current source line (and is the breakpoint hook). |
constants
[] -> [v]
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Const | u32 | ||
True | none | ||
False | none | ||
Null | none | ||
Omitted | none | The value of a skipped argument (f(1,,3)): .F. |
stack
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Pop | none | ||
Dup | none | ||
Nop | none |
variables
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
LoadLocal | u32 | [] -> [v] | |
StoreLocal | u32 | [v] -> [] | |
LoadName | u32 | Dynamic lookup: privates in this frame, then callers, then PUBLIC. [] -> [v] | |
StoreName | u32 | Dynamic store; an unknown name becomes a PRIVATE of the current frame. [v] -> [] | |
DeclLocal | u32 | Sets the slot to .F. (LOCAL declaration). | |
DeclPrivate | u32 | Declares a PRIVATE (hides any outer variable of that name) initialised to .F. | |
DeclPublic | u32 | Declares a PUBLIC initialised to .F. (keeps an existing value). | |
DeclareNamed | public: flag | [name] -> [] | PRIVATE (cName) / PUBLIC (cName): the same declaration for a name the program worked out when it ran. |
StoreByName | none | [value, name] -> [] | STORE x TO (cName): writes the value to whatever the name names - a variable, or a property some way down an object - which is only known when it runs. The name is read as a target and the value taken off the stack by the code compiled for it, so anything that can be assigned to can be named here. |
ParamToPrivate | arg: u32name: u32 | PARAMETERS-style: pops the n-th argument and stores it as a PRIVATE. [] -> [] | |
Dim | target: Varndims: byte | Creates an array in the target. [dims...] -> [] | |
LoadIndex | byte | [array, i (, j)] -> [v] | |
StoreIndex | byte | [v, array, i (, j)] -> [] | |
Ref | Var | Pushes a by-reference cell for the variable (converts it in place). [] -> [ref] | |
RefOrMakeArray | Var | The same, for a name that need not exist yet: an array function is handed the array it is to fill, and Visual FoxPro makes one when the program never declared it. [] -> [ref] | |
ReleaseName | u32 | Releases variables: RELEASE a, b. | |
ReleaseLocal | u32 | RELEASE of a LOCAL. A local lives in a numbered slot, so there is nowhere to take it from: the slot is marked instead, and reads as a variable that is not there until something writes it again. | |
ReleaseAll | none |
operators
[a, b] -> [r] / [a] -> [r]
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Neg | none | ||
Not | none | ||
Add | none | ||
Sub | none | ||
Mul | none | ||
Div | none | ||
Mod | none | ||
Pow | none | ||
Eq | none | ||
ExactEq | none | ||
Ne | none | ||
Lt | none | ||
Le | none | ||
Gt | none | ||
Ge | none | ||
Contains | none | ||
And | none | Three-valued AND/OR applied after the short-circuit jump kept the left operand. | |
Or | none |
control flow (targets are absolute pcs)
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Jump | u32 | ||
JumpIfFalse | u32 | Pops; jumps when .F. or NULL; errors on a non-logical. | |
JumpIfTrue | u32 | ||
JumpIfFalseKeep | u32 | Short-circuit for AND: peeks (never pops); jumps when the top is .F. The left operand stays on the stack either way, so a AND b compiles to a; JumpIfFalseKeep(end); b; And; end:. | |
JumpIfTrueKeep | u32 | Short-circuit for OR: peeks; jumps when the top is .T. | |
ForTest | u32 | FOR loop test. [var, end, step] -> [] ; jumps to the exit when the loop is finished. | |
ForEachNext | u32 | FOR EACH support: [array, index] -> [array, index+1, element]; at the end pops both and jumps to the exit. | |
ReturnTo | u32 | [] -> [] | RETURN TO: leave every routine between here and the one this names, which is the program the run started in when the name is empty (RETURN TO MASTER). |
calls
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
IndexOrCall | name: u32argc: byte | name(args): array element access when name resolves to an array, else a user function (this module, then loaded programs). [args...] -> [v] | |
CallBuiltin | id: u16argc: byte | Built-in function by id (see builtins::REGISTRY). [args...] -> [v] | |
Do | name: u32argc: bytein_prog: flagA program name went on the stack under the arguments. | DO name [WITH args] [IN prog]: procedure call as a statement. [args...] -> [] | |
DoDynamic | argc: bytein_prog: flagA program name went on the stack under the arguments. | [name, args...] -> [] | DO (cProgram): the name is computed, not written in the source. |
Return | none | [v] -> returns v to the caller (RETURN without a value pushes .T. first). | |
MakeLambda | u32 | LAMBDA(...) ... ENDLAMBDA: builds a function value out of the function at this index, the captured slots its proto lists, and the frame's THIS. [] -> [f] | |
IndexOrCallValue | byte | f(args) where f is a local: the value under the arguments is subscripted when it is an array and called when it is a function, which is the same question IndexOrCall asks about a name. [v, args...] -> [result] |
objects
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
LoadThis | none | ||
LoadThisForm | none | ||
LoadThisFormSet | none | THISFORMSET: the formset the object belongs to. A formset is a container whose members are whole forms, shown together, so this is not the form above the object but the thing above that; an object in no formset raises error 1938 rather than answering. | |
LoadScreen | none | ||
GetMember | u32 | [obj] -> [value or child object] | |
GetMemberByName | none | [obj, name] -> [value] | the same, for a member named by a variable: obj.&cName. |
SetMemberByName | none | obj.&cName = v: the member a variable names is written. [value, obj, name] -> [] | |
CallMethodByName | byte | [obj, name, a1 .. an] -> [value] | (yields HostRequest::CallMethod) for obj.&cName(...). |
SetMember | u32 | [v, obj] -> [] | (yields HostRequest::SetProp) |
SetMemberIndex | name: u32argc: byte | [v, obj, subs...] -> [] | (yields HostRequest::SetPropIndex) for obj.Prop[1] = v |
DimMember | name: u32ndims: byte | [obj, d1 .. dn] -> [] | (yields HostRequest::DimProp) for DIMENSION obj.aProp[2, 3]. Sizing an array property is its own instruction rather than an assignment of a fresh array, because the two are different statements: DIMENSION keeps the elements that still fit, and a plain assignment of an array to a property is not a way to give a property an array at all. |
CallMethod | name: u32argc: byte | [obj, args...] -> [v] | (yields HostRequest::CallMethod) |
PushWith | none | [obj] -> [] | pushes onto the WITH stack |
PopWith | none | ||
LoadWith | none | [] -> [obj] | |
ReleaseObject | none | [obj] -> [] | (yields HostRequest::ReleaseObject) |
DoMenu | u32 | DO menu.fxm: installs a menu. [] -> [] (yields HostRequest::DoMenu) |
runtime compilation
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Macro | none | &name in an expression: compiles the text on the stack as an expression in this frame. [text] -> [v] | |
ToText | none | TEXTMERGE <<expr>>: replaces the top of the stack with its display text. [v] -> [text] | |
MergeText | always: flag | Text merge: replaces the raw text on the stack with the same text, every expression between the merge delimiters worked out and put in its place. Which characters those delimiters are, and whether the merge happens at all, is what SET TEXTMERGE says at the time; always is the TEXTMERGE clause of TEXT, which merges whatever the setting says. [raw] -> [text] | |
TextOut | newline: flagnoshow: flag | \, \\ and a TEXT block with nowhere to go: sends the text on the stack to wherever SET TEXTMERGE TO points. newline ends the line before it first, and noshow is the command's own NOSHOW, which stops it also being shown. [text] -> [] |
statements with host effects
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Print | newline: flagargc: byte | ? / ??. [items...] -> [] | |
WaitWindow | byte | [text? , timeout?] -> [] | per wait_flags; TO var is a following StoreName. |
ReadEvents | none | ||
ClearEvents | none | ||
Quit | none | ||
Cancel | none | ||
DoForm | flags: byteargc: byte | [name, args...] -> [obj?, result?] | per form_flags. |
SetCmd | name: u32argc: byteto: flag | SET name ON|OFF|TO args. [args...] -> [] ; ON/OFF push True/False first. to says the command was the TO form. One setting can hold two things at once - SET HELP ON and SET HELP TO afile are both remembered, and SET("HELP") answers the first where SET("HELP", 1) answers the second - so which of them the command wrote has to travel with the instruction. The values alone cannot say. | |
NoDefault | none | ||
DoDefault | byte | [args...] -> [v] |
exceptions
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
TryPush | catch: u32finally: u32 | Installs a handler; either target may be NO_TARGET. On an error the VM unwinds to the stack depth at the push, then jumps to catch (installing a finally-only handler for the CATCH block) or, without CATCH, to finally with the error pending for EndFinally. | |
TryPop | none | Removes the innermost handler; when it has a FINALLY block a "no error pending" entry is recorded and the compiler jumps to the block next. | |
Erase | none | [path] -> [] | (yields HostRequest::FileDelete) for ERASE. |
Retry | none | Returns from this frame and runs the statement that called it again, for RETRY. | |
Throw | none | [v] -> raises a user error carrying v (a NULL re-raises the last caught error). | |
CatchObject | none | [] -> [exception object] | (yields HostRequest::CreateException) for CATCH TO oErr. |
EndFinally | none | End of a FINALLY block: re-raises the error that was propagating when the block was entered. | |
OnError | u32 or none | ON ERROR command: installs (Some(const)) or clears (None) the error handler text. |
data
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Use | alias: u32 or nonenamed_alias: flagAn alias went on the stack under the path, worked out when the statement ran.exclusive: flagonline: flagONLINE or ADMIN: the table opens, and then the command answers for what those two ask of it, which only an offline view can give.in_area: flagTrue when a work area was pushed under the path: USE x IN 0 opens the table somewhere else and leaves the selected area where it was. | [path] -> [] | USE table [ALIAS x] [EXCLUSIVE|SHARED] [AGAIN]; an empty path closes the work area. alias is the name index of an explicit ALIAS, if there was one. |
SelectArea | u32 or none | SELECT n / SELECT alias: name is a name index, or none when a number is on the stack. | |
Go | GoTarget | GO TOP / GO BOTTOM / GO n (the record number is on the stack for Record). | |
Skip | none | SKIP [n], with the count on the stack. | |
PushArea | none | [area] -> [] | The work area a command says IN: it is selected, and what was selected before is remembered so PopArea can put it back. |
PopArea | none | [] -> [] | The work area PushArea remembered, selected again. |
CloseTables | all: flag | USE with nothing open to close, or CLOSE TABLES/CLOSE ALL. | |
SetFound | none | [flag] -> [] | what FOUND() will report for the selected work area, after a LOCATE. |
ReplaceField | field: u32additive: flag | [value] -> [] | Changes one field of the record the pointer is on, in the page in hand. additive is REPLACE ... ADDITIVE, which adds to a memo field rather than replacing it. |
ReplaceFieldNamed | additive: flag | [name, value] -> [] | REPLACE (expr) WITH value: the field the name works out to. |
MarkDeleted | flag | [] -> [] | DELETE and RECALL: the flag at the front of the record. |
Zap | none | ZAP: empties the selected table. | |
FileCommand | byte | A file command: 1 COPY FILE, 2 RENAME, 3 MD, 4 RD, 5 DIR, 6 TYPE. Pops its names. | |
DeclareDll | u32 | DECLARE ... DLL: pops the library name and registers the declaration at that index. | |
EndOfCode | none | The routine ran out of statements: it returns the value on top of the stack, and stops there. A RETURN the program wrote goes further - out of a line a macro put together and out of the routine that line belongs to - so the two are not the same instruction. | |
ExecMacroText | u32 | A command with a macro in it, kept as the source text at that constant: every &name in it is replaced by the text that variable holds, and what comes out is compiled and run in this frame. | |
CreateTable | index: u32The definition in the module: the columns the new table has.from_array: flagcolumns: byteHow many column names went on the stack instead, worked out when it ran. | CREATE TABLE: pops a path and asks the host to write an empty table of the fields in Module::cursors at that index. With from_array the columns are described by an array on the stack under the path instead, and the module holds none. | |
CreateTableAllowed | none | [path] -> [logical] | Asks the open database whether a table of its own may be made: dbc_BeforeCreateTable, answering whether the statement is to go ahead. A .F. stops the whole of CREATE TABLE - no file is written and no work area taken - so the rest of the statement is jumped over rather than run. A free table never reaches this. |
RaiseError | none | ERROR: pops a message (or Omitted) and a number or text, and raises it. | |
AppendBlank | none | [] -> [] | APPEND BLANK: an empty record at the end, which the pointer moves to. |
InsertBlank | before: flag | [] -> [] | INSERT [BEFORE] [BLANK]: an empty record beside the one the pointer is on, with everything below it moved down one. The pointer ends on the new record. |
InsertFrom | from: byte0 an array, 1 a variable per field, 2 an object - as GATHER numbers them. | [source, row] -> [more, next] | One record of INSERT INTO ... FROM ARRAY | MEMVAR | NAME: appends a blank and fills it from that row of the source, then says whether another row follows and which it is. An array of two dimensions holds a record per row, so the statement loops over this; the other two sources have the one row. |
CreateCursorFromArray | index: u32The name written in the statement, when it was not worked out on the stack.named: flag | [array] -> [] | CREATE CURSOR name FROM ARRAY a: a cursor whose columns the array describes, in the shape AFIELDS() hands back. The name works the same way as CreateCursor's. |
FlushRecord | none | [] -> [] | Sends the changed record back to the host, if anything changed it. |
NewDocument | u32 | [path] -> [] | CREATE FORM, CREATE MENU and the rest: a new one of that kind, in its designer. The constant says which kind. |
Import | sheet: flag | IMPORT: the file is on the stack, with the sheet name over it when there is one. Reads the workbook, gathers the table it describes, and pushes where it is to go. | |
Build | what: u32count: u16recompile: flag | BUILD: the kind is a constant, the target and count sources are on the stack. | |
Compile | what: u32flags: byte | COMPILE: the kind is a constant and the file expression is on the stack. | |
ModifyInContainer | what: byteflags: u16NOWAIT and NOEDIT, which dbc_ModifyData is handed. | [path] -> [] | MODIFY TABLE, MODIFY VIEW, MODIFY PROCEDURE and MODIFY DATABASE: the designer for something the open database holds, which the database is told about either side of. 0 a table, 1 a view, 2 the stored procedures, 3 the database itself. |
Unsupported | u32 | [] -> [] | A command this runtime cannot honour: raises "Feature is not available" with the constant's text when the line is reached. It compiles, as it does in the product. |
Redefined | u32 | [] -> [] | Assigning to THIS, THISFORM, THISFORMSET or _SCREEN: "Cannot redefine X.", which the constant names. The line compiles, as it does in the product. |
OpenDocument | u32 | [path] -> [] | (yields HostRequest::OpenDocument) for MODIFY and BROWSE. The constant holds the word that followed MODIFY, because each kind of document brings its own extension when the name written has none: MODIFY DATABASE dvds opens dvds.dbc. |
LoadTablePath | none | [] -> [path] | The file behind the selected work area, for BROWSE. |
MakeArray | byte | [d1 .. dn] -> [array] | A fresh array of that shape, for DIMENSION of something that is not a variable: an array property, which is assigned to rather than declared. |
CreateCursor | index: u32The definition in the module: its columns, and the name it was written with.named: flagA name went on the stack instead, worked out when the statement ran.columns: byteHow many column names went on the stack too, under that name. | [] -> [] | CREATE CURSOR: an empty table of that shape, in a free work area. |
ReplaceFieldAt | byte | [value] -> [] | Changes the field at that position of the record the pointer is on, for an INSERT that gave its values in the table's own order. |
ClearAll | tables: flag | [] -> [] | CLEAR MEMORY and, with tables, CLEAR ALL. |
LoadField | area: u32 or nonefield: u32 | [] -> [value] | a field, or a member: area is a bare name the VM resolves - an object variable, the m. memory-variable prefix, or the alias of an open table. |
Blank | u32 | [] -> [] | BLANK: the fields of the record in hand go back to empty. The constant names the fields, a comma apart, or is empty for all of them. |
SELECT-SQL
The loops are ordinary bytecode; these four hold the query together.
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
SqlOpen | table: u32alias: u32named: flag | [name?] -> [] | Opens (or borrows) one FROM source and selects it. table is a constant and alias a name index; named says the name is on the stack instead, which is what FROM (cPath) compiles to. |
SelectSource | u16 | [] -> [] | Selects the work area of the query's nth FROM source. The source is named by where it is in the FROM clause rather than by what it is called, because a source named by an expression is only called something once it has been opened. |
JoinMiss | u16 | [] -> [] | The nth FROM source has no record matching the row being built, so it is parked past its last record and every field of it reads as .NULL. until it is moved again. That is what an outer join puts on the side that missed. |
SqlBegin | u32 | [top?] -> [] | Starts gathering rows for the plan at plan, expanding its * columns against the sources just opened. |
SqlRow | u16 | [v1 .. vn] -> [] | One gathered row: the column values, then the GROUP BY keys, then the ORDER BY keys. |
SqlEnd | none | [] -> [] | Folds, sorts and installs the result, then lets go of the sources. |
SqlHavingNext | none | [] -> [logical] | Folds the gathered rows the first time, then moves the HAVING clause on to the next group and says whether there is one. The three that follow are the loop the compiler emits between the gathering and SqlEnd: HAVING is an expression of the program's own, so it is run as bytecode, a group at a time. |
SqlHavingValue | u16 | [] -> [value] | The nth thing the plan's HAVING clause names, out of the group being asked about. |
SqlHavingKeep | none | [logical] -> [] | What the predicate came to for that group: keeps it or drops it. |
SqlSourceField | u32 | [] -> [value] | The field of that name in whichever of the query's sources has one, read from the record that source is on, or .NULL. when none of them has such a field. It is what a HAVING clause gathers for a name the select list gave with AS, since the name itself means nothing to a record but a field of the same name would shadow it. |
SqlRequireGroupBy | none | [] -> [] | Raises 1807 unless SET ENGINEBEHAVIOR 70 is in force. It stands in front of a query whose HAVING clause names an aggregate the select list has not got and which groups by nothing, which the older rules allow and the current ones do not. |
InCursor | u32 | [value] -> [logical] | Is the value one of those in the first column of that cursor: what IN (SELECT ...) and = ANY (SELECT ...) come to once the subquery has been run. |
indexes
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
OpenIndex | none | [] -> [] | Reads the compound index beside the table a USE has just opened, when the table's header says one sits there. |
SetOrder | descending: flag or none | [tag] -> [] | SET ORDER TO: a tag name, a tag number, or Omitted for record order. descending overrides the tag's own direction when the command said which way to go. |
Seek | none | [key] -> [] | SEEK: to the first record the controlling order holds under that key, or to end of file. FOUND() answers with whether it was there. |
IndexBegin | none | [path?, name, key, for, flags] -> [] | INDEX ON: starts gathering the keys of a new index. The flags are 1 UNIQUE, 2 CANDIDATE, 4 DESCENDING, 8 a single-entry index of its own rather than a tag, 16 COMPACT, 32 ADDITIVE; the path is there when 8 is set. |
IndexKey | none | [key] -> [] | One key of the tag being built, for the record the pointer is on. |
IndexEnd | none | [] -> [] | The tag is complete: it is sorted, becomes the controlling order, and the index is written back beside the table. |
DeleteTag | all: flag | [name] -> [] | DELETE TAG: that tag, or every tag, and the index is written back. |
Reindex | none | [] -> [] | REINDEX: writes the index back beside the table. |
OpenIdx | count: byte | [path...] -> [] | USE ... INDEX x, y: single-entry indexes opened beside the table, the first of them the controlling order. What SET INDEX TO does goes through set_cmd instead, so that the setting and the command stay one thing. |
CopyIndexes | count: byteall: flag | [path..., target] -> [] | COPY INDEXES: a tag per single-entry index, in the structural compound index or in the file the target names. all copies every index open beside the table and leaves the list empty. |
CopyTag | none | [tag, of, target] -> [] | COPY TAG: that tag of the compound index, or of the file of names, written out as a single-entry index of its own. |
tables, databases and transactions
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Unlock | record: flagarea: u32 or noneall: flag | [record?] -> [] | UNLOCK: one record, or everything the work area has locked. |
AlterTable | list of AlterStep | [path, names...] -> [] | ALTER TABLE: the table is read, given its new columns and written back. The names the program worked out sit above the path, in the order the changes were written. |
Transaction | byte | [] -> [] | A transaction: 0 begins one, 1 writes what it held, 2 throws it away. |
DbCommand | kind: bytenamed: flagA name was pushed for it.target: flagA second name was pushed, for a rename.sql: u32 or noneThe SELECT a view stands for, as a constant.flags: u16The clauses the command was written with, as crate::ast::db_flags bits: what the database event that goes with the command is handed. | [name?, target?] -> [] | A command that works on a database container. kind is 0 create, 1 open, 2 close, 3 set, 4 delete, 5 validate, 6 add a table, 7 remove one, 8 free one, 9 rename one, 10 create a view, 11 drop one, 12 list what is in it. |
listing, reports and browsing
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
ShowInfo | kind: byteskeleton: flagA LIKE skeleton is on the stack, narrowing what is listed to the names it matches. | [] -> [] | LIST and DISPLAY of something the runtime holds: 0 the structure of the table, 1 the variables, 2 the settings and work areas, 3 the files, 4 the database's tables, 5 its views, 6 the declared library functions, 7 the loaded programs, 8 the objects, 9 the connections. |
ListBegin | none | [] -> [] | A record listing is starting, so the row of field names is due. It is written above the first record there is to write and not before, because a LIST that matches nothing writes nothing at all. SET HEADINGS OFF means none is due. |
ListRecord | fields: u32numbers: flag | [] -> [] | One record, written out as LIST writes it. fields is a constant naming the fields the command asked for, a comma apart, or empty for every field of the table; numbers is false when the command said OFF, which drops the record-number column. |
ReportBegin | flags: bytelabel: flagto_file: flag | [path, file?] -> [] | REPORT FORM: reads the report file and starts it, writing the bands that print once at the top. flags is the statement's own. |
ReportRow | none | [] -> [] | One record of it: the detail band, worked out against the record the pointer is on. |
ReportEnd | none | [] -> [] | The bands that print once at the end, and the report goes where it was told. |
Browse | fields: u32 or nonecond: u32 or noneflags: bytetitled: flag | [title?] -> [] | BROWSE: the records of the work area go to the host, which shows them in a window of their own. The constant names the columns, a comma apart. |
events, memos and saved variables
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
OnEvent | what: u32given: flag | [command?] -> [] | The ON family: what it hangs off, and the command it hangs there. A command of nothing takes the one that was there away. |
Memo | what: bytefields: u32pathed: flagnamed: flagflags: byte | [field?, path?] -> [] | APPEND MEMO, COPY MEMO, MODIFY MEMO, CLOSE MEMO and APPEND GENERAL. The constant names the fields, a comma apart; named says the one field is on the stack instead, under the file, because the program worked its name out. |
Variables | save: flagmemo: flagskeleton: flagA skeleton went on the stack after the target.except: flagadditive: flag | [target, skeleton?] -> [] | SAVE TO and RESTORE FROM. |
input, windows and menus
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Mouse | clicks: byteat: flagAn AT position went on the stack first.drags: byteHow many DRAG TO positions followed it.window: flagA WINDOW name went on last.style: u32The words that came after, as one constant. | [row?, col?, drag rows and columns ...] -> [] | MOUSE: the pointer moves and presses. |
Ask | kind: byteprompted: flagtarget: u32The variable the answer goes into. | [prompt?] -> [] | INPUT, ACCEPT or GETEXPR: ask, and put the answer where the statement said. kind is 0 text, 1 worked out as an expression, 2 an expression kept as text. |
Run | nowait: flag | [command] -> [] | RUN: a command line handed to the operating system. |
Diagnostic | checked: flagargc: byte | [cond?, v1 .. vn] -> [] | ASSERT and DEBUGOUT. |
Yield | events: flag | [] -> [] | FLUSH and DOEVENTS: let the host catch up. |
Keyboard | plain: flagclear: flag | [keys] -> [] | KEYBOARD: keys into the buffer as if they had been typed. |
KeyStack | push: flagclear: flag | [] -> [] | PUSH KEY / POP KEY. |
Eject | none | [] -> [] | EJECT: the page ends here. |
WindowCommand | kind: bytegiven: byteOne bit each from the least significant: the name, the two corners and the title.text: u32 or noneflags: byte | [name?, r1?, c1?, r2?, c2?, title?] -> [] | A window command. kind says which one, and text the words that say how the window looks. |
AtCommand | kind: bytegiven: u16style: u32 or noneThe words that say how it is drawn, what a GET is called, and its two conditions.name: u32 or nonevalid: u32 or nonewhen: u32 or none | [row?, col?, value?, r2?, c2?, picture?, function?, amount?] -> [] | One thing an @ line draws. given is one bit each, in that order. |
MenuCommand | kind: bytegiven: byteWhich of the operands were pushed, one bit each from the least significant: the name, the OF, the number, the prompt, the key and the message.text: u32 or noneflags: byte | [name?, of?, number?, prompt?, key?, message?] -> [] | A menu command. kind says which one, and text the command a choice runs or the condition it is skipped for. |
copying, appending and aggregates
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Pack | none | [] -> [] | PACK: the table is read, the records that are left are written back from the top, and the header is told how many there are. |
AppendFrom | except: flagcount: u16cond: u32 or nonetext: byte0 a table, 1 fixed-width text, 2 comma-separated, 3 delimited. | [path, name1 .. nameN] -> [] | APPEND FROM: the file to read and which columns to take from it. cond is the FOR condition as written, or 0 when there is none. |
CopyBegin | kind: byteexcept: flagcount: u16descending: u32Which sort keys run backwards, one bit per key from the least significant.text: byte0 a table, 1 fixed-width text, 2 comma-separated, 3 delimited by what follows. | [path, name1 .. nameN] -> [] | COPY TO, SORT TO and TOTAL ON: the table to make and which of the columns go in it. kind is 0 records, 1 structure, 2 sorted, 3 totals. |
CopyRow | u16 | [key1 .. keyN] -> [] | One record for the copy: its keys, and the record itself. |
CopyEnd | none | [] -> [] | The copy is complete: the file is written. |
AggBegin | list of byte | [] -> [] | COUNT/SUM/AVERAGE/CALCULATE: starts one accumulator per column, each named by what it works out - 0 CNT, 1 SUM, 2 AVG, 3 MIN, 4 MAX, 5 STD, 6 VAR, 7 NPV. |
AggStep | u16 | [value] -> [] | One record's worth for the column at that index. NPV takes the rate and the flow, so it pops two. |
AggEnd | none | [] -> [array] | The columns worked out, in the order they were asked for. |
Scatter | to: byte0 an array, 1 a variable each, 2 an object.except: flagThe names are the fields to leave out rather than the ones to take.count: u16blank: flagBLANK: the shape of the record rather than what is in it. | [name1 .. nameN] -> [row?] | SCATTER: the record's fields, as an array or an object on the stack, or as a variable each. The field names named by FIELDS are on the stack, or none of them when the command named none. |
Gather | to: byteexcept: flagcount: u16 | [row?, name1 .. nameN] -> [] | GATHER: the other way, into the record in hand. |
SetFilter | u32 | [] -> [] | SET FILTER TO: the condition at that constant, empty for none. |
SetRelation | count: u16additive: flagoff: flag | [expr1, alias1, ...] -> [] | SET RELATION TO ... INTO ...: count pairs of expression text and work-area alias. off takes one relation away instead of setting them. |
the debugger
| Instruction | Operands | Stack | What it does |
|---|---|---|---|
Debug | DebugVerb | [] -> [] | SUSPEND and RESUME: hand the program over to the debugger, or take it back. |