# The MIT License (MIT)
#
# Copyright (C) 2026 Scott Duensing
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

.section Libraries
.topic lib.basrt
.title BASIC Runtime Library
.toc 0 BASIC Runtime Library
.index BASIC Runtime
.index BasVmT
.index BasValueT
.index BasStringT
.index BasArrayT
.index BasModuleT

.h1 BASIC Runtime Library

Stack-based p-code virtual machine and value system for DVX BASIC. Embeddable: the host provides I/O and UI callbacks. No DVX GUI dependencies in the core runtime.

Headers: apps/dvxbasic/runtime/vm.h, apps/dvxbasic/runtime/values.h

.link lib.basrt.values Value System (values.h)
.link lib.basrt.vm Virtual Machine (vm.h)

.topic lib.basrt.values
.title Value System
.toc 1 Value System
.index BasValueT
.index BasStringT
.index BasArrayT
.index BasUdtT
.index basStringNew
.index basArrayNew
.index basValCopy
.index basValRelease

.h1 Value System

Tagged union value type for the VM evaluation stack, variables, and array elements. Strings, arrays, and UDT instances are reference-counted for automatic memory management without a garbage collector.

Header: apps/dvxbasic/runtime/values.h

.h2 Type Tags

.table
  Constant         Value   C Union Field   Description
  --------         -----   -------------   -----------
  BAS_TYPE_INTEGER 0       intVal          16-bit signed integer.
  BAS_TYPE_LONG    1       longVal         32-bit signed integer.
  BAS_TYPE_SINGLE  2       sngVal          32-bit float.
  BAS_TYPE_DOUBLE  3       dblVal          64-bit float.
  BAS_TYPE_STRING  4       strVal          Reference-counted dynamic string.
  BAS_TYPE_BOOLEAN 5       boolVal         True (-1) or False (0).
  BAS_TYPE_ARRAY   6       arrVal          Reference-counted array.
  BAS_TYPE_UDT     7       udtVal          Reference-counted user-defined type.
  BAS_TYPE_OBJECT  8       objVal          Opaque host pointer (form, control).
  BAS_TYPE_REF     9       refVal          ByRef pointer to a BasValueT slot.
.endtable

.h2 BasValueT

Tagged union holding any BASIC value.

.code
struct BasValueTag {
    uint8_t type;   // BAS_TYPE_*
    union {
        int16_t     intVal;
        int32_t     longVal;
        float       sngVal;
        double      dblVal;
        BasStringT *strVal;
        int16_t     boolVal;
        BasArrayT  *arrVal;
        BasUdtT    *udtVal;
        void       *objVal;
        BasValueT  *refVal;
    };
};
.endcode

.h2 Value Constructors

.code
BasValueT basValInteger(int16_t v);
BasValueT basValLong(int32_t v);
BasValueT basValSingle(float v);
BasValueT basValDouble(double v);
BasValueT basValString(BasStringT *s);
BasValueT basValStringFromC(const char *text);
BasValueT basValBool(bool v);
BasValueT basValObject(void *obj);
.endcode

Each returns a BasValueT with the appropriate type tag set. basValString increments the string's reference count.

.h2 Value Lifetime

.code
BasValueT basValCopy(BasValueT v);
void      basValRelease(BasValueT *v);
.endcode

.table
  Function       Description
  --------       -----------
  basValCopy     Copy a value. Increments reference count for strings, arrays, and UDTs.
  basValRelease  Release a value. Decrements reference count and frees if it reaches zero.
.endtable

.h2 Type Conversion

.code
BasValueT basValToInteger(BasValueT v);
BasValueT basValToLong(BasValueT v);
BasValueT basValToSingle(BasValueT v);
BasValueT basValToDouble(BasValueT v);
BasValueT basValToString(BasValueT v);
BasValueT basValToBool(BasValueT v);
.endcode

Each returns a new value of the target type. The original is not released; the caller manages both lifetimes.

.h2 Value Utilities

.table
  Function                          Description
  --------                          -----------
  basValToNumber(v)                 Convert any numeric value to double.
  basValFormatString(v)             Return a new ref-counted string representation of v.
  basValIsTruthy(v)                 True if non-zero number or non-empty string.
  basValCompare(a, b)               Compare two values. Returns -1, 0, or 1.
  basValCompareCI(a, b)             Case-insensitive comparison (OPTION COMPARE TEXT).
  basValPromoteType(a, b)           Determine common type for binary ops (e.g. Integer + Single -> Single).
.endtable

.h2 BasStringT

Reference-counted string with flexible array member for inline storage.

.code
typedef struct {
    int32_t refCount;
    int32_t len;
    int32_t cap;
    char    data[];
} BasStringT;
.endcode

.h3 String Functions

.table
  Function                            Description
  --------                            -----------
  basStringNew(text, len)             Allocate from a C string. refCount starts at 1.
  basStringAlloc(cap)                 Allocate an empty string with given capacity.
  basStringRef(s)                     Increment reference count. Returns s.
  basStringUnref(s)                   Decrement reference count. Frees when it reaches zero.
  basStringConcat(a, b)               Concatenate two strings. Returns a new string (refCount 1).
  basStringSub(s, start, len)         Extract a substring. Returns a new string (refCount 1).
  basStringCompare(a, b)              Compare. Returns <0, 0, >0 (like strcmp).
  basStringCompareCI(a, b)            Case-insensitive compare.
  basStringSystemInit()               Initialize the string system and empty string singleton.
  basStringSystemShutdown()           Shut down the string system.
.endtable

The global basEmptyString is a singleton that is never freed.

.h2 BasArrayT

Reference-counted multi-dimensional array (up to BAS_ARRAY_MAX_DIMS = 8 dimensions).

.code
typedef struct {
    int32_t    refCount;
    uint8_t    elementType;
    int32_t    dims;
    int32_t    lbound[BAS_ARRAY_MAX_DIMS];
    int32_t    ubound[BAS_ARRAY_MAX_DIMS];
    int32_t    totalElements;
    BasValueT *elements;
} BasArrayT;
.endcode

.h3 Array Functions

.table
  Function                                  Description
  --------                                  -----------
  basArrayNew(dims, lbounds, ubounds, type) Allocate an array. refCount starts at 1.
  basArrayFree(arr)                         Free all elements and release the array.
  basArrayRef(arr)                          Increment reference count.
  basArrayUnref(arr)                        Decrement reference count. Frees at zero.
  basArrayIndex(arr, indices, ndims)        Compute flat index from multi-dimensional indices. Returns -1 if out of bounds.
.endtable

.h2 BasUdtT

Reference-counted user-defined type instance.

.code
typedef struct {
    int32_t    refCount;
    int32_t    typeId;
    int32_t    fieldCount;
    BasValueT *fields;
} BasUdtT;
.endcode

.h3 UDT Functions

.table
  Function                          Description
  --------                          -----------
  basUdtNew(typeId, fieldCount)     Allocate a UDT instance. refCount starts at 1.
  basUdtFree(udt)                   Free all fields and release.
  basUdtRef(udt)                    Increment reference count.
  basUdtUnref(udt)                  Decrement reference count. Frees at zero.
.endtable

.topic lib.basrt.vm
.title Virtual Machine
.toc 1 Virtual Machine
.index BasVmT
.index BasModuleT
.index BasVmResultE
.index basVmCreate
.index basVmRun
.index basVmStep
.index basVmDestroy
.index basVmCallSub

.h1 Virtual Machine

Stack-based p-code interpreter. Executes compiled BASIC bytecode modules. The host provides I/O, UI, SQL, and external library callbacks. The VM has no DVX dependencies; it can be embedded in any C program.

Header: apps/dvxbasic/runtime/vm.h

.h2 VM Limits

.table
  Constant                Value   Description
  --------                -----   -----------
  BAS_VM_STACK_SIZE       256     Evaluation stack depth.
  BAS_VM_CALL_STACK_SIZE  64      Maximum call nesting depth.
  BAS_VM_MAX_GLOBALS      512     Global variable slots.
  BAS_VM_MAX_LOCALS       64      Local variables per stack frame.
  BAS_VM_MAX_FOR_DEPTH    32      Maximum nested FOR loop depth.
  BAS_VM_MAX_FILES        16      Open file channels (1-based).
.endtable

.h2 BasVmResultE

Result codes returned by basVmRun and basVmStep.

.table
  Code                    Value   Description
  ----                    -----   -----------
  BAS_VM_OK               0       Program completed normally.
  BAS_VM_HALTED           1       HALT instruction reached.
  BAS_VM_YIELDED          2       DoEvents yielded control.
  BAS_VM_ERROR            3       Runtime error.
  BAS_VM_STACK_OVERFLOW   4       Evaluation stack overflow.
  BAS_VM_STACK_UNDERFLOW  5       Evaluation stack underflow.
  BAS_VM_CALL_OVERFLOW    6       Call stack overflow.
  BAS_VM_DIV_BY_ZERO      7       Division by zero.
  BAS_VM_TYPE_MISMATCH    8       Type mismatch in operation.
  BAS_VM_OUT_OF_MEMORY    9       Memory allocation failed.
  BAS_VM_BAD_OPCODE       10      Unknown opcode encountered.
  BAS_VM_FILE_ERROR       11      File I/O error.
  BAS_VM_SUBSCRIPT_RANGE  12      Array subscript out of range.
  BAS_VM_USER_ERROR       13      ON ERROR raised by program.
  BAS_VM_STEP_LIMIT       14      Step limit reached (not an error).
  BAS_VM_BREAKPOINT       15      Breakpoint or step completed (not an error).
.endtable

.h2 Lifecycle

.code
BasVmT *basVmCreate(void);
void    basVmDestroy(BasVmT *vm);
void    basVmLoadModule(BasVmT *vm, BasModuleT *module);
void    basVmReset(BasVmT *vm);
.endcode

.table
  Function         Description
  --------         -----------
  basVmCreate      Allocate and initialize a new VM instance.
  basVmDestroy     Destroy the VM and free all resources.
  basVmLoadModule  Load a compiled module (BasModuleT) into the VM.
  basVmReset       Reset to initial state (clear stack, globals, PC).
.endtable

.h2 Execution

.code
BasVmResultE basVmRun(BasVmT *vm);
BasVmResultE basVmStep(BasVmT *vm);
void         basVmSetStepLimit(BasVmT *vm, int32_t limit);
.endcode

.table
  Function           Description
  --------           -----------
  basVmRun           Execute the loaded module until it ends, halts, yields, errors, or hits a breakpoint/step limit.
  basVmStep          Execute a single instruction and return. Useful for debugger stepping.
  basVmSetStepLimit  Set maximum instructions per basVmRun call. 0 = unlimited (default). Returns BAS_VM_STEP_LIMIT when reached.
.endtable

.h2 I/O Callbacks

The host provides these callbacks for PRINT, INPUT, and DoEvents statements.

.code
void basVmSetPrintCallback(BasVmT *vm, BasPrintFnT fn, void *ctx);
void basVmSetInputCallback(BasVmT *vm, BasInputFnT fn, void *ctx);
void basVmSetDoEventsCallback(BasVmT *vm, BasDoEventsFnT fn, void *ctx);
.endcode

.h3 Callback Types

.code
typedef void (*BasPrintFnT)(void *ctx, const char *text, bool newline);
typedef bool (*BasInputFnT)(void *ctx, const char *prompt,
    char *buf, int32_t bufSize);
typedef bool (*BasDoEventsFnT)(void *ctx);
.endcode

.table
  Type             Description
  ----             -----------
  BasPrintFnT      Called for PRINT output. text is null-terminated. newline indicates line advance.
  BasInputFnT      Called for INPUT. Fill buf (up to bufSize-1 chars). Return true on success, false on cancel.
  BasDoEventsFnT   Called for DoEvents. Process pending events and return. Return false to stop the program.
.endtable

.h2 UI Callbacks

For form and control integration. The VM resolves all UI operations through these callbacks, keeping it independent of any specific GUI toolkit.

.code
void basVmSetUiCallbacks(BasVmT *vm, const BasUiCallbacksT *ui);
.endcode

.h3 BasUiCallbacksT

.table
  Field         Signature                                            Description
  -----         ---------                                            -----------
  getProp       BasValueT (*)(ctx, ctrlRef, propName)                Get a control property value.
  setProp       void (*)(ctx, ctrlRef, propName, value)              Set a control property.
  callMethod    BasValueT (*)(ctx, ctrlRef, methodName, args, argc)  Call a method on a control.
  createCtrl    void *(*)(ctx, formRef, typeName, ctrlName)          Create a control on a form.
  findCtrl      void *(*)(ctx, formRef, ctrlName)                    Find a control by name.
  findCtrlIdx   void *(*)(ctx, formRef, ctrlName, index)             Find a control array element.
  loadForm      void *(*)(ctx, formName)                             Load a form by name.
  unloadForm    void (*)(ctx, formRef)                               Unload a form.
  showForm      void (*)(ctx, formRef, modal)                        Show a form (modal or modeless).
  hideForm      void (*)(ctx, formRef)                               Hide a form (keep in memory).
  msgBox        int32_t (*)(ctx, message, flags)                     Display a message box.
  inputBox      BasStringT *(*)(ctx, prompt, title, defaultText)     Display an input box.
  ctx           void *                                               User pointer passed to all callbacks.
.endtable

.h2 SQL Callbacks

For database integration.

.code
void basVmSetSqlCallbacks(BasVmT *vm, const BasSqlCallbacksT *sql);
.endcode

.h3 BasSqlCallbacksT

.table
  Field           Signature                                  Description
  -----           ---------                                  -----------
  sqlOpen          int32_t (*)(path)                          Open a database. Returns handle.
  sqlClose         void (*)(db)                               Close a database.
  sqlExec          bool (*)(db, sql)                          Execute a non-query SQL statement.
  sqlError         const char *(*)(db)                        Get last error message.
  sqlQuery         int32_t (*)(db, sql)                       Execute a query. Returns result set handle.
  sqlNext          bool (*)(rs)                               Advance to next row.
  sqlEof           bool (*)(rs)                               Check if at end of result set.
  sqlFieldCount    int32_t (*)(rs)                            Get number of columns.
  sqlFieldName     const char *(*)(rs, col)                   Get column name by index.
  sqlFieldText     const char *(*)(rs, col)                   Get column value as text by index.
  sqlFieldByName   const char *(*)(rs, name)                  Get column value as text by name.
  sqlFieldInt      int32_t (*)(rs, col)                       Get column value as integer.
  sqlFieldDbl      double (*)(rs, col)                        Get column value as double.
  sqlFreeResult    void (*)(rs)                               Free a result set.
  sqlAffectedRows  int32_t (*)(db)                            Get number of rows affected by last statement.
.endtable

.h2 External Library Callbacks

For DECLARE LIBRARY support. The VM resolves external functions at runtime via the host.

.code
void basVmSetExternCallbacks(BasVmT *vm,
    const BasExternCallbacksT *ext);
.endcode

.h3 BasExternCallbacksT

.table
  Field           Signature                                                Description
  -----           ---------                                                -----------
  resolveExtern   void *(*)(ctx, libName, funcName)                        Resolve a native function by library and symbol name. Cached after first call.
  callExtern      BasValueT (*)(ctx, funcPtr, funcName, args, argc, retType) Call a resolved native function, marshalling arguments and return value.
  ctx             void *                                                   User pointer passed to both callbacks.
.endtable

.h2 Form Context

Set the active form context during event dispatch.

.code
void basVmSetCurrentForm(BasVmT *vm, void *formRef);
void basVmSetCurrentFormVars(BasVmT *vm,
    BasValueT *vars, int32_t count);
.endcode

.h2 Stack Access

Push and pop values on the evaluation stack for host integration.

.code
bool basVmPush(BasVmT *vm, BasValueT val);
bool basVmPop(BasVmT *vm, BasValueT *val);
.endcode

Both return true on success, false on stack overflow/underflow.

.h2 Error Reporting

.code
const char *basVmGetError(const BasVmT *vm);
.endcode

Returns the current error message string. Valid after basVmRun returns BAS_VM_ERROR.

.h2 Sub/Function Calls from Host

Call a SUB or FUNCTION by its code address from host code.

.code
bool basVmCallSub(BasVmT *vm, int32_t codeAddr);
bool basVmCallSubWithArgs(BasVmT *vm, int32_t codeAddr,
    const BasValueT *args, int32_t argCount);
bool basVmCallSubWithArgsOut(BasVmT *vm, int32_t codeAddr,
    const BasValueT *args, int32_t argCount,
    BasValueT *outArgs, int32_t outCount);
.endcode

.table
  Function                Description
  --------                -----------
  basVmCallSub            Call a SUB with no arguments.
  basVmCallSubWithArgs    Call a SUB with arguments pushed onto the stack frame.
  basVmCallSubWithArgsOut Call a SUB and read back modified argument values after it returns.
.endtable

All three push a call frame, execute until the SUB returns, then restore the previous execution state. Return true on normal completion, false on error or if the VM is not idle.

.h2 Debugger API

.code
void    basVmSetBreakpoints(BasVmT *vm,
            int32_t *lines, int32_t count);
void    basVmStepInto(BasVmT *vm);
void    basVmStepOver(BasVmT *vm);
void    basVmStepOut(BasVmT *vm);
void    basVmRunToCursor(BasVmT *vm, int32_t line);
int32_t basVmGetCurrentLine(const BasVmT *vm);
.endcode

.table
  Function              Description
  --------              -----------
  basVmSetBreakpoints   Set the breakpoint list (sorted array of source line numbers, host-owned memory).
  basVmStepInto         Break at the next OP_LINE instruction.
  basVmStepOver         Break when call depth returns to the current level.
  basVmStepOut          Break when call depth drops below the current level.
  basVmRunToCursor      Break when execution reaches the specified source line.
  basVmGetCurrentLine   Get the current source line number (from the last OP_LINE instruction).
.endtable

The breakpoint callback notifies the host when a breakpoint fires during nested sub calls:

.code
typedef void (*BasBreakpointFnT)(void *ctx, int32_t line);
.endcode

.h2 BasModuleT

Compiled module produced by the BASIC compiler and loaded into the VM.

.code
typedef struct {
    uint8_t          *code;
    int32_t           codeLen;
    BasStringT      **constants;
    int32_t           constCount;
    int32_t           globalCount;
    int32_t           entryPoint;
    BasValueT        *dataPool;
    int32_t           dataCount;
    BasProcEntryT    *procs;
    int32_t           procCount;
    BasFormVarInfoT  *formVarInfo;
    int32_t           formVarInfoCount;
    BasDebugVarT     *debugVars;
    int32_t           debugVarCount;
    BasDebugUdtDefT  *debugUdtDefs;
    int32_t           debugUdtDefCount;
} BasModuleT;
.endcode

.table
  Field              Description
  -----              -----------
  code               P-code bytecode array.
  codeLen            Length of bytecode in bytes.
  constants          String constant pool.
  constCount         Number of string constants.
  globalCount        Number of global variable slots needed.
  entryPoint         PC of the first instruction (module-level code).
  dataPool           DATA statement value pool (for READ).
  dataCount          Number of values in the data pool.
  procs              Procedure table (SUBs and FUNCTIONs).
  procCount          Number of procedures.
  formVarInfo        Per-form variable counts and init code addresses.
  formVarInfoCount   Number of forms with form-scoped variables.
  debugVars          Variable names and metadata for the debugger.
  debugVarCount      Number of debug variable entries.
  debugUdtDefs       UDT type definitions for the debugger.
  debugUdtDefCount   Number of debug UDT definitions.
.endtable
