mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-20 01:04:08 +10:00
Expanded bytecode inspector, added functions to Toy_copyValue
This commit is contained in:
@@ -34,7 +34,7 @@ Bytecode Format Structure
|
||||
.header:
|
||||
N total size # size of this routine, including all data and subroutines
|
||||
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 (used for subroutines)
|
||||
N .param count # the number of parameter fields expected (a secondary jump table, used for subroutine parameters)
|
||||
N .data count # the number of data fields present
|
||||
N .subs count # the number of subroutines present
|
||||
.code start # absolute address of .code; mandatory
|
||||
@@ -48,14 +48,14 @@ Bytecode Format Structure
|
||||
# opcode instructions read and 'executed' by the interpreter (aligned to 4-byte widths)
|
||||
[READ, TOY_VALUE_STRING, Toy_StringType, stringLength] [jumpIndex]
|
||||
|
||||
.param:
|
||||
# a list of names, stored in .data, to be used for any provided function arguments
|
||||
|
||||
.jumptable:
|
||||
.jumps:
|
||||
# a layer of indirection for quickly looking up values in .data and .subs
|
||||
0 -> {string, 0x00}
|
||||
4 -> {fn, 0xFF}
|
||||
|
||||
.param:
|
||||
# a list of names, stored in .data, to be used for any provided function arguments
|
||||
|
||||
.data:
|
||||
# data that can't be cleanly embedded into .code, such as strings
|
||||
"Hello world\0"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int jumps_addr, unsigned int data_addr);
|
||||
int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_addr, unsigned int data_addr);
|
||||
@@ -15,31 +16,34 @@ int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_ad
|
||||
// void inspect_data(unsigned char* bytecode, unsigned int pc, unsigned int size);
|
||||
// void inspect_subs(unsigned char* bytecode, unsigned int pc, unsigned int size);
|
||||
|
||||
#define ISPRINT_SANITIZE(x) (isprint((int)x) > 0 ? (x) : '_')
|
||||
|
||||
#define MARKER_VALUE(pc, type) \
|
||||
(pc * sizeof(type))
|
||||
|
||||
#define MARKER "\033[" TOY_CC_FONT_BLACK "m" " %lu\t" TOY_CC_RESET
|
||||
#define MARKER "\t\033[" TOY_CC_FONT_BLACK "m" " %lu\t" TOY_CC_RESET
|
||||
#define FONT_BLACK "\033[" TOY_CC_FONT_BLACK "m"
|
||||
|
||||
//exposed functions
|
||||
void inspect_bytecode(unsigned char* bytecode) {
|
||||
int inspect_bytecode(unsigned char* bytecode) {
|
||||
//TODO: handle version info
|
||||
|
||||
unsigned int const header_size = 0;
|
||||
unsigned int const header_jumps = 1;
|
||||
unsigned int const header_param = 2;
|
||||
unsigned int const header_data = 3;
|
||||
unsigned int const header_subs = 4;
|
||||
unsigned int const bytecodeSize = ((unsigned int*)(bytecode))[0];
|
||||
unsigned int const jumpsSize = ((unsigned int*)(bytecode))[1];
|
||||
unsigned int const paramSize = ((unsigned int*)(bytecode))[2];
|
||||
unsigned int const dataSize = ((unsigned int*)(bytecode))[3];
|
||||
unsigned int const subsSize = ((unsigned int*)(bytecode))[4];
|
||||
|
||||
//header size
|
||||
printf(MARKER TOY_CC_NOTICE "Bytecode Size: \t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_size, unsigned int), ((unsigned int*)(bytecode))[header_size]);
|
||||
printf(FONT_BLACK ".header:\r" TOY_CC_RESET);
|
||||
|
||||
//bytecode size
|
||||
printf(MARKER TOY_CC_NOTICE "Bytecode Size: \t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(0, unsigned int), bytecodeSize);
|
||||
|
||||
//header counts
|
||||
printf(MARKER TOY_CC_NOTICE "Jumps Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_jumps, unsigned int), ((unsigned int*)(bytecode))[header_jumps]);
|
||||
printf(MARKER TOY_CC_NOTICE "Param Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_param, unsigned int), ((unsigned int*)(bytecode))[header_param]);
|
||||
printf(MARKER TOY_CC_NOTICE "Data Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_data, unsigned int), ((unsigned int*)(bytecode))[header_data]);
|
||||
printf(MARKER TOY_CC_NOTICE "Subs Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_subs, unsigned int), ((unsigned int*)(bytecode))[header_subs]);
|
||||
|
||||
printf("\n---\n");
|
||||
printf(MARKER TOY_CC_NOTICE "Jumps Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(1, unsigned int), jumpsSize);
|
||||
printf(MARKER TOY_CC_NOTICE "Param Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(2, unsigned int), paramSize);
|
||||
printf(MARKER TOY_CC_NOTICE "Data Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(3, unsigned int), dataSize);
|
||||
printf(MARKER TOY_CC_NOTICE "Subs Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(4, unsigned int), subsSize);
|
||||
|
||||
//some addresses may be absent
|
||||
unsigned int addr_pc = 4;
|
||||
@@ -49,6 +53,8 @@ void inspect_bytecode(unsigned char* bytecode) {
|
||||
unsigned int data_addr = 0;
|
||||
unsigned int subs_addr = 0;
|
||||
|
||||
//bugfix
|
||||
unsigned int code_end = 0;
|
||||
|
||||
//header addresses
|
||||
if (true) {
|
||||
@@ -57,42 +63,93 @@ void inspect_bytecode(unsigned char* bytecode) {
|
||||
code_addr = ((unsigned int*)(bytecode))[addr_pc];
|
||||
}
|
||||
|
||||
if (((unsigned int*)(bytecode))[header_jumps] > 0) {
|
||||
if (jumpsSize > 0) {
|
||||
addr_pc++;
|
||||
printf(MARKER TOY_CC_NOTICE "Jumps Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]);
|
||||
jumps_addr = ((unsigned int*)(bytecode))[addr_pc];
|
||||
if (code_end == 0) code_end = jumps_addr;
|
||||
}
|
||||
|
||||
if (((unsigned int*)(bytecode))[header_param] > 0) {
|
||||
if (paramSize > 0) {
|
||||
addr_pc++;
|
||||
printf(MARKER TOY_CC_NOTICE "Param Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]);
|
||||
param_addr = ((unsigned int*)(bytecode))[addr_pc];
|
||||
if (code_end == 0) code_end = param_addr;
|
||||
}
|
||||
|
||||
if (((unsigned int*)(bytecode))[header_data] > 0) {
|
||||
if (dataSize > 0) {
|
||||
addr_pc++;
|
||||
printf(MARKER TOY_CC_NOTICE "Data Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]);
|
||||
data_addr = ((unsigned int*)(bytecode))[addr_pc];
|
||||
if (code_end == 0) code_end = data_addr;
|
||||
}
|
||||
|
||||
if (((unsigned int*)(bytecode))[header_subs] > 0) {
|
||||
if (subsSize > 0) {
|
||||
addr_pc++;
|
||||
printf(MARKER TOY_CC_NOTICE "Subs Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]);
|
||||
subs_addr = ((unsigned int*)(bytecode))[addr_pc];
|
||||
if (code_end == 0) code_end = subs_addr;
|
||||
}
|
||||
|
||||
printf("\n---\n");
|
||||
if (code_end == 0) code_end = bytecodeSize; //very hacky
|
||||
|
||||
printf(FONT_BLACK ".code:\r" TOY_CC_RESET);
|
||||
|
||||
unsigned int pc = code_addr;
|
||||
while(bytecode[pc] != TOY_OPCODE_RETURN) {
|
||||
while(pc < code_end) {
|
||||
pc += inspect_instruction(bytecode, pc, jumps_addr, data_addr);
|
||||
}
|
||||
pc += inspect_instruction(bytecode, pc, jumps_addr, data_addr); //one more for the final return
|
||||
|
||||
(void)jumps_addr;
|
||||
(void)param_addr;
|
||||
(void)data_addr;
|
||||
(void)subs_addr;
|
||||
//jumps
|
||||
if (jumpsSize > 0) {
|
||||
printf(FONT_BLACK ".jumps:\r" TOY_CC_RESET);
|
||||
|
||||
for (unsigned int i = 0; (i*4) < jumpsSize; i++) {
|
||||
printf(MARKER TOY_CC_NOTICE "%u (data %u)" TOY_CC_RESET "\n", MARKER_VALUE(jumps_addr + i, unsigned int),
|
||||
i,
|
||||
((unsigned int*)(bytecode + jumps_addr))[i] + data_addr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//param
|
||||
if (paramSize > 0) {
|
||||
printf(FONT_BLACK ".param:\r" TOY_CC_RESET);
|
||||
|
||||
for (unsigned int i = 0; (i*4) < paramSize; i += 2) {
|
||||
printf(MARKER TOY_CC_NOTICE "%u (type %s, data %u)" TOY_CC_RESET "\n", MARKER_VALUE(param_addr + i, unsigned int),
|
||||
i,
|
||||
Toy_private_getValueTypeAsCString(((unsigned int*)(bytecode + param_addr))[i + 1]),
|
||||
((unsigned int*)(bytecode + param_addr))[i] + data_addr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//data; assume there's only strings for now
|
||||
if (dataSize > 0) {
|
||||
printf(FONT_BLACK ".data:\r" TOY_CC_RESET);
|
||||
|
||||
for (unsigned int i = 0; (i*4) < dataSize; i++) {
|
||||
printf(MARKER TOY_CC_NOTICE "%c %c %c %c" TOY_CC_RESET "\n", MARKER_VALUE(data_addr + i, unsigned int),
|
||||
ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[0]),
|
||||
ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[1]),
|
||||
ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[2]),
|
||||
ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[3])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//subs
|
||||
if (subsSize > 0) {
|
||||
printf(FONT_BLACK ".subs:\n" TOY_CC_RESET);
|
||||
|
||||
unsigned int i = 0;
|
||||
while (i < subsSize) {
|
||||
i += inspect_bytecode(bytecode + subs_addr + i);
|
||||
}
|
||||
}
|
||||
|
||||
return bytecodeSize;
|
||||
}
|
||||
|
||||
int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int jumps_addr, unsigned int data_addr) {
|
||||
@@ -129,7 +186,7 @@ int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int j
|
||||
return 4;
|
||||
|
||||
case TOY_OPCODE_INVOKE:
|
||||
printf(MARKER "INVOKE %s (%d args)\n", MARKER_VALUE(pc, unsigned char),
|
||||
printf(MARKER "INVOKE as '%s' (%d parameters)\n", MARKER_VALUE(pc, unsigned char),
|
||||
Toy_private_getValueTypeAsCString(bytecode[pc + 1]),
|
||||
bytecode[pc + 2]);
|
||||
return 4;
|
||||
@@ -143,23 +200,23 @@ int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int j
|
||||
return 4;
|
||||
|
||||
case TOY_OPCODE_ADD:
|
||||
printf(MARKER "ADD %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : "");
|
||||
printf(MARKER "ADD %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : "");
|
||||
return 4;
|
||||
|
||||
case TOY_OPCODE_SUBTRACT:
|
||||
printf(MARKER "SUBTRACT %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : "");
|
||||
printf(MARKER "SUBTRACT %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : "");
|
||||
return 4;
|
||||
|
||||
case TOY_OPCODE_MULTIPLY:
|
||||
printf(MARKER "MULTIPLY %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : "");
|
||||
printf(MARKER "MULTIPLY %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : "");
|
||||
return 4;
|
||||
|
||||
case TOY_OPCODE_DIVIDE:
|
||||
printf(MARKER "DIVIDE %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : "");
|
||||
printf(MARKER "DIVIDE %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : "");
|
||||
return 4;
|
||||
|
||||
case TOY_OPCODE_MODULO:
|
||||
printf(MARKER "MODULO %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : "");
|
||||
printf(MARKER "MODULO %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : "");
|
||||
return 4;
|
||||
|
||||
case TOY_OPCODE_COMPARE_EQUAL:
|
||||
@@ -291,6 +348,7 @@ int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_ad
|
||||
case TOY_VALUE_STRING: {
|
||||
Toy_StringType stringType = (Toy_StringType)(*(bytecode + pc + 2)); //Probably not needed
|
||||
int len = bytecode[pc + 3]; //only used for names?
|
||||
(void)len;
|
||||
|
||||
(void)stringType;
|
||||
|
||||
@@ -298,13 +356,13 @@ int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_ad
|
||||
unsigned int jumpValue = *((unsigned int*)(bytecode + jumps_addr + indexValue));
|
||||
char* cstr = ((char*)(bytecode + data_addr + jumpValue));
|
||||
|
||||
printf(MARKER "READ STRING (%d) %s\n", MARKER_VALUE(pc, unsigned char), len, cstr);
|
||||
printf(MARKER "READ STRING %u '%s'\n", MARKER_VALUE(pc, unsigned char), indexValue, cstr);
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
case TOY_VALUE_FUNCTION:
|
||||
printf(MARKER "READ FUNCTION (%d params)\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 2]);
|
||||
printf(MARKER "READ FUNCTION '%u' (%d params)\n", MARKER_VALUE(pc, unsigned char), *((unsigned int*)(bytecode + pc + 4)), bytecode[pc + 2]);
|
||||
return 8;
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void inspect_bytecode(unsigned char* bytecode);
|
||||
int inspect_bytecode(unsigned char* bytecode);
|
||||
|
||||
@@ -4,6 +4,16 @@ fn isLeapYear(n: int) {
|
||||
if (n % 100 == 0) return false;
|
||||
return n % 4 == 0;
|
||||
}
|
||||
print isLeapYear(1999);
|
||||
print isLeapYear(2000);
|
||||
print isLeapYear(2004);
|
||||
|
||||
//check for string reuse
|
||||
{
|
||||
print isLeapYear(1999);
|
||||
}
|
||||
|
||||
{
|
||||
print isLeapYear(2000);
|
||||
}
|
||||
|
||||
{
|
||||
print isLeapYear(2004);
|
||||
}
|
||||
|
||||
@@ -1222,10 +1222,13 @@ static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast) {
|
||||
|
||||
writeBytecodeFromAst(&mb, ast);
|
||||
|
||||
EMIT_BYTE(&mb, code, TOY_OPCODE_RETURN); //end terminator
|
||||
EMIT_BYTE(&mb, code, 0); //4-byte alignment
|
||||
EMIT_BYTE(&mb, code, 0);
|
||||
EMIT_BYTE(&mb, code, 0);
|
||||
//append an extra return if needed
|
||||
if (mb->codeCount <= 4 || mb->code[mb->codeCount - 4] != TOY_OPCODE_RETURN) { //if empty or no return statement
|
||||
EMIT_BYTE(&mb, code, TOY_OPCODE_RETURN); //end terminator
|
||||
EMIT_BYTE(&mb, code, 0); //4-byte alignment
|
||||
EMIT_BYTE(&mb, code, 0);
|
||||
EMIT_BYTE(&mb, code, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char* collateBytecodeBody(Toy_Bytecode* mb) {
|
||||
|
||||
@@ -20,6 +20,23 @@ Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nati
|
||||
return fn;
|
||||
}
|
||||
|
||||
Toy_Function* Toy_copyFunction(Toy_Bucket** bucketHandle, Toy_Function* original) {
|
||||
Toy_Function* fn = (Toy_Function*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Function));
|
||||
|
||||
if (original->type == TOY_FUNCTION_CUSTOM) {
|
||||
fn->type = original->type;
|
||||
fn->bytecode.code = original->bytecode.code;
|
||||
fn->bytecode.parentScope = original->bytecode.parentScope;
|
||||
Toy_private_incrementScopeRefCount(fn->bytecode.parentScope);
|
||||
}
|
||||
else if (fn->type == TOY_FUNCTION_NATIVE) {
|
||||
fn->type = original->type;
|
||||
fn->native.callback = original->native.callback;
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
TOY_API void Toy_freeFunction(Toy_Function* fn) {
|
||||
if (fn->type == TOY_FUNCTION_CUSTOM) {
|
||||
Toy_private_decrementScopeRefCount(fn->bytecode.parentScope);
|
||||
|
||||
@@ -34,4 +34,5 @@ typedef union Toy_Function_t {
|
||||
TOY_API Toy_Function* Toy_createFunctionFromBytecode(Toy_Bucket** bucketHandle, unsigned char* bytecode, Toy_Scope* parentScope);
|
||||
TOY_API Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nativeCallback callback);
|
||||
|
||||
TOY_API Toy_Function* Toy_copyFunction(Toy_Bucket** bucketHandle, Toy_Function* fn);
|
||||
TOY_API void Toy_freeFunction(Toy_Function* fn);
|
||||
@@ -90,7 +90,7 @@ unsigned int Toy_hashValue(Toy_Value value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Toy_Value Toy_copyValue(Toy_Value value) {
|
||||
Toy_Value Toy_copyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
||||
MAYBE_UNWRAP(value);
|
||||
|
||||
switch(value.type) {
|
||||
@@ -104,13 +104,13 @@ Toy_Value Toy_copyValue(Toy_Value value) {
|
||||
return TOY_VALUE_FROM_STRING(Toy_copyString(value.as.string));
|
||||
}
|
||||
|
||||
case TOY_VALUE_ARRAY: {
|
||||
case TOY_VALUE_ARRAY: { //TODO: switch to buckets
|
||||
//arrays probably won't get copied much
|
||||
Toy_Array* ptr = value.as.array;
|
||||
Toy_Array* result = Toy_resizeArray(NULL, ptr->capacity);
|
||||
|
||||
for (unsigned int i = 0; i < ptr->count; i++) {
|
||||
result->data[i] = Toy_copyValue(ptr->data[i]);
|
||||
result->data[i] = Toy_copyValue(bucketHandle, ptr->data[i]);
|
||||
}
|
||||
|
||||
result->capacity = ptr->capacity;
|
||||
@@ -119,15 +119,15 @@ Toy_Value Toy_copyValue(Toy_Value value) {
|
||||
return TOY_VALUE_FROM_ARRAY(result);
|
||||
}
|
||||
|
||||
case TOY_VALUE_TABLE: {
|
||||
case TOY_VALUE_TABLE: { //TODO: switch to buckets
|
||||
//tables probably won't get copied much
|
||||
Toy_Table* ptr = value.as.table;
|
||||
Toy_Table* result = Toy_private_adjustTableCapacity(NULL, ptr->capacity);
|
||||
|
||||
for (unsigned int i = 0; i < ptr->capacity; i++) {
|
||||
if (TOY_VALUE_IS_NULL(ptr->data[i].key) != true) {
|
||||
result->data[i].key = Toy_copyValue(ptr->data[i].key);
|
||||
result->data[i].value = Toy_copyValue(ptr->data[i].value);
|
||||
result->data[i].key = Toy_copyValue(bucketHandle, ptr->data[i].key);
|
||||
result->data[i].value = Toy_copyValue(bucketHandle, ptr->data[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,8 @@ Toy_Value Toy_copyValue(Toy_Value value) {
|
||||
return TOY_VALUE_FROM_TABLE(result);
|
||||
}
|
||||
|
||||
case TOY_VALUE_FUNCTION: //TODO: implement function duplication elsewhere
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy a function (use a reference instead), exiting\n" TOY_CC_RESET);
|
||||
exit(-1);
|
||||
case TOY_VALUE_FUNCTION:
|
||||
return TOY_VALUE_FROM_FUNCTION(Toy_copyFunction(bucketHandle, value.as.function));
|
||||
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_ANY:
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "toy_common.h"
|
||||
#include "toy_print.h"
|
||||
#include "toy_bucket.h"
|
||||
|
||||
//forward declarations
|
||||
struct Toy_Bucket;
|
||||
union Toy_String_t;
|
||||
struct Toy_Array;
|
||||
struct Toy_Table;
|
||||
@@ -79,7 +79,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS
|
||||
TOY_API Toy_Value Toy_unwrapValue(Toy_Value value);
|
||||
TOY_API unsigned int Toy_hashValue(Toy_Value value);
|
||||
|
||||
TOY_API Toy_Value Toy_copyValue(Toy_Value value);
|
||||
TOY_API Toy_Value Toy_copyValue(struct Toy_Bucket** bucketHandle, Toy_Value value);
|
||||
TOY_API void Toy_freeValue(Toy_Value value);
|
||||
|
||||
TOY_API bool Toy_checkValueIsTruthy(Toy_Value value);
|
||||
|
||||
@@ -159,7 +159,7 @@ static void processRead(Toy_VM* vm) {
|
||||
unsigned int addr = (unsigned int)READ_INT(vm);
|
||||
|
||||
//create and push the function value
|
||||
Toy_Function* function = Toy_createFunctionFromBytecode(&vm->memoryBucket, vm->code + vm->subsAddr + addr, vm->scope);
|
||||
Toy_Function* function = Toy_createFunctionFromBytecode(&vm->memoryBucket, vm->code + vm->subsAddr + addr, vm->scope); //BUG: functions don't have the jumps indirection?
|
||||
value = TOY_VALUE_FROM_FUNCTION(function);
|
||||
|
||||
break;
|
||||
@@ -227,7 +227,7 @@ static void processAssign(Toy_VM* vm) {
|
||||
//in case of chaining, leave a copy on the stack
|
||||
bool chainedAssignment = READ_BYTE(vm);
|
||||
if (chainedAssignment) {
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(value));
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, value));
|
||||
}
|
||||
|
||||
//cleanup
|
||||
@@ -253,7 +253,7 @@ static void processAssignCompound(Toy_VM* vm) {
|
||||
target = TOY_REFERENCE_FROM_POINTER(valuePtr);
|
||||
}
|
||||
else {
|
||||
target = Toy_copyValue(*valuePtr);
|
||||
target = Toy_copyValue(&vm->memoryBucket, *valuePtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,12 +280,12 @@ static void processAssignCompound(Toy_VM* vm) {
|
||||
}
|
||||
|
||||
//set the value
|
||||
array->data[index] = Toy_copyValue(TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value);
|
||||
array->data[index] = Toy_copyValue(&vm->memoryBucket, TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value);
|
||||
|
||||
//in case of chaining, leave a copy on the stack
|
||||
bool chainedAssignment = READ_BYTE(vm);
|
||||
if (chainedAssignment) {
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(value));
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, value));
|
||||
}
|
||||
|
||||
//cleanup
|
||||
@@ -296,12 +296,12 @@ static void processAssignCompound(Toy_VM* vm) {
|
||||
Toy_Table* table = TOY_VALUE_AS_TABLE(target);
|
||||
|
||||
//set the value
|
||||
Toy_insertTable(&table, Toy_copyValue(TOY_VALUE_IS_REFERENCE(key) ? Toy_unwrapValue(key) : key), Toy_copyValue(TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value));
|
||||
Toy_insertTable(&table, Toy_copyValue(&vm->memoryBucket, TOY_VALUE_IS_REFERENCE(key) ? Toy_unwrapValue(key) : key), Toy_copyValue(&vm->memoryBucket, TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value));
|
||||
|
||||
//in case of chaining, leave a copy on the stack
|
||||
bool chainedAssignment = READ_BYTE(vm);
|
||||
if (chainedAssignment) {
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(value));
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, value));
|
||||
}
|
||||
|
||||
//cleanup
|
||||
@@ -335,7 +335,7 @@ static void processAccess(Toy_VM* vm) {
|
||||
Toy_pushStack(&vm->stack, ref);
|
||||
}
|
||||
else {
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(*valuePtr));
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, *valuePtr));
|
||||
}
|
||||
|
||||
//cleanup
|
||||
@@ -403,7 +403,7 @@ static void processInvoke(Toy_VM* vm) {
|
||||
|
||||
//extract and store any results
|
||||
if (resultCount > 0) {
|
||||
Toy_Array* results = Toy_extractResultsFromVM(&subVM, resultCount);
|
||||
Toy_Array* results = Toy_extractResultsFromVM(vm, &subVM, resultCount);
|
||||
|
||||
for (unsigned int i = 0; i < results->count; i++) {
|
||||
//NOTE: since the results array is being immediately freed, just push each element without a call to copy
|
||||
@@ -432,7 +432,7 @@ static void processInvoke(Toy_VM* vm) {
|
||||
}
|
||||
|
||||
static void processDuplicate(Toy_VM* vm) {
|
||||
Toy_Value value = Toy_copyValue(Toy_peekStack(&vm->stack));
|
||||
Toy_Value value = Toy_copyValue(&vm->memoryBucket, Toy_peekStack(&vm->stack));
|
||||
Toy_pushStack(&vm->stack, value);
|
||||
|
||||
//check for compound assignments
|
||||
@@ -878,7 +878,7 @@ static void processIndex(Toy_VM* vm) {
|
||||
Toy_pushStack(&vm->stack, ref);
|
||||
}
|
||||
else {
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(array->data[i]));
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, array->data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,7 +911,7 @@ static void processIndex(Toy_VM* vm) {
|
||||
Toy_pushStack(&vm->stack, ref);
|
||||
}
|
||||
else {
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(entry->value));
|
||||
Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, entry->value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1146,7 +1146,7 @@ void Toy_freeVM(Toy_VM* vm) {
|
||||
}
|
||||
}
|
||||
|
||||
Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount) {
|
||||
Toy_Array* Toy_extractResultsFromVM(Toy_VM* parentVM, Toy_VM* subVM, unsigned int resultCount) {
|
||||
if (subVM->stack->count < resultCount) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Too many results requested from VM, exiting\n" TOY_CC_RESET);
|
||||
exit(-1);
|
||||
@@ -1156,8 +1156,8 @@ Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount) {
|
||||
|
||||
const unsigned int offset = subVM->stack->count - resultCount; //first element to extract
|
||||
|
||||
for (/* EMPTY */; results->count < resultCount; results->count++) {
|
||||
results->data[results->count] = Toy_copyValue(subVM->stack->data[offset + results->count]);
|
||||
for (/* EMPTY */; results->count < resultCount; results->count++) { //TODO: make sure the parent bucket adopts the child bucket's responsibilities
|
||||
results->data[results->count] = Toy_copyValue(&parentVM->memoryBucket, subVM->stack->data[offset + results->count]);
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
@@ -51,6 +51,6 @@ void Toy_bindVM(Toy_VM* vm, unsigned char* bytecode, Toy_Scope* parentScope);
|
||||
TOY_API unsigned int Toy_runVM(Toy_VM* vm);
|
||||
TOY_API void Toy_freeVM(Toy_VM* vm);
|
||||
|
||||
TOY_API Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount);
|
||||
TOY_API Toy_Array* Toy_extractResultsFromVM(Toy_VM* parentVM, Toy_VM* subVM, unsigned int resultCount);
|
||||
|
||||
//TODO: inject extra data (hook system for external libraries)
|
||||
|
||||
@@ -102,15 +102,21 @@ int test_value_creation(void) {
|
||||
int test_value_copying(void) {
|
||||
//test simple integer copy
|
||||
{
|
||||
//setup
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
|
||||
Toy_Value original = TOY_VALUE_FROM_INTEGER(42);
|
||||
Toy_Value result = Toy_copyValue(original);
|
||||
Toy_Value result = Toy_copyValue(&bucket, original);
|
||||
|
||||
if (!TOY_VALUE_IS_INTEGER(result) ||
|
||||
TOY_VALUE_AS_INTEGER(result) != 42
|
||||
) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: copy an integer value failed\n" TOY_CC_RESET);
|
||||
Toy_freeBucket(&bucket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Toy_freeBucket(&bucket);
|
||||
}
|
||||
|
||||
//test string copy
|
||||
@@ -119,7 +125,7 @@ int test_value_copying(void) {
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
|
||||
Toy_Value original = TOY_VALUE_FROM_STRING(Toy_createStringLength(&bucket, "Hello world!", 12));
|
||||
Toy_Value result = Toy_copyValue(original);
|
||||
Toy_Value result = Toy_copyValue(&bucket, original);
|
||||
|
||||
if (TOY_VALUE_IS_STRING(result) == false ||
|
||||
TOY_VALUE_AS_STRING(result)->info.type != TOY_STRING_LEAF ||
|
||||
@@ -143,6 +149,8 @@ int test_value_copying(void) {
|
||||
//test copy arrays
|
||||
{
|
||||
//setup
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
|
||||
Toy_Array* array = Toy_resizeArray(NULL, TOY_ARRAY_INITIAL_CAPACITY);
|
||||
TOY_ARRAY_PUSHBACK(array, TOY_VALUE_FROM_INTEGER(42));
|
||||
TOY_ARRAY_PUSHBACK(array, TOY_VALUE_FROM_INTEGER(69));
|
||||
@@ -150,7 +158,7 @@ int test_value_copying(void) {
|
||||
|
||||
Toy_Value original = TOY_VALUE_FROM_ARRAY(array);
|
||||
|
||||
Toy_Value result = Toy_copyValue(original);
|
||||
Toy_Value result = Toy_copyValue(&bucket, original);
|
||||
|
||||
if (TOY_VALUE_AS_ARRAY(result) == false ||
|
||||
TOY_VALUE_AS_ARRAY(result)->capacity != 8 ||
|
||||
@@ -163,12 +171,14 @@ int test_value_copying(void) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: copy an array value failed\n" TOY_CC_RESET);
|
||||
Toy_freeValue(original);
|
||||
Toy_freeValue(result);
|
||||
Toy_freeBucket(&bucket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
Toy_freeValue(original);
|
||||
Toy_freeValue(result);
|
||||
Toy_freeBucket(&bucket);
|
||||
}
|
||||
|
||||
//arrays can't be compared
|
||||
|
||||
Reference in New Issue
Block a user