mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 09:17:17 +00:00
Remove ValuePrint. Improve ValueToString for reference types.
This commit is contained in:
parent
37faac1f8a
commit
42ecaf301a
26
main.c
26
main.c
@ -7,16 +7,21 @@
|
|||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "disasm.h"
|
#include "disasm.h"
|
||||||
|
|
||||||
|
void StringPut(uint8_t * string) {
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t len = VStringSize(string);
|
||||||
|
for (i = 0; i < len; ++i)
|
||||||
|
fputc(string[i], stdout);
|
||||||
|
}
|
||||||
|
|
||||||
/* Test c function */
|
/* Test c function */
|
||||||
Value print(VM * vm) {
|
Value print(VM * vm) {
|
||||||
uint32_t i, j, count;
|
uint32_t j, count;
|
||||||
Value nil;
|
Value nil;
|
||||||
count = VMCountArgs(vm);
|
count = VMCountArgs(vm);
|
||||||
for (j = 0; j < count; ++j) {
|
for (j = 0; j < count; ++j) {
|
||||||
uint8_t * string = ValueToString(vm, VMGetArg(vm, j));
|
uint8_t * string = ValueToString(vm, VMGetArg(vm, j));
|
||||||
uint32_t len = VStringSize(string);
|
StringPut(string);
|
||||||
for (i = 0; i < len; ++i)
|
|
||||||
fputc(string[i], stdout);
|
|
||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
}
|
}
|
||||||
nil.type = TYPE_NIL;
|
nil.type = TYPE_NIL;
|
||||||
@ -25,7 +30,7 @@ Value print(VM * vm) {
|
|||||||
|
|
||||||
/* A simple repl for debugging */
|
/* A simple repl for debugging */
|
||||||
void debugRepl() {
|
void debugRepl() {
|
||||||
char buffer[128] = {0};
|
char buffer[1024] = {0};
|
||||||
const char * reader = buffer;
|
const char * reader = buffer;
|
||||||
Value func;
|
Value func;
|
||||||
VM vm;
|
VM vm;
|
||||||
@ -46,7 +51,7 @@ void debugRepl() {
|
|||||||
while (p.status == PARSER_PENDING) {
|
while (p.status == PARSER_PENDING) {
|
||||||
/* Get some input if we are done */
|
/* Get some input if we are done */
|
||||||
if (*reader == '\0') {
|
if (*reader == '\0') {
|
||||||
printf("> ");
|
printf(">> ");
|
||||||
if (!fgets(buffer, sizeof(buffer), stdin)) {
|
if (!fgets(buffer, sizeof(buffer), stdin)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -86,9 +91,9 @@ void debugRepl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Print asm */
|
/* Print asm */
|
||||||
printf("\n");
|
//printf("\n");
|
||||||
dasmFunc(stdout, func.data.func);
|
//dasmFunc(stdout, func.data.func);
|
||||||
printf("\n");
|
//printf("\n");
|
||||||
|
|
||||||
/* Execute function */
|
/* Execute function */
|
||||||
VMLoad(&vm, func);
|
VMLoad(&vm, func);
|
||||||
@ -98,7 +103,8 @@ void debugRepl() {
|
|||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
ValuePrint(vm.ret, 0);
|
uint8_t * string = ValueToString(&vm, vm.ret);
|
||||||
|
StringPut(string);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
86
value.c
86
value.c
@ -5,79 +5,6 @@
|
|||||||
#include "ds.h"
|
#include "ds.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
/* Print the bytecode for a FuncDef */
|
|
||||||
static void FuncDefBytecodePrint(FuncDef * def) {
|
|
||||||
uint32_t count, i;
|
|
||||||
count = def->byteCodeLen;
|
|
||||||
printf("(bytecode)[");
|
|
||||||
if (count) {
|
|
||||||
for (i = 0; i < count - 1; ++i) {
|
|
||||||
printf("%04x ", def->byteCode[i]);
|
|
||||||
}
|
|
||||||
printf("%04x", def->byteCode[i]);
|
|
||||||
}
|
|
||||||
printf("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print a value recursively. Used for debugging */
|
|
||||||
void ValuePrint(Value x, uint32_t indent) {
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < indent; ++i)
|
|
||||||
fputc(' ', stdout);
|
|
||||||
switch (x.type) {
|
|
||||||
case TYPE_NIL:
|
|
||||||
printf("<nil>");
|
|
||||||
break;
|
|
||||||
case TYPE_BOOLEAN:
|
|
||||||
printf(x.data.boolean ? "<true>" : "<false>");
|
|
||||||
break;
|
|
||||||
case TYPE_NUMBER:
|
|
||||||
printf("%f", x.data.number);
|
|
||||||
break;
|
|
||||||
case TYPE_FORM:
|
|
||||||
case TYPE_ARRAY:
|
|
||||||
if (x.type == TYPE_ARRAY) printf(" [\n"); else printf(" (\n");
|
|
||||||
for (i = 0; i < x.data.array->count; ++i) {
|
|
||||||
ValuePrint(x.data.array->data[i], indent + 4);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
for (i = 0; i < indent; ++i) fputc(' ', stdout);
|
|
||||||
if (x.type == TYPE_ARRAY) printf(" ]\n"); else printf(" )\n");
|
|
||||||
break;
|
|
||||||
case TYPE_STRING:
|
|
||||||
printf("\"%.*s\"", VStringSize(x.data.string), (char *) x.data.string);
|
|
||||||
break;
|
|
||||||
case TYPE_SYMBOL:
|
|
||||||
printf("%.*s", VStringSize(x.data.string), (char *) x.data.string);
|
|
||||||
break;
|
|
||||||
case TYPE_CFUNCTION:
|
|
||||||
printf("<cfunction>");
|
|
||||||
break;
|
|
||||||
case TYPE_FUNCTION:
|
|
||||||
printf("<function ");
|
|
||||||
FuncDefBytecodePrint(x.data.func->def);
|
|
||||||
printf(">");
|
|
||||||
break;
|
|
||||||
case TYPE_DICTIONARY:
|
|
||||||
printf("<dictionary>");
|
|
||||||
break;
|
|
||||||
case TYPE_BYTEBUFFER:
|
|
||||||
printf("<bytebuffer>");
|
|
||||||
break;
|
|
||||||
case TYPE_FUNCDEF:
|
|
||||||
printf("<funcdef ");
|
|
||||||
FuncDefBytecodePrint(x.data.funcdef);
|
|
||||||
printf(">");
|
|
||||||
break;
|
|
||||||
case TYPE_FUNCENV:
|
|
||||||
printf("<funcenv>");
|
|
||||||
break;
|
|
||||||
case TYPE_THREAD:
|
|
||||||
printf("<thread>");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t * LoadCString(VM * vm, const char * string, uint32_t len) {
|
static uint8_t * LoadCString(VM * vm, const char * string, uint32_t len) {
|
||||||
uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t));
|
uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t));
|
||||||
data += 2 * sizeof(uint32_t);
|
data += 2 * sizeof(uint32_t);
|
||||||
@ -104,12 +31,12 @@ static uint8_t * NumberToString(VM * vm, Number x) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * HEX_CHARACTERS = "0123456789ABCDEF";
|
static const char * HEX_CHARACTERS = "0123456789abcdef";
|
||||||
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)])
|
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)])
|
||||||
|
|
||||||
/* Returns a string description for a pointer */
|
/* Returns a string description for a pointer */
|
||||||
static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlelen, void * pointer) {
|
static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlelen, void * pointer) {
|
||||||
uint32_t len = 3 + titlelen + sizeof(pointer) * 2;
|
uint32_t len = 5 + titlelen + sizeof(void *) * 2;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t));
|
uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t));
|
||||||
uint8_t * c;
|
uint8_t * c;
|
||||||
@ -125,12 +52,17 @@ static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlele
|
|||||||
*c++ = ((uint8_t *)title) [i];
|
*c++ = ((uint8_t *)title) [i];
|
||||||
}
|
}
|
||||||
*c++ = ' ';
|
*c++ = ' ';
|
||||||
for (i = 0; i < sizeof(void *); ++i) {
|
*c++ = '0';
|
||||||
uint8_t byte = buf.bytes[i];
|
*c++ = 'x';
|
||||||
|
for (i = sizeof(void *); i > 0; --i) {
|
||||||
|
uint8_t byte = buf.bytes[i - 1];
|
||||||
|
if (!byte) continue;
|
||||||
*c++ = HEX(byte >> 4);
|
*c++ = HEX(byte >> 4);
|
||||||
*c++ = HEX(byte & 0xF);
|
*c++ = HEX(byte & 0xF);
|
||||||
}
|
}
|
||||||
*c++ = '>';
|
*c++ = '>';
|
||||||
|
VStringHash(data) = 0;
|
||||||
|
VStringSize(data) = len;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
value.h
2
value.h
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
|
||||||
void ValuePrint(Value x, uint32_t indent);
|
|
||||||
|
|
||||||
int ValueCompare(Value x, Value y);
|
int ValueCompare(Value x, Value y);
|
||||||
|
|
||||||
int ValueEqual(Value x, Value y);
|
int ValueEqual(Value x, Value y);
|
||||||
|
455
vm.c
455
vm.c
@ -467,259 +467,262 @@ int VMStart(VM * vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
Value temp, v1, v2;
|
||||||
uint16_t opcode = *vm->pc;
|
uint16_t opcode = *vm->pc;
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
Value temp, v1, v2;
|
|
||||||
|
|
||||||
#define DO_BINARY_MATH(op) \
|
#define DO_BINARY_MATH(op) \
|
||||||
v1 = vm->base[vm->pc[2]]; \
|
v1 = vm->base[vm->pc[2]]; \
|
||||||
v2 = vm->base[vm->pc[3]]; \
|
v2 = vm->base[vm->pc[3]]; \
|
||||||
VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \
|
VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \
|
||||||
VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \
|
VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \
|
||||||
temp.type = TYPE_NUMBER; \
|
temp.type = TYPE_NUMBER; \
|
||||||
temp.data.number = v1.data.number op v2.data.number; \
|
temp.data.number = v1.data.number op v2.data.number; \
|
||||||
vm->base[vm->pc[1]] = temp; \
|
vm->base[vm->pc[1]] = temp; \
|
||||||
vm->pc += 4; \
|
vm->pc += 4; \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_ADD: /* Addition */
|
case VM_OP_ADD: /* Addition */
|
||||||
DO_BINARY_MATH(+)
|
DO_BINARY_MATH(+)
|
||||||
|
|
||||||
case VM_OP_SUB: /* Subtraction */
|
case VM_OP_SUB: /* Subtraction */
|
||||||
DO_BINARY_MATH(-)
|
DO_BINARY_MATH(-)
|
||||||
|
|
||||||
case VM_OP_MUL: /* Multiplication */
|
case VM_OP_MUL: /* Multiplication */
|
||||||
DO_BINARY_MATH(*)
|
DO_BINARY_MATH(*)
|
||||||
|
|
||||||
case VM_OP_DIV: /* Division */
|
case VM_OP_DIV: /* Division */
|
||||||
DO_BINARY_MATH(/)
|
DO_BINARY_MATH(/)
|
||||||
|
|
||||||
#undef DO_BINARY_MATH
|
#undef DO_BINARY_MATH
|
||||||
|
|
||||||
case VM_OP_NOT: /* Boolean unary (Boolean not) */
|
case VM_OP_NOT: /* Boolean unary (Boolean not) */
|
||||||
temp.type = TYPE_BOOLEAN;
|
temp.type = TYPE_BOOLEAN;
|
||||||
temp.data.boolean = !truthy(vm->base[vm->pc[2]]);
|
temp.data.boolean = !truthy(vm->base[vm->pc[2]]);
|
||||||
vm->base[vm->pc[1]] = temp;
|
vm->base[vm->pc[1]] = temp;
|
||||||
vm->pc += 3;
|
vm->pc += 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_LD0: /* Load 0 */
|
case VM_OP_LD0: /* Load 0 */
|
||||||
temp.type = TYPE_NUMBER;
|
temp.type = TYPE_NUMBER;
|
||||||
temp.data.number = 0;
|
temp.data.number = 0;
|
||||||
vm->base[vm->pc[1]] = temp;
|
vm->base[vm->pc[1]] = temp;
|
||||||
vm->pc += 2;
|
vm->pc += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_LD1: /* Load 1 */
|
case VM_OP_LD1: /* Load 1 */
|
||||||
temp.type = TYPE_NUMBER;
|
temp.type = TYPE_NUMBER;
|
||||||
temp.data.number = 1;
|
temp.data.number = 1;
|
||||||
vm->base[vm->pc[1]] = temp;
|
vm->base[vm->pc[1]] = temp;
|
||||||
vm->pc += 2;
|
vm->pc += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_FLS: /* Load False */
|
case VM_OP_FLS: /* Load False */
|
||||||
temp.type = TYPE_BOOLEAN;
|
temp.type = TYPE_BOOLEAN;
|
||||||
temp.data.boolean = 0;
|
temp.data.boolean = 0;
|
||||||
vm->base[vm->pc[1]] = temp;
|
vm->base[vm->pc[1]] = temp;
|
||||||
vm->pc += 2;
|
vm->pc += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_TRU: /* Load True */
|
case VM_OP_TRU: /* Load True */
|
||||||
temp.type = TYPE_BOOLEAN;
|
temp.type = TYPE_BOOLEAN;
|
||||||
temp.data.boolean = 1;
|
temp.data.boolean = 1;
|
||||||
vm->base[vm->pc[1]] = temp;
|
vm->base[vm->pc[1]] = temp;
|
||||||
vm->pc += 2;
|
vm->pc += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_NIL: /* Load Nil */
|
case VM_OP_NIL: /* Load Nil */
|
||||||
temp.type = TYPE_NIL;
|
temp.type = TYPE_NIL;
|
||||||
vm->base[vm->pc[1]] = temp;
|
vm->base[vm->pc[1]] = temp;
|
||||||
vm->pc += 2;
|
vm->pc += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_I16: /* Load Small Integer */
|
case VM_OP_I16: /* Load Small Integer */
|
||||||
temp.type = TYPE_NUMBER;
|
temp.type = TYPE_NUMBER;
|
||||||
temp.data.number = ((int16_t *)(vm->pc))[2];
|
temp.data.number = ((int16_t *)(vm->pc))[2];
|
||||||
vm->base[vm->pc[1]] = temp;
|
vm->base[vm->pc[1]] = temp;
|
||||||
vm->pc += 3;
|
vm->pc += 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VM_OP_UPV: /* Load Up Value */
|
case VM_OP_UPV: /* Load Up Value */
|
||||||
temp = vm->frame->callee;
|
temp = vm->frame->callee;
|
||||||
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
|
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
|
||||||
vm->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]);
|
vm->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]);
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_JIF: /* Jump If */
|
||||||
|
if (truthy(vm->base[vm->pc[1]])) {
|
||||||
vm->pc += 4;
|
vm->pc += 4;
|
||||||
break;
|
} else {
|
||||||
|
vm->pc += *((int32_t *)(vm->pc + 2));
|
||||||
case VM_OP_JIF: /* Jump If */
|
|
||||||
if (truthy(vm->base[vm->pc[1]])) {
|
|
||||||
vm->pc += 4;
|
|
||||||
} else {
|
|
||||||
vm->pc += *((int32_t *)(vm->pc + 2));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_JMP: /* Jump */
|
|
||||||
vm->pc += *((int32_t *)(vm->pc + 1));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_CAL: /* Call */
|
|
||||||
VMCallOp(vm);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_RET: /* Return */
|
|
||||||
VMReturn(vm, vm->base[vm->pc[1]]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_SUV: /* Set Up Value */
|
|
||||||
temp = vm->frame->callee;
|
|
||||||
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
|
|
||||||
*GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]];
|
|
||||||
vm->pc += 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_CST: /* Load constant value */
|
|
||||||
temp = vm->frame->callee;
|
|
||||||
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
|
|
||||||
vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]);
|
|
||||||
vm->pc += 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_I32: /* Load 32 bit integer */
|
|
||||||
temp.type = TYPE_NUMBER;
|
|
||||||
temp.data.number = *((int32_t *)(vm->pc + 2));
|
|
||||||
vm->base[vm->pc[1]] = temp;
|
|
||||||
vm->pc += 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_F64: /* Load 64 bit float */
|
|
||||||
temp.type = TYPE_NUMBER;
|
|
||||||
temp.data.number = (Number) *((double *)(vm->pc + 2));
|
|
||||||
vm->base[vm->pc[1]] = temp;
|
|
||||||
vm->pc += 6;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_MOV: /* Move Values */
|
|
||||||
vm->base[vm->pc[1]] = vm->base[vm->pc[2]];
|
|
||||||
vm->pc += 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_CLN: /* Create closure from constant FuncDef */
|
|
||||||
vm->base[vm->pc[1]] = VMMakeClosure(vm, vm->pc[2]);
|
|
||||||
vm->pc += 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_EQL: /* Equality */
|
|
||||||
temp.type = TYPE_BOOLEAN;
|
|
||||||
temp.data.boolean = ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]);
|
|
||||||
vm->base[vm->pc[1]] = temp;
|
|
||||||
vm->pc += 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_LTN: /* Less Than */
|
|
||||||
temp.type = TYPE_BOOLEAN;
|
|
||||||
temp.data.boolean = (ValueCompare(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) == -1);
|
|
||||||
vm->base[vm->pc[1]] = temp;
|
|
||||||
vm->pc += 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_LTE: /* Less Than or Equal to */
|
|
||||||
temp.type = TYPE_BOOLEAN;
|
|
||||||
temp.data.boolean = (ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) != 1);
|
|
||||||
vm->base[vm->pc[1]] = temp;
|
|
||||||
vm->pc += 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_ARR: /* Array literal */
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
uint32_t arrayLen = vm->pc[2];
|
|
||||||
Array * array = ArrayNew(vm, arrayLen);
|
|
||||||
array->count = arrayLen;
|
|
||||||
for (i = 0; i < arrayLen; ++i)
|
|
||||||
array->data[i] = vm->base[vm->pc[3 + i]];
|
|
||||||
temp.type = TYPE_ARRAY;
|
|
||||||
temp.data.array = array;
|
|
||||||
vm->base[vm->pc[1]] = temp;
|
|
||||||
vm->pc += 3 + arrayLen;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_DIC: /* Dictionary literal */
|
|
||||||
{
|
|
||||||
uint32_t i = 3;
|
|
||||||
uint32_t kvs = vm->pc[2];
|
|
||||||
Dictionary * dict = DictNew(vm, kvs + 2);
|
|
||||||
kvs = kvs + 3;
|
|
||||||
while (i < kvs) {
|
|
||||||
v1 = vm->base[vm->pc[i++]];
|
|
||||||
v2 = vm->base[vm->pc[i++]];
|
|
||||||
DictPut(vm, dict, v1, v2);
|
|
||||||
}
|
|
||||||
temp.type = TYPE_DICTIONARY;
|
|
||||||
temp.data.dict = dict;
|
|
||||||
vm->base[vm->pc[1]] = temp;
|
|
||||||
vm->pc += kvs;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VM_OP_TCL: /* Tail call */
|
|
||||||
VMTailCallOp(vm);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Macro for generating some math operators */
|
|
||||||
#define DO_MULTI_MATH(op, start) { \
|
|
||||||
uint16_t count = vm->pc[2]; \
|
|
||||||
uint16_t i; \
|
|
||||||
Number accum = start; \
|
|
||||||
for (i = 0; i < count; ++i) { \
|
|
||||||
v1 = vm->base[vm->pc[3 + i]]; \
|
|
||||||
VMAssert(vm, v1.type == TYPE_NUMBER, "Expected number"); \
|
|
||||||
accum = accum op v1.data.number; \
|
|
||||||
} \
|
|
||||||
temp.type = TYPE_NUMBER; \
|
|
||||||
temp.data.number = accum; \
|
|
||||||
vm->base[vm->pc[1]] = temp; \
|
|
||||||
vm->pc += 3 + count; \
|
|
||||||
break; \
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
/* Vectorized math */
|
case VM_OP_JMP: /* Jump */
|
||||||
case VM_OP_ADM:
|
vm->pc += *((int32_t *)(vm->pc + 1));
|
||||||
DO_MULTI_MATH(+, 0)
|
break;
|
||||||
|
|
||||||
case VM_OP_SBM:
|
case VM_OP_CAL: /* Call */
|
||||||
DO_MULTI_MATH(-, 0)
|
VMCallOp(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
case VM_OP_MUM:
|
case VM_OP_RET: /* Return */
|
||||||
DO_MULTI_MATH(*, 1)
|
VMReturn(vm, vm->base[vm->pc[1]]);
|
||||||
|
break;
|
||||||
|
|
||||||
case VM_OP_DVM:
|
case VM_OP_SUV: /* Set Up Value */
|
||||||
DO_MULTI_MATH(/, 1)
|
temp = vm->frame->callee;
|
||||||
|
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
|
||||||
|
*GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]];
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
#undef DO_MULTI_MATH
|
case VM_OP_CST: /* Load constant value */
|
||||||
|
temp = vm->frame->callee;
|
||||||
|
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
|
||||||
|
vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]);
|
||||||
|
vm->pc += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
case VM_OP_RTN: /* Return nil */
|
case VM_OP_I32: /* Load 32 bit integer */
|
||||||
temp.type = TYPE_NIL;
|
temp.type = TYPE_NUMBER;
|
||||||
VMReturn(vm, temp);
|
temp.data.number = *((int32_t *)(vm->pc + 2));
|
||||||
break;
|
vm->base[vm->pc[1]] = temp;
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
case VM_OP_GET:
|
case VM_OP_F64: /* Load 64 bit float */
|
||||||
temp = ValueGet(vm, vm->base[vm->pc[2]], vm->base[vm->pc[3]]);
|
temp.type = TYPE_NUMBER;
|
||||||
vm->base[vm->pc[1]] = temp;
|
temp.data.number = (Number) *((double *)(vm->pc + 2));
|
||||||
vm->pc += 4;
|
vm->base[vm->pc[1]] = temp;
|
||||||
break;
|
vm->pc += 6;
|
||||||
|
break;
|
||||||
|
|
||||||
case VM_OP_SET:
|
case VM_OP_MOV: /* Move Values */
|
||||||
ValueSet(vm, vm->base[vm->pc[1]], vm->base[vm->pc[2]], vm->base[vm->pc[3]]);
|
vm->base[vm->pc[1]] = vm->base[vm->pc[2]];
|
||||||
vm->pc += 4;
|
vm->pc += 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case VM_OP_CLN: /* Create closure from constant FuncDef */
|
||||||
VMError(vm, "Unknown opcode");
|
vm->base[vm->pc[1]] = VMMakeClosure(vm, vm->pc[2]);
|
||||||
break;
|
vm->pc += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_EQL: /* Equality */
|
||||||
|
temp.type = TYPE_BOOLEAN;
|
||||||
|
temp.data.boolean = ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]);
|
||||||
|
vm->base[vm->pc[1]] = temp;
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_LTN: /* Less Than */
|
||||||
|
temp.type = TYPE_BOOLEAN;
|
||||||
|
temp.data.boolean = (ValueCompare(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) == -1);
|
||||||
|
vm->base[vm->pc[1]] = temp;
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_LTE: /* Less Than or Equal to */
|
||||||
|
temp.type = TYPE_BOOLEAN;
|
||||||
|
temp.data.boolean = (ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) != 1);
|
||||||
|
vm->base[vm->pc[1]] = temp;
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_ARR: /* Array literal */
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t arrayLen = vm->pc[2];
|
||||||
|
Array * array = ArrayNew(vm, arrayLen);
|
||||||
|
array->count = arrayLen;
|
||||||
|
for (i = 0; i < arrayLen; ++i)
|
||||||
|
array->data[i] = vm->base[vm->pc[3 + i]];
|
||||||
|
temp.type = TYPE_ARRAY;
|
||||||
|
temp.data.array = array;
|
||||||
|
vm->base[vm->pc[1]] = temp;
|
||||||
|
vm->pc += 3 + arrayLen;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_DIC: /* Dictionary literal */
|
||||||
|
{
|
||||||
|
uint32_t i = 3;
|
||||||
|
uint32_t kvs = vm->pc[2];
|
||||||
|
Dictionary * dict = DictNew(vm, kvs + 2);
|
||||||
|
kvs = kvs + 3;
|
||||||
|
while (i < kvs) {
|
||||||
|
v1 = vm->base[vm->pc[i++]];
|
||||||
|
v2 = vm->base[vm->pc[i++]];
|
||||||
|
DictPut(vm, dict, v1, v2);
|
||||||
|
}
|
||||||
|
temp.type = TYPE_DICTIONARY;
|
||||||
|
temp.data.dict = dict;
|
||||||
|
vm->base[vm->pc[1]] = temp;
|
||||||
|
vm->pc += kvs;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_TCL: /* Tail call */
|
||||||
|
VMTailCallOp(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Macro for generating some math operators */
|
||||||
|
#define DO_MULTI_MATH(op, start) { \
|
||||||
|
uint16_t count = vm->pc[2]; \
|
||||||
|
uint16_t i; \
|
||||||
|
Number accum = start; \
|
||||||
|
for (i = 0; i < count; ++i) { \
|
||||||
|
v1 = vm->base[vm->pc[3 + i]]; \
|
||||||
|
VMAssert(vm, v1.type == TYPE_NUMBER, "Expected number"); \
|
||||||
|
accum = accum op v1.data.number; \
|
||||||
|
} \
|
||||||
|
temp.type = TYPE_NUMBER; \
|
||||||
|
temp.data.number = accum; \
|
||||||
|
vm->base[vm->pc[1]] = temp; \
|
||||||
|
vm->pc += 3 + count; \
|
||||||
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Vectorized math */
|
||||||
|
case VM_OP_ADM:
|
||||||
|
DO_MULTI_MATH(+, 0)
|
||||||
|
|
||||||
|
case VM_OP_SBM:
|
||||||
|
DO_MULTI_MATH(-, 0)
|
||||||
|
|
||||||
|
case VM_OP_MUM:
|
||||||
|
DO_MULTI_MATH(*, 1)
|
||||||
|
|
||||||
|
case VM_OP_DVM:
|
||||||
|
DO_MULTI_MATH(/, 1)
|
||||||
|
|
||||||
|
#undef DO_MULTI_MATH
|
||||||
|
|
||||||
|
case VM_OP_RTN: /* Return nil */
|
||||||
|
temp.type = TYPE_NIL;
|
||||||
|
VMReturn(vm, temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_GET:
|
||||||
|
temp = ValueGet(vm, vm->base[vm->pc[2]], vm->base[vm->pc[3]]);
|
||||||
|
vm->base[vm->pc[1]] = temp;
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VM_OP_SET:
|
||||||
|
ValueSet(vm, vm->base[vm->pc[1]], vm->base[vm->pc[2]], vm->base[vm->pc[3]]);
|
||||||
|
vm->pc += 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
VMError(vm, "Unknown opcode");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move collection only to places that allocate memory */
|
||||||
|
/* This, however, is good for testing */
|
||||||
VMMaybeCollect(vm);
|
VMMaybeCollect(vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,6 +756,10 @@ void VMInit(VM * vm) {
|
|||||||
/* Garbage collection */
|
/* Garbage collection */
|
||||||
vm->blocks = NULL;
|
vm->blocks = NULL;
|
||||||
vm->nextCollection = 0;
|
vm->nextCollection = 0;
|
||||||
|
/* Setting memoryInterval to zero currently forces
|
||||||
|
* a collection pretty much every cycle, which is
|
||||||
|
* obviously horrible for performance. It helps ensure
|
||||||
|
* there are no memory bugs during dev */
|
||||||
vm->memoryInterval = 0;
|
vm->memoryInterval = 0;
|
||||||
vm->black = 0;
|
vm->black = 0;
|
||||||
vm->lock = 0;
|
vm->lock = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user