go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

dev.texi (10543B)


      1 @node dev
      2 @chapter Developing with vise
      3 
      4 
      5 @section Code repository structure
      6 
      7 @table @code
      8 @item asm
      9 Assembly parser and compiler.
     10 @item cache
     11 Holds and manages all loaded content.
     12 @item engine
     13 Outermost interface. Orchestrates execution of bytecode against input. 
     14 @item lang
     15 Validation and specification of language context.
     16 @item logging
     17 Logging interface and build tags for loglevels.
     18 @item persist
     19 Interface and reference implementation of `state` and `cache` persistence across asynchronous vm executions.
     20 @item render
     21 Renders menu and templates, and enforces output size constraints.
     22 @item resource
     23 Retrieves data and bytecode from external symbols, and retrieves templates.
     24 @item state
     25 Holds the bytecode buffer, error states and navigation states.
     26 @item vm
     27 Defines instructions, and applies transformations according to the instructions.
     28 @end table
     29 
     30 
     31 @section Interacting with @code{vise}
     32 
     33 Implementers of @code{vise} should interface with the system using the @code{engine} module.
     34 
     35 The engine comes in two implementations, one volatile base implemetnation and a subclass that includes persistent state.
     36 
     37 
     38 @subsection Modes of operation
     39 
     40 The @code{engine} module provides three different modes of operation for the engine implementations.
     41 
     42 
     43 @subsubsection Manual operation
     44 
     45 Directly interaction with an @code{engine.Engine} instance.
     46 
     47 The engine is manually initialized, and execution must be explicitly triggered with input every time the VM yields control.
     48 
     49 Output flushing must also be operated manually.
     50 
     51 The interface is the same for both persistent and volatile operation.
     52 
     53 
     54 @subsubsection Synchronous loop
     55 
     56 Receives input from a reader and writes into to a writer, and executes the underlying @code{engine.Engine} with given inputs until execution is terminated.
     57 
     58 The loop may be either persistent or volatile.
     59 
     60 This mode drives the interactive driver execution tool. 
     61 
     62 
     63 @subsubsection Asynchronous one-shot
     64 
     65 Compatible with e.g. a network socket or HTTP frontend. The @code{engine.RunPersisted} method restores a persisted state and runs one single input until VM yield after which the new state is persisted.
     66 
     67 This mode of operation can only be used with persistent state.
     68 
     69 
     70 @subsection Configuration
     71 
     72 The engine configuration defines the top-level parameters for the execution environment, including maximum output size, default language, execution entry point and more.
     73 
     74 Please refer to @code{engine.Config} for details.
     75 
     76 
     77 @subsection Sessions
     78 
     79 The @code{engine.Config.SessionId} is used to disambiguate the end-user that is interacting with the engine.
     80 
     81 For example, in a @abbr{USSD} context, the @code{SessionId} may be the @emph{phone number} of the end-user.
     82 
     83 
     84 @anchor{execution_context}
     85 @subsection Execution context
     86 
     87 The engine stores the @code{SessionId} aswell as the current chosen @code{lang.Language} in the execution context. This is passed through to the VM operation, and is available for client code, specifically:
     88 
     89 @itemize
     90 @item When resolving symbols with @code{LOAD}. (@code{resource.EntryFunc}).
     91 @item When resolving menu symbols (@code{resource.Resource.GetMenu}).
     92 @item When retrieving node templates (@code{resource.Resource.GetTemplate}).
     93 @end itemize
     94 
     95 
     96 @section Resolving resources
     97 
     98 The core of implementation code is defined by implementing the @code{resource.Resource} interface. This is also described in the @ref{load_handler, LOAD handler} section.
     99 
    100 In addition to resolving external code symbols, @code{resource.Resource} implementations also translate @emph{menu labels} and @emph{templates} based on the current language context, and retrieves bytecode for execution nodes.
    101 
    102 @subsection Memory resource implementation
    103 
    104 One of two reference implementations of @code{resource.Resource} is the @code{resource.MemResource} class. It enables the client to register all node and symbol resolutions at runtime, using its functions prefixed with @code{Add...}. 
    105 
    106 The @code{resource.MemResource} implementation is primarily useful for use in tests.
    107 
    108 
    109 @subsection Filesystem resource implementation
    110 
    111 The Filesystem based resource implemementation is used by the @code{dev/interactive} tool, aswell as the executable examples in @file{examples/} directory.
    112 
    113 It is instantiated with a base directory location relative to which all resources are read.
    114 
    115 
    116 @subsubsection Bytecode (@code{resource.Resource.GetCode})
    117 
    118 Read from @file{basedir/<node>.bin}.
    119 
    120 
    121 @subsubsection Templates (@code{resource.Resource.GetTemplate})
    122 
    123 If language has been set, the template will be read from @file{basedir/<node>_<lang>}. For example, the @emph{norwegian} template for the node @code{root} will be read from @file{basedir/root_nor}.
    124 
    125 If reading the language specific template fails (or if no language has been set), template will be read from @file{basedir/<node>}.
    126 
    127 A missing template file will result in load failure and program termination.
    128 
    129 
    130 @subsubsection Menus (@code{resource.Resource.GetMenu})
    131 
    132 If language has been set, the template will be read from @file{basedir/<label>_<lang>_menu}. For example, the @emph{norwegian} template for the menu label @code{foo} will be read from @file{basedir/foo_nor_menu}.
    133 
    134 If reading the language specific menu label fails (or if no language has been set), label will be read from @file{basedir/<label>_menu}.
    135 
    136 If this also fails, the implementation returns the original label used for lookup.
    137 
    138 
    139 @subsubsection External symbols (@code{resource.Resource.FuncFor})
    140 
    141 The implementation allows setting resolver functions for symbols at runtime, using the @code{resource.FsResource.AddLocalFunc} method. This registers an @code{resource.FsResource.EntryFunc} with the lookup symbol as key. Note that the @code{EntryFunc} receives the language setting through the execution context.
    142 
    143 If no function has been registered for the requested symbol, it will be looked up in the filesystem on @file{basedir/<symbol>_<lang>.txt}. For example, the @emph{norwegian} entry for the symbol @code{foo} will be read from @file{basedir/foo_nor.txt}.
    144 
    145 If reading the language specific entry fails (or if no language has been set), entry will be read from @file{basedir/<symbol>.txt}.
    146 
    147 A missing entry will result in load failure and program termination.
    148 
    149 The implementation contains no built-in handling of the @code{SessionId} supplied by the context.
    150 
    151 
    152 @section Logging
    153 
    154 Loglevels are set at compile-time using the following build tags:
    155 
    156 @itemize
    157 @item @code{lognone}
    158 @item @code{logerror}
    159 @item @code{logwarn}
    160 @item @code{loginfo}
    161 @item @code{logdebug}
    162 @item @code{logtrace}
    163 @end itemize
    164 
    165 Only use @strong{ONE} of these tags.
    166 
    167 The default tag is @code{lognone} which disables logging completely.
    168 
    169 @code{logging.Logger} defines the logging interface. It is faintly inspired by the experimental @url{https://pkg.go.dev/golang.org/x/exp/slog) package, in that it differentiates explicit context logging, slog}.
    170 
    171 
    172 @section Tools
    173 
    174 Located in the @file{dev/} directory of the source code repository. 
    175 
    176 
    177 @subsection Test data generation
    178 
    179 @example
    180 go run ./dev/gendata/ <directory>
    181 @end example
    182 
    183 Outputs bytecodes and templates for test data scenarios used in `engine` unit tests.
    184 
    185 
    186 @subsection Interactive runner
    187 
    188 @example
    189 go run ./dev/interactive [-d <data_directory>] [--root <root_symbol>] [--session-id <session_id>] [--persist]
    190 @end example
    191 
    192 Creates a new interactive session using @code{engine.DefaultEngine}, starting execution at symbol @code{root_symbol}
    193 
    194 @code{data_directory} points to a directory where templates and bytecode is to be found (in the same format as generated by @file{dev/gendata}).
    195 
    196 If @code{data_directory} is not set, current directory will be used.
    197 
    198 if @code{root_symbol} is not set, the symbol @code{root} will be used.
    199 
    200 if @code{session_id} is set, mutable data will be stored and retrieved keyed by the given identifer (if implemented).
    201 
    202 If @code{persist} is set, the execution state will be persisted across sessions.
    203 
    204 
    205 @subsection Assembler
    206 
    207 @example
    208 go run ./dev/asm <assembly_file>
    209 @end example
    210 
    211 Will output bytecode on STDOUT generated from a valid assembly file.
    212 
    213 
    214 @subsection Disassembler
    215 
    216 @example
    217 go run ./dev/disasm/ <binary_file>
    218 @end example
    219 
    220 Will list all the instructions on STDOUT from a valid binary file.
    221 
    222 
    223 @subsection Interactive case examples
    224 
    225 Found in @file{examples/}.
    226 
    227 Be sure to @code{make examples} before running them.
    228 
    229 Can be run with:
    230 
    231 @example
    232 go run ./examples/<case> [...]
    233 @end example
    234 
    235 except helloworld which is run as
    236 
    237 @example
    238 go run ./dev/interactive -d ./examples/helloworld [...]
    239 @end example
    240 
    241 The available options are the same as for the @file{dev/interactive} tool.
    242 
    243 Contents of the case directory:
    244 
    245 @table @file
    246 @item *.vis
    247 assembly code.
    248 @item *.bin
    249 bytecode for each node symbol (only available after make).
    250 @item *.txt.orig
    251 default contents of a single data entry.
    252 @item *.txt
    253 current contents of a single data entry (only available after make).
    254 @end table
    255 
    256 
    257 @section Assembly examples
    258 
    259 See @file{testdata/*.vis}
    260 
    261 
    262 @section Bytecode example
    263 
    264 Currently the following rules apply for encoding in version @code{0}:
    265 
    266 @itemize
    267 @item A code instruction is a @emph{big-endian} 2-byte value. See @file{vm/opcodes.go} for valid opcode values.
    268 @item @code{symbol} value is encoded as @emph{one byte} of string length, after which the  byte-value of the string follows.
    269 @item @code{size} value is encoded as @emph{one byte} of numeric length, after which the @emph{big-endian} byte-value of the integer follows.
    270 @item @code{signal} value is encoded as @emph{one byte} of byte length, after which a byte-array representing the defined signal follows.
    271 @end itemize
    272 
    273 
    274 @subsection Example
    275 
    276 (Minimal, WIP)
    277 
    278 @verbatim
    279 000a 03666f6f 05746f666f6f    # MOUT tofoo foo  - display a menu entry for choice "foo", described by "to foo"
    280 0008 03666f6f 03626172        # INCMP bar foo   - move to node "bar" if input is "FOO"
    281 0001 0461696565 01 01         # CATCH aiee 1 1  - move to node "aiee" (and immediately halt) if input match flag (1) is not set (1)
    282 0003 04616263 020104          # LOAD abc 260    - execute code symbol "abc" with a result size limit of 260 (2 byte BE integer, 0x0104)
    283 0003 04646566 00              # LOAD def 0      - execute code symbol "abc" with no size limit (sink)
    284 0005 04616263                 # MAP abc         - make "abc" available for renderer
    285 0007                          # HALT            - stop execution (require new input to continue)
    286 0006 0461313233               # MOVE a123       - move to node "a123" (regardless of input)
    287 0007                          # HALT            - stop execution
    288 @end verbatim