mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
WIP, adjusting architecture, read more
The 'source' directory compiles, but the repl and tests are almost
untouched so far. There's no guarantee that the code in 'source' is
correct, so I'm branching this for a short time, until I'm confident the
whole project passes the CI again.
I'm adjusting the concepts of routines and bytecode to make them more
consistent, and tweaking the VM so it loads from an instance of
'Toy_Module'.
* 'Toy_ModuleBuilder' (formally 'Toy_Routine')
This is where the AST is compiled, producing a chunk of memory that can
be read by the VM. This will eventually operate on individual
user-defined functions as well.
* 'Toy_ModuleBundle' (formally 'Toy_Bytecode')
This collects one or more otherwise unrelated modules into one chunk of
memory, stored in sequence. It is also preprended with the version data for
Toy's reference implementation:
For each byte in the bytecode:
0th: TOY_VERSION_MAJOR
1st: TOY_VERSION_MINOR
2nd: TOY_VERSION_PATCH
3rd: (the number of modules in the bundle)
4th and onwards: TOY_VERSION_BUILD
TOY_VERSION_BUILD has always been a null terminated C-string, but from
here on, it begins at the word-alignment, and continues until the first
word-alignment after the null terminator.
As for the 3rd byte listed, since having more than 256 modules in one
bundle seems unlikely, I'm storing the count here, as it was otherwise
unused. This is a bit janky, but it works for now.
* 'Toy_Module'
This new structure represents a single complete unit of operation, such
as a single source file, or a user-defined function. It is divided into
three main sections, with various sub-sections.
HEADER (all members are unsigned ints):
total module size in bytes
jumps count
param count
data count
subs count
code addr
jumps addr (if jumps count > 0)
param addr (if param count > 0)
data addr (if data count > 0)
subs addr (if subs count > 0)
BODY:
<raw opcodes, etc.>
DATA:
jumps table
uint array, pointing to addresses in 'data' or 'subs'
param table
uint array, pointing to addresses in 'data'
data
heterogeneous data, including strings
subs
an array of modules, using recursive logic
The reference implementation as a whole uses a lot of recursion, so this
makes sense.
The goal of this rework is so 'Toy_Module' can be added as a member of
'Toy_Value', as a simple and logical way to handle functions. I'll
probably use the union pattern, similarly to Toy_String, so functions
can be written in C and Toy, and used without needing to worry which is
which.
This commit is contained in:
2
.notes/README.md
Normal file
2
.notes/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
This folder is full of development notes, and are probably out of date. Check the actual docs for the correct info.
|
||||||
|
|
||||||
@@ -40,26 +40,26 @@ Additional information may be added later, or multiple 'modules' listed sequenti
|
|||||||
|
|
||||||
.header:
|
.header:
|
||||||
N total size # size of this routine, including all data and subroutines
|
N total size # size of this routine, including all data and subroutines
|
||||||
N .param count # the number of parameter fields expected
|
|
||||||
N .jumps count # the number of entries in the jump table (should be data count + routine count)
|
N .jumps count # the number of entries in the jump table (should be data count + routine count)
|
||||||
|
N .param count # the number of parameter fields expected
|
||||||
N .data count # the number of data fields expected
|
N .data count # the number of data fields expected
|
||||||
N .routine count # the number of routines present
|
N .routine count # the number of routines present
|
||||||
.param start # absolute addess of .param; omitted if not needed
|
|
||||||
.code start # absolute address of .code; mandatory
|
.code start # absolute address of .code; mandatory
|
||||||
|
.param start # absolute addess of .param; omitted if not needed
|
||||||
.datatable start # absolute address of .datatable; omitted if not needed
|
.datatable start # absolute address of .datatable; omitted if not needed
|
||||||
.data start # absolute address of .data; omitted if not needed
|
.data start # absolute address of .data; omitted if not needed
|
||||||
.routine start # absolute address of .routine; omitted if not needed
|
.routine start # absolute address of .routine; omitted if not needed
|
||||||
# additional metadata fields can be added later
|
# additional metadata fields can be added later
|
||||||
|
|
||||||
.param:
|
|
||||||
# a list of symbols to be used as keys in the environment
|
|
||||||
|
|
||||||
.code:
|
.code:
|
||||||
# instructions read and 'executed' by the interpreter
|
# instructions read and 'executed' by the interpreter
|
||||||
READ 0
|
READ 0
|
||||||
LOAD 0
|
LOAD 0
|
||||||
ASSERT
|
ASSERT
|
||||||
|
|
||||||
|
.param:
|
||||||
|
# a list of symbols to be used as keys in the environment
|
||||||
|
|
||||||
.jumptable:
|
.jumptable:
|
||||||
# a 'symbol -> pointer' jumptable for quickly looking up values in .data and .routines
|
# a 'symbol -> pointer' jumptable for quickly looking up values in .data and .routines
|
||||||
0 -> {string, 0x00}
|
0 -> {string, 0x00}
|
||||||
@@ -71,4 +71,3 @@ Additional information may be added later, or multiple 'modules' listed sequenti
|
|||||||
|
|
||||||
.routines:
|
.routines:
|
||||||
# inner routines, each of which conforms to this spec
|
# inner routines, each of which conforms to this spec
|
||||||
|
|
||||||
|
|||||||
@@ -80,3 +80,4 @@ API:
|
|||||||
# Notes
|
# Notes
|
||||||
|
|
||||||
* Scopes, buckets, strings, etc. will persist until the root VM is cleared
|
* Scopes, buckets, strings, etc. will persist until the root VM is cleared
|
||||||
|
* The parameters are...
|
||||||
@@ -325,7 +325,7 @@ int repl(const char* filepath) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_ModuleBundle bc = Toy_compileModuleBundle(ast);
|
||||||
Toy_bindVM(&vm, &bc);
|
Toy_bindVM(&vm, &bc);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
@@ -333,7 +333,7 @@ int repl(const char* filepath) {
|
|||||||
|
|
||||||
//free the bytecode, and leave the VM ready for the next loop
|
//free the bytecode, and leave the VM ready for the next loop
|
||||||
Toy_resetVM(&vm);
|
Toy_resetVM(&vm);
|
||||||
Toy_freeBytecode(bc);
|
Toy_freeModuleBundle(bc);
|
||||||
|
|
||||||
printf("%s> ", prompt); //shows the terminal prompt
|
printf("%s> ", prompt); //shows the terminal prompt
|
||||||
}
|
}
|
||||||
@@ -473,7 +473,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_ModuleBundle bc = Toy_compileModuleBundle(ast);
|
||||||
|
|
||||||
//run the setup
|
//run the setup
|
||||||
Toy_VM vm;
|
Toy_VM vm;
|
||||||
@@ -491,7 +491,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeVM(&vm);
|
Toy_freeVM(&vm);
|
||||||
Toy_freeBytecode(bc);
|
Toy_freeModuleBundle(bc);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
free(source);
|
free(source);
|
||||||
}
|
}
|
||||||
|
|||||||
25
source/toy.h
25
source/toy.h
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
//general utilities
|
|
||||||
#include "toy_common.h"
|
|
||||||
#include "toy_console_colors.h"
|
|
||||||
#include "toy_print.h"
|
|
||||||
|
|
||||||
//basic structures
|
|
||||||
#include "toy_bucket.h"
|
|
||||||
#include "toy_string.h"
|
|
||||||
#include "toy_value.h"
|
|
||||||
#include "toy_array.h"
|
|
||||||
#include "toy_stack.h"
|
|
||||||
#include "toy_table.h"
|
|
||||||
|
|
||||||
//IR structures and other components
|
|
||||||
#include "toy_ast.h"
|
|
||||||
#include "toy_routine.h"
|
|
||||||
|
|
||||||
//pipeline
|
|
||||||
#include "toy_lexer.h"
|
|
||||||
#include "toy_parser.h"
|
|
||||||
#include "toy_bytecode.h"
|
|
||||||
#include "toy_vm.h"
|
|
||||||
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
#include "toy_bytecode.h"
|
|
||||||
#include "toy_console_colors.h"
|
|
||||||
|
|
||||||
#include "toy_routine.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
//utils
|
|
||||||
static void expand(Toy_Bytecode* bc, unsigned int amount) {
|
|
||||||
if (bc->count + amount > bc->capacity) {
|
|
||||||
|
|
||||||
while (bc->count + amount > bc->capacity) { //expand as much as needed
|
|
||||||
bc->capacity = bc->capacity < 8 ? 8 : bc->capacity * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bc->ptr = realloc(bc->ptr, bc->capacity);
|
|
||||||
|
|
||||||
if (bc->ptr == NULL) {
|
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a 'Toy_Bytecode' of %d capacity\n" TOY_CC_RESET, (int)(bc->capacity));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void emitByte(Toy_Bytecode* bc, unsigned char byte) {
|
|
||||||
expand(bc, 1);
|
|
||||||
bc->ptr[bc->count++] = byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
//bytecode
|
|
||||||
static void writeBytecodeHeader(Toy_Bytecode* bc) {
|
|
||||||
emitByte(bc, TOY_VERSION_MAJOR);
|
|
||||||
emitByte(bc, TOY_VERSION_MINOR);
|
|
||||||
emitByte(bc, TOY_VERSION_PATCH);
|
|
||||||
|
|
||||||
//check strlen for the build string
|
|
||||||
const char* build = Toy_private_version_build();
|
|
||||||
size_t len = strlen(build) + 1;
|
|
||||||
|
|
||||||
//BUGFIX: ensure the end of the header has 4-byte alignment
|
|
||||||
if (len % 4 != 1) { //1 to fill the 4th byte above
|
|
||||||
len += 4 - (len % 4) +1; //ceil
|
|
||||||
}
|
|
||||||
|
|
||||||
expand(bc, len);
|
|
||||||
memcpy(bc->ptr + bc->count, build, len);
|
|
||||||
bc->count += len;
|
|
||||||
|
|
||||||
bc->ptr[bc->count] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void writeBytecodeBody(Toy_Bytecode* bc, Toy_Ast* ast) {
|
|
||||||
//a 'module' is a routine that runs at the root-level of a file
|
|
||||||
//since routines can be recursive, this distinction is important
|
|
||||||
//eventually, the bytecode may support multiple modules packed into one file
|
|
||||||
void* module = Toy_compileRoutine(ast);
|
|
||||||
|
|
||||||
//don't try writing an empty module
|
|
||||||
if (module == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = (size_t)(((int*)module)[0]);
|
|
||||||
|
|
||||||
expand(bc, len);
|
|
||||||
memcpy(bc->ptr + bc->count, module, len);
|
|
||||||
bc->count += len;
|
|
||||||
bc->moduleCount++;
|
|
||||||
|
|
||||||
free(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
//exposed functions
|
|
||||||
Toy_Bytecode Toy_compileBytecode(Toy_Ast* ast) {
|
|
||||||
//setup
|
|
||||||
Toy_Bytecode bc;
|
|
||||||
|
|
||||||
bc.ptr = NULL;
|
|
||||||
bc.capacity = 0;
|
|
||||||
bc.count = 0;
|
|
||||||
|
|
||||||
bc.moduleCount = 0;
|
|
||||||
|
|
||||||
//build
|
|
||||||
writeBytecodeHeader(&bc);
|
|
||||||
writeBytecodeBody(&bc, ast); //TODO: implement module packing (multiple modules in one package)
|
|
||||||
|
|
||||||
return bc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_freeBytecode(Toy_Bytecode bc) {
|
|
||||||
free(bc.ptr);
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "toy_common.h"
|
|
||||||
#include "toy_ast.h"
|
|
||||||
|
|
||||||
typedef struct Toy_Bytecode {
|
|
||||||
unsigned char* ptr;
|
|
||||||
unsigned int capacity;
|
|
||||||
unsigned int count;
|
|
||||||
|
|
||||||
unsigned int moduleCount;
|
|
||||||
} Toy_Bytecode;
|
|
||||||
|
|
||||||
TOY_API Toy_Bytecode Toy_compileBytecode(Toy_Ast* ast);
|
|
||||||
TOY_API void Toy_freeBytecode(Toy_Bytecode bc);
|
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
#define TOY_BITNESS -1
|
#define TOY_BITNESS -1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//bytecode version specifiers, embedded as the header
|
//version specifiers, embedded as the header
|
||||||
#define TOY_VERSION_MAJOR 2
|
#define TOY_VERSION_MAJOR 2
|
||||||
#define TOY_VERSION_MINOR 0
|
#define TOY_VERSION_MINOR 0
|
||||||
#define TOY_VERSION_PATCH 0
|
#define TOY_VERSION_PATCH 0
|
||||||
@@ -56,3 +56,13 @@
|
|||||||
#define TOY_VERSION_BUILD Toy_private_version_build()
|
#define TOY_VERSION_BUILD Toy_private_version_build()
|
||||||
TOY_API const char* Toy_private_version_build(void);
|
TOY_API const char* Toy_private_version_build(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Version validation rules:
|
||||||
|
|
||||||
|
* Under no circumstance, should you ever run code whose major version is different from the interpreter’s major version
|
||||||
|
* Under no circumstance, should you ever run code whose minor version is above the interpreter’s minor version
|
||||||
|
* You may, at your own risk, attempt to run code whose patch version is different from the interpreter’s patch version
|
||||||
|
* You may, at your own risk, attempt to run code whose build version is different from the interpreter’s build version
|
||||||
|
|
||||||
|
*/
|
||||||
|
|||||||
40
source/toy_module.c
Normal file
40
source/toy_module.c
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include "toy_module.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
static inline unsigned int readUnsignedInt(unsigned char** handle) {
|
||||||
|
unsigned int i = *((unsigned int*)(*handle));
|
||||||
|
(*handle) += 4;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Module Toy_parseModule(unsigned char* ptr) {
|
||||||
|
Toy_Module module;
|
||||||
|
|
||||||
|
module.scopePtr = NULL;
|
||||||
|
|
||||||
|
module.code = ptr;
|
||||||
|
|
||||||
|
//header
|
||||||
|
readUnsignedInt(&ptr);
|
||||||
|
// module.codeCount = readUnsignedInt(&ptr); NOTE: note used
|
||||||
|
module.jumpsCount = readUnsignedInt(&ptr);
|
||||||
|
module.paramCount = readUnsignedInt(&ptr);
|
||||||
|
module.dataCount = readUnsignedInt(&ptr);
|
||||||
|
module.subsCount = readUnsignedInt(&ptr);
|
||||||
|
|
||||||
|
module.codeAddr = readUnsignedInt(&ptr);
|
||||||
|
if (module.jumpsCount) {
|
||||||
|
module.jumpsAddr = readUnsignedInt(&ptr);
|
||||||
|
}
|
||||||
|
if (module.paramCount) {
|
||||||
|
module.paramAddr = readUnsignedInt(&ptr);
|
||||||
|
}
|
||||||
|
if (module.dataCount) {
|
||||||
|
module.dataAddr = readUnsignedInt(&ptr);
|
||||||
|
}
|
||||||
|
if (module.subsCount) {
|
||||||
|
module.subsAddr = readUnsignedInt(&ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return module;
|
||||||
|
}
|
||||||
27
source/toy_module.h
Normal file
27
source/toy_module.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "toy_common.h"
|
||||||
|
#include "toy_scope.h"
|
||||||
|
|
||||||
|
//runtime module info
|
||||||
|
typedef struct Toy_Module {
|
||||||
|
//closure support - points to parent scope
|
||||||
|
Toy_Scope* scopePtr;
|
||||||
|
|
||||||
|
unsigned char* code;
|
||||||
|
|
||||||
|
//extracted metadata
|
||||||
|
// unsigned int codeCount; //NOTE: not used
|
||||||
|
unsigned int jumpsCount;
|
||||||
|
unsigned int paramCount;
|
||||||
|
unsigned int dataCount;
|
||||||
|
unsigned int subsCount;
|
||||||
|
|
||||||
|
unsigned int codeAddr;
|
||||||
|
unsigned int jumpsAddr;
|
||||||
|
unsigned int paramAddr;
|
||||||
|
unsigned int dataAddr;
|
||||||
|
unsigned int subsAddr;
|
||||||
|
} Toy_Module;
|
||||||
|
|
||||||
|
TOY_API Toy_Module Toy_parseModule(unsigned char* ptr);
|
||||||
1163
source/toy_module_builder.c
Normal file
1163
source/toy_module_builder.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
|||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "toy_ast.h"
|
#include "toy_ast.h"
|
||||||
|
|
||||||
//the 'escapes' are lists of data used for processing the 'break' and 'continue' keywords, and can be safely ignored
|
//the 'escapes' are lists of data used for processing the 'break' and 'continue' keywords
|
||||||
typedef struct Toy_private_EscapeEntry_t {
|
typedef struct Toy_private_EscapeEntry_t {
|
||||||
unsigned int addr; //the address to write *to*
|
unsigned int addr; //the address to write *to*
|
||||||
unsigned int depth; //the current depth
|
unsigned int depth; //the current depth
|
||||||
@@ -26,12 +26,8 @@ typedef struct Toy_private_EscapeArray {
|
|||||||
|
|
||||||
TOY_API void* Toy_private_resizeEscapeArray(Toy_private_EscapeArray* ptr, unsigned int capacity);
|
TOY_API void* Toy_private_resizeEscapeArray(Toy_private_EscapeArray* ptr, unsigned int capacity);
|
||||||
|
|
||||||
//internal structure that holds the individual parts of a compiled routine
|
//structure for holding the module as it is built
|
||||||
typedef struct Toy_Routine {
|
typedef struct Toy_ModuleBuilder {
|
||||||
unsigned char* param; //c-string params in sequence (could be moved below the jump table?)
|
|
||||||
unsigned int paramCapacity;
|
|
||||||
unsigned int paramCount;
|
|
||||||
|
|
||||||
unsigned char* code; //the instruction set
|
unsigned char* code; //the instruction set
|
||||||
unsigned int codeCapacity;
|
unsigned int codeCapacity;
|
||||||
unsigned int codeCount;
|
unsigned int codeCount;
|
||||||
@@ -40,23 +36,27 @@ typedef struct Toy_Routine {
|
|||||||
unsigned int jumpsCapacity;
|
unsigned int jumpsCapacity;
|
||||||
unsigned int jumpsCount;
|
unsigned int jumpsCount;
|
||||||
|
|
||||||
unsigned char* data; //data for longer stuff
|
unsigned char* param; //each 'param' is the starting address of a name string within 'data'
|
||||||
|
unsigned int paramCapacity;
|
||||||
|
unsigned int paramCount;
|
||||||
|
|
||||||
|
unsigned char* data; //a block of read-only data
|
||||||
unsigned int dataCapacity;
|
unsigned int dataCapacity;
|
||||||
unsigned int dataCount;
|
unsigned int dataCount;
|
||||||
|
|
||||||
unsigned char* subs; //subroutines, recursively
|
unsigned char* subs; //submodules, built recursively
|
||||||
unsigned int subsCapacity;
|
unsigned int subsCapacity;
|
||||||
unsigned int subsCount;
|
unsigned int subsCount;
|
||||||
|
|
||||||
|
//TODO: duplicate string reuse, see #168
|
||||||
|
|
||||||
|
//tools for handling the build process
|
||||||
unsigned int currentScopeDepth;
|
unsigned int currentScopeDepth;
|
||||||
Toy_private_EscapeArray* breakEscapes;
|
Toy_private_EscapeArray* breakEscapes;
|
||||||
Toy_private_EscapeArray* continueEscapes;
|
Toy_private_EscapeArray* continueEscapes;
|
||||||
|
|
||||||
bool panic; //any issues found at this point are compilation errors
|
//compilation errors
|
||||||
} Toy_Routine;
|
bool panic;
|
||||||
|
} Toy_ModuleBuilder;
|
||||||
|
|
||||||
TOY_API void* Toy_compileRoutine(Toy_Ast* ast);
|
TOY_API void* Toy_compileModuleBuilder(Toy_Ast* ast);
|
||||||
|
|
||||||
//URGENT: Rename routines to ModuleBuilder
|
|
||||||
//URGENT: Rename bytecode to ModuleBundler
|
|
||||||
//URGENT: Compiled code is a "module"
|
|
||||||
168
source/toy_module_bundle.c
Normal file
168
source/toy_module_bundle.c
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
#include "toy_module_bundle.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
#include "toy_module_builder.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//utils
|
||||||
|
static void expand(Toy_ModuleBundle* bundle, unsigned int amount) {
|
||||||
|
if (bundle->count + amount > bundle->capacity) {
|
||||||
|
bundle->capacity = 0;
|
||||||
|
|
||||||
|
while (bundle->count + amount > bundle->capacity) { //expand as much as needed
|
||||||
|
bundle->capacity >>= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle->ptr = realloc(bundle->ptr, bundle->capacity);
|
||||||
|
|
||||||
|
if (bundle->ptr == NULL) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a 'Toy_ModuleBundle' of %d capacity\n" TOY_CC_RESET, (int)(bundle->capacity));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitByte(Toy_ModuleBundle* bundle, unsigned char byte) {
|
||||||
|
expand(bundle, 1);
|
||||||
|
bundle->ptr[bundle->count++] = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeModuleBundleHeader(Toy_ModuleBundle* bundle) {
|
||||||
|
emitByte(bundle, TOY_VERSION_MAJOR);
|
||||||
|
emitByte(bundle, TOY_VERSION_MINOR);
|
||||||
|
emitByte(bundle, TOY_VERSION_PATCH);
|
||||||
|
emitByte(bundle, 0); //module count
|
||||||
|
|
||||||
|
//get the build string
|
||||||
|
const char* build = Toy_private_version_build();
|
||||||
|
size_t len = strlen(build) + 1; //includes null
|
||||||
|
|
||||||
|
//emit the build string
|
||||||
|
expand(bundle, len);
|
||||||
|
strncpy((char*)(bundle->ptr + bundle->count), build, len);
|
||||||
|
bundle->count += len;
|
||||||
|
|
||||||
|
//align the count
|
||||||
|
bundle->count = (bundle->count + 3) & ~3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int validateModuleBundleHeader(Toy_ModuleBundle* bundle) {
|
||||||
|
if (bundle->ptr[0] != TOY_VERSION_MAJOR || bundle->ptr[1] > TOY_VERSION_MINOR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bundle->ptr[2] != TOY_VERSION_PATCH) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp((char*)(bundle->ptr + 4), TOY_VERSION_BUILD) != 0) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//exposed functions
|
||||||
|
void Toy_initModuleBundle(Toy_ModuleBundle* bundle) {
|
||||||
|
bundle->ptr = NULL;
|
||||||
|
bundle->capacity = 0;
|
||||||
|
bundle->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_appendModuleBundle(Toy_ModuleBundle* bundle, Toy_Ast* ast) {
|
||||||
|
//probably some inefficincies in memory usage here
|
||||||
|
if (bundle->capacity == 0) {
|
||||||
|
writeModuleBundleHeader(bundle); //TODO: update the header?
|
||||||
|
}
|
||||||
|
|
||||||
|
//increment the module count
|
||||||
|
if (bundle->ptr[3] < 255) {
|
||||||
|
bundle->ptr[3]++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Too many modules in a bundle\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* module = Toy_compileModuleBuilder(ast);
|
||||||
|
|
||||||
|
//don't try writing an empty module
|
||||||
|
if (module == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//write the module to the bundle
|
||||||
|
size_t len = (size_t)(((int*)module)[0]);
|
||||||
|
|
||||||
|
expand(bundle, len);
|
||||||
|
memcpy(bundle->ptr + bundle->count, module, len);
|
||||||
|
bundle->count += len;
|
||||||
|
|
||||||
|
free(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_freeModuleBundle(Toy_ModuleBundle* bundle) {
|
||||||
|
free(bundle->ptr);
|
||||||
|
Toy_initModuleBundle(bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_bindModuleBundle(Toy_ModuleBundle* bundle, unsigned char* ptr, unsigned int size) {
|
||||||
|
if (bundle == NULL) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't bind a NULL bundle\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bundle->ptr != NULL || bundle->capacity != 0 || bundle->count != 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't bind a bundle with pre-existing contents\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy
|
||||||
|
expand(bundle, size);
|
||||||
|
|
||||||
|
memcpy(bundle->ptr, ptr, size);
|
||||||
|
bundle->count = size;
|
||||||
|
|
||||||
|
//URGENT: test this
|
||||||
|
int valid = validateModuleBundleHeader(bundle);
|
||||||
|
|
||||||
|
if (valid < 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Wrong version info found in module header: expected %d.%d.%d.%s found %d.%d.%d.%s, exiting\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD, bundle->ptr[0], bundle->ptr[1], bundle->ptr[2], (char*)(bundle->ptr + 4));
|
||||||
|
exit(valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid > 0) {
|
||||||
|
fprintf(stderr, TOY_CC_WARN "WARNING: Wrong version info found in module header: expected %d.%d.%d.%s found %d.%d.%d.%s, continuing\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD, bundle->ptr[0], bundle->ptr[1], bundle->ptr[2], (char*)(bundle->ptr + 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Module Toy_extractModuleFromBundle(Toy_ModuleBundle* bundle, unsigned char index) {
|
||||||
|
if (bundle == NULL) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't extract from a NULL bundle\n" TOY_CC_RESET);
|
||||||
|
return (Toy_Module){ 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bundle->ptr == NULL) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't extract from an empty bundle\n" TOY_CC_RESET);
|
||||||
|
return (Toy_Module){ 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
//yes, it's a bit awkward
|
||||||
|
char* buildPtr = (char*)(bundle->ptr + 4);
|
||||||
|
int buildLen = strlen(buildPtr);
|
||||||
|
buildLen = (buildLen + 3) & ~3;
|
||||||
|
|
||||||
|
//first module's start position
|
||||||
|
unsigned char* moduleHead = bundle->ptr + 4 + buildLen;
|
||||||
|
|
||||||
|
for (unsigned char i = 0; i < index; i++) {
|
||||||
|
unsigned int size = *((int*)(moduleHead));
|
||||||
|
moduleHead += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read in the module
|
||||||
|
return Toy_parseModule(moduleHead);
|
||||||
|
}
|
||||||
20
source/toy_module_bundle.h
Normal file
20
source/toy_module_bundle.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "toy_common.h"
|
||||||
|
#include "toy_ast.h"
|
||||||
|
#include "toy_module.h"
|
||||||
|
|
||||||
|
typedef struct Toy_ModuleBundle {
|
||||||
|
unsigned char* ptr;
|
||||||
|
unsigned int capacity;
|
||||||
|
unsigned int count;
|
||||||
|
} Toy_ModuleBundle;
|
||||||
|
|
||||||
|
//create a bundle
|
||||||
|
TOY_API void Toy_initModuleBundle(Toy_ModuleBundle* bundle);
|
||||||
|
TOY_API void Toy_appendModuleBundle(Toy_ModuleBundle* bundle, Toy_Ast* ast);
|
||||||
|
TOY_API void Toy_freeModuleBundle(Toy_ModuleBundle* bundle);
|
||||||
|
|
||||||
|
//load module bundle with external data (makes an internal copy)
|
||||||
|
TOY_API void Toy_bindModuleBundle(Toy_ModuleBundle* bundle, unsigned char* ptr, unsigned int size);
|
||||||
|
TOY_API Toy_Module Toy_extractModuleFromBundle(Toy_ModuleBundle* bundle, unsigned char index);
|
||||||
1160
source/toy_routine.c
1160
source/toy_routine.c
File diff suppressed because it is too large
Load Diff
196
source/toy_vm.c
196
source/toy_vm.c
@@ -10,16 +10,16 @@
|
|||||||
|
|
||||||
//utilities
|
//utilities
|
||||||
#define READ_BYTE(vm) \
|
#define READ_BYTE(vm) \
|
||||||
vm->module[vm->programCounter++]
|
vm->code[vm->programCounter++]
|
||||||
|
|
||||||
#define READ_UNSIGNED_INT(vm) \
|
#define READ_UNSIGNED_INT(vm) \
|
||||||
*((unsigned int*)(vm->module + readPostfixUtil(&(vm->programCounter), 4)))
|
*((unsigned int*)(vm->code + readPostfixUtil(&(vm->programCounter), 4)))
|
||||||
|
|
||||||
#define READ_INT(vm) \
|
#define READ_INT(vm) \
|
||||||
*((int*)(vm->module + readPostfixUtil(&(vm->programCounter), 4)))
|
*((int*)(vm->code + readPostfixUtil(&(vm->programCounter), 4)))
|
||||||
|
|
||||||
#define READ_FLOAT(vm) \
|
#define READ_FLOAT(vm) \
|
||||||
*((float*)(vm->module + readPostfixUtil(&(vm->programCounter), 4)))
|
*((float*)(vm->code + readPostfixUtil(&(vm->programCounter), 4)))
|
||||||
|
|
||||||
static inline int readPostfixUtil(unsigned int* ptr, int amount) {
|
static inline int readPostfixUtil(unsigned int* ptr, int amount) {
|
||||||
int ret = *ptr;
|
int ret = *ptr;
|
||||||
@@ -66,10 +66,10 @@ static void processRead(Toy_VM* vm) {
|
|||||||
int len = (int)READ_BYTE(vm); //only needed for name strings
|
int len = (int)READ_BYTE(vm); //only needed for name strings
|
||||||
|
|
||||||
//grab the jump as an integer
|
//grab the jump as an integer
|
||||||
unsigned int jump = *((int*)(vm->module + vm->jumpsAddr + READ_INT(vm)));
|
unsigned int jump = *((int*)(vm->code + vm->jumpsAddr + READ_INT(vm)));
|
||||||
|
|
||||||
//jumps are relative to the data address
|
//jumps are relative to the data address
|
||||||
char* cstring = (char*)(vm->module + vm->dataAddr + jump);
|
char* cstring = (char*)(vm->code + vm->dataAddr + jump);
|
||||||
|
|
||||||
//build a string from the data section
|
//build a string from the data section
|
||||||
if (stringType == TOY_STRING_LEAF) {
|
if (stringType == TOY_STRING_LEAF) {
|
||||||
@@ -192,10 +192,10 @@ static void processDeclare(Toy_VM* vm) {
|
|||||||
bool constant = READ_BYTE(vm); //constness
|
bool constant = READ_BYTE(vm); //constness
|
||||||
|
|
||||||
//grab the jump
|
//grab the jump
|
||||||
unsigned int jump = *(unsigned int*)(vm->module + vm->jumpsAddr + READ_INT(vm));
|
unsigned int jump = *(unsigned int*)(vm->code + vm->jumpsAddr + READ_INT(vm));
|
||||||
|
|
||||||
//grab the data
|
//grab the data
|
||||||
char* cstring = (char*)(vm->module + vm->dataAddr + jump);
|
char* cstring = (char*)(vm->code + vm->dataAddr + jump);
|
||||||
|
|
||||||
//build the name string
|
//build the name string
|
||||||
Toy_String* name = Toy_createNameStringLength(&vm->stringBucket, cstring, len, type, constant);
|
Toy_String* name = Toy_createNameStringLength(&vm->stringBucket, cstring, len, type, constant);
|
||||||
@@ -939,121 +939,17 @@ static void process(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void Toy_initVM(Toy_VM* vm) {
|
|
||||||
//clear the stack, scope and memory
|
|
||||||
vm->stringBucket = NULL;
|
|
||||||
vm->scopeBucket = NULL;
|
|
||||||
vm->stack = NULL;
|
|
||||||
vm->scope = NULL;
|
|
||||||
|
|
||||||
Toy_resetVM(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_bindVM(Toy_VM* vm, struct Toy_Bytecode* bc) {
|
|
||||||
if (bc->ptr[0] != TOY_VERSION_MAJOR || bc->ptr[1] > TOY_VERSION_MINOR) {
|
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Wrong bytecode version found: expected %d.%d.%d found %d.%d.%d, exiting\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, bc->ptr[0], bc->ptr[1], bc->ptr[2]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bc->ptr[2] != TOY_VERSION_PATCH) {
|
|
||||||
fprintf(stderr, TOY_CC_WARN "WARNING: Wrong bytecode version found: expected %d.%d.%d found %d.%d.%d, continuing\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, bc->ptr[0], bc->ptr[1], bc->ptr[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp((char*)(bc->ptr + 3), TOY_VERSION_BUILD) != 0) {
|
|
||||||
fprintf(stderr, TOY_CC_WARN "WARNING: Wrong bytecode build info found: expected '%s' found '%s', continuing\n" TOY_CC_RESET, TOY_VERSION_BUILD, (char*)(bc->ptr + 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
//offset by the header size
|
|
||||||
int offset = 3 + strlen(TOY_VERSION_BUILD) + 1;
|
|
||||||
if (offset % 4 != 0) {
|
|
||||||
offset += 4 - (offset % 4); //ceil
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bc->moduleCount != 0) { //tmp check, just in case the bytecode is empty; will rework this when module packing works
|
|
||||||
//delegate to a more specialized function
|
|
||||||
Toy_bindVMToModule(vm, bc->ptr + offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_bindVMToModule(Toy_VM* vm, unsigned char* module) {
|
|
||||||
vm->module = module;
|
|
||||||
|
|
||||||
//read the header metadata
|
|
||||||
vm->moduleSize = READ_UNSIGNED_INT(vm);
|
|
||||||
vm->paramSize = READ_UNSIGNED_INT(vm);
|
|
||||||
vm->jumpsSize = READ_UNSIGNED_INT(vm);
|
|
||||||
vm->dataSize = READ_UNSIGNED_INT(vm);
|
|
||||||
vm->subsSize = READ_UNSIGNED_INT(vm);
|
|
||||||
|
|
||||||
//read the header addresses
|
|
||||||
if (vm->paramSize > 0) {
|
|
||||||
vm->paramAddr = READ_UNSIGNED_INT(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->codeAddr = READ_UNSIGNED_INT(vm); //required
|
|
||||||
|
|
||||||
if (vm->jumpsSize > 0) {
|
|
||||||
vm->jumpsAddr = READ_UNSIGNED_INT(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm->dataSize > 0) {
|
|
||||||
vm->dataAddr = READ_UNSIGNED_INT(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm->subsSize > 0) {
|
|
||||||
vm->subsAddr = READ_UNSIGNED_INT(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
//allocate the stack, scope, and memory (skip if already in use)
|
|
||||||
if (vm->stringBucket == NULL) {
|
|
||||||
vm->stringBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
|
||||||
}
|
|
||||||
if (vm->scopeBucket == NULL) {
|
|
||||||
vm->scopeBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
|
||||||
}
|
|
||||||
if (vm->stack == NULL) {
|
|
||||||
vm->stack = Toy_allocateStack();
|
|
||||||
}
|
|
||||||
if (vm->scope == NULL) {
|
|
||||||
vm->scope = Toy_pushScope(&vm->scopeBucket, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_runVM(Toy_VM* vm) {
|
|
||||||
//NO-OP on empty VMs
|
|
||||||
if (vm->module == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: read params into scope
|
|
||||||
|
|
||||||
//prep the program counter for execution
|
|
||||||
vm->programCounter = vm->codeAddr;
|
|
||||||
|
|
||||||
//begin
|
|
||||||
process(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_freeVM(Toy_VM* vm) {
|
|
||||||
//clear the stack, scope and memory
|
|
||||||
Toy_freeStack(vm->stack);
|
|
||||||
Toy_popScope(vm->scope);
|
|
||||||
Toy_freeBucket(&vm->stringBucket);
|
|
||||||
Toy_freeBucket(&vm->scopeBucket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_resetVM(Toy_VM* vm) {
|
void Toy_resetVM(Toy_VM* vm) {
|
||||||
vm->module = NULL;
|
vm->code = NULL;
|
||||||
vm->moduleSize = 0;
|
|
||||||
|
|
||||||
vm->paramSize = 0;
|
vm->jumpsCount = 0;
|
||||||
vm->jumpsSize = 0;
|
vm->paramCount = 0;
|
||||||
vm->dataSize = 0;
|
vm->dataCount = 0;
|
||||||
vm->subsSize = 0;
|
vm->subsCount = 0;
|
||||||
|
|
||||||
vm->paramAddr = 0;
|
|
||||||
vm->codeAddr = 0;
|
vm->codeAddr = 0;
|
||||||
vm->jumpsAddr = 0;
|
vm->jumpsAddr = 0;
|
||||||
|
vm->paramAddr = 0;
|
||||||
vm->dataAddr = 0;
|
vm->dataAddr = 0;
|
||||||
vm->subsAddr = 0;
|
vm->subsAddr = 0;
|
||||||
|
|
||||||
@@ -1061,5 +957,67 @@ void Toy_resetVM(Toy_VM* vm) {
|
|||||||
|
|
||||||
Toy_resetStack(&vm->stack);
|
Toy_resetStack(&vm->stack);
|
||||||
|
|
||||||
//NOTE: scope and memory are not altered during resets
|
//NOTE: scope and buckets are not altered during resets
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_initVM(Toy_VM* vm) {
|
||||||
|
//create persistent memory
|
||||||
|
vm->scope = NULL;
|
||||||
|
vm->stack = Toy_allocateStack();
|
||||||
|
vm->stringBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
vm->scopeBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
|
Toy_resetVM(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_inheritVM(Toy_VM* vm, Toy_VM* parent) {
|
||||||
|
//inherent persistent memory
|
||||||
|
vm->scope = NULL;
|
||||||
|
vm->stack = Toy_allocateStack();
|
||||||
|
vm->stringBucket = parent->stringBucket;
|
||||||
|
vm->scopeBucket = parent->scopeBucket;
|
||||||
|
|
||||||
|
//TODO: parent bucket pointers are updated after function calls
|
||||||
|
|
||||||
|
Toy_resetVM(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_bindVMToModule(Toy_VM* vm, Toy_Module* module) {
|
||||||
|
vm->code = module->code;
|
||||||
|
|
||||||
|
vm->jumpsCount = module->jumpsCount;
|
||||||
|
vm->paramCount = module->paramCount;
|
||||||
|
vm->dataCount = module->dataCount;
|
||||||
|
vm->subsCount = module->subsCount;
|
||||||
|
|
||||||
|
vm->codeAddr = module->codeAddr;
|
||||||
|
vm->jumpsAddr = module->jumpsAddr;
|
||||||
|
vm->paramAddr = module->paramAddr;
|
||||||
|
vm->dataAddr = module->dataAddr;
|
||||||
|
vm->subsAddr = module->subsAddr;
|
||||||
|
|
||||||
|
vm->scope = Toy_pushScope(&vm->scopeBucket, module->scopePtr); //new scope for the upcoming run
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_runVM(Toy_VM* vm) {
|
||||||
|
//TODO: read params into scope
|
||||||
|
|
||||||
|
//prep the program counter for execution
|
||||||
|
vm->programCounter = vm->codeAddr;
|
||||||
|
|
||||||
|
//begin
|
||||||
|
process(vm);
|
||||||
|
|
||||||
|
//TODO: add return value extraction
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_freeVM(Toy_VM* vm) {
|
||||||
|
Toy_resetVM(vm);
|
||||||
|
|
||||||
|
Toy_popScope(vm->scope);
|
||||||
|
|
||||||
|
//clear the persistent memory
|
||||||
|
Toy_freeStack(vm->stack);
|
||||||
|
Toy_freeBucket(&vm->stringBucket);
|
||||||
|
Toy_freeBucket(&vm->scopeBucket);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#include "toy_bytecode.h"
|
|
||||||
#include "toy_bucket.h"
|
#include "toy_bucket.h"
|
||||||
#include "toy_scope.h"
|
#include "toy_scope.h"
|
||||||
|
#include "toy_module.h"
|
||||||
|
|
||||||
#include "toy_value.h"
|
#include "toy_value.h"
|
||||||
#include "toy_string.h"
|
#include "toy_string.h"
|
||||||
@@ -14,40 +14,42 @@
|
|||||||
|
|
||||||
typedef struct Toy_VM {
|
typedef struct Toy_VM {
|
||||||
//raw instructions to be executed
|
//raw instructions to be executed
|
||||||
unsigned char* module; //URGENT: rename to 'code'
|
unsigned char* code;
|
||||||
unsigned int moduleSize;
|
|
||||||
|
|
||||||
unsigned int paramSize;
|
//metadata
|
||||||
unsigned int jumpsSize;
|
unsigned int jumpsCount;
|
||||||
unsigned int dataSize;
|
unsigned int paramCount;
|
||||||
unsigned int subsSize;
|
unsigned int dataCount;
|
||||||
|
unsigned int subsCount;
|
||||||
|
|
||||||
unsigned int paramAddr;
|
|
||||||
unsigned int codeAddr;
|
unsigned int codeAddr;
|
||||||
unsigned int jumpsAddr;
|
unsigned int jumpsAddr;
|
||||||
|
unsigned int paramAddr;
|
||||||
unsigned int dataAddr;
|
unsigned int dataAddr;
|
||||||
unsigned int subsAddr;
|
unsigned int subsAddr;
|
||||||
|
|
||||||
|
//execution utils
|
||||||
unsigned int programCounter;
|
unsigned int programCounter;
|
||||||
|
|
||||||
//stack - immediate-level values only
|
|
||||||
Toy_Stack* stack;
|
|
||||||
|
|
||||||
//scope - block-level key/value pairs
|
//scope - block-level key/value pairs
|
||||||
Toy_Scope* scope;
|
Toy_Scope* scope;
|
||||||
|
|
||||||
|
//stack - immediate-level values only
|
||||||
|
Toy_Stack* stack;
|
||||||
|
|
||||||
//easy access to memory
|
//easy access to memory
|
||||||
Toy_Bucket* stringBucket; //stores the string literals
|
Toy_Bucket* stringBucket; //stores the string literals
|
||||||
Toy_Bucket* scopeBucket; //stores the scopes
|
Toy_Bucket* scopeBucket; //stores the scope instances TODO: is this separation needed?
|
||||||
} Toy_VM;
|
} Toy_VM;
|
||||||
|
|
||||||
TOY_API void Toy_initVM(Toy_VM* vm);
|
TOY_API void Toy_resetVM(Toy_VM* vm); //persists memory
|
||||||
TOY_API void Toy_bindVM(Toy_VM* vm, struct Toy_Bytecode* bc); //process the version data
|
|
||||||
TOY_API void Toy_bindVMToModule(Toy_VM* vm, unsigned char* module); //process the module only
|
|
||||||
|
|
||||||
|
TOY_API void Toy_initVM(Toy_VM* vm); //creates memory
|
||||||
|
TOY_API void Toy_inheritVM(Toy_VM* vm, Toy_VM* parent); //inherits memory
|
||||||
|
|
||||||
|
TOY_API void Toy_bindVMToModule(Toy_VM* vm, Toy_Module* module);
|
||||||
TOY_API void Toy_runVM(Toy_VM* vm);
|
TOY_API void Toy_runVM(Toy_VM* vm);
|
||||||
|
|
||||||
TOY_API void Toy_freeVM(Toy_VM* vm);
|
TOY_API void Toy_freeVM(Toy_VM* vm);
|
||||||
|
|
||||||
TOY_API void Toy_resetVM(Toy_VM* vm); //prepares for another run without deleting stack, scope and memory
|
|
||||||
|
|
||||||
//TODO: inject extra data (hook system for external libraries)
|
//TODO: inject extra data (hook system for external libraries)
|
||||||
|
|||||||
Reference in New Issue
Block a user