pocketlang/src/var.c

190 lines
4.6 KiB
C
Raw Normal View History

2021-02-07 15:40:00 +08:00
/*
* Copyright (c) 2020-2021 Thakee Nathees
* Licensed under: MIT License
*/
#include "var.h"
#include "vm.h"
2021-02-12 01:35:43 +08:00
// Number of maximum digits for to_string buffer.
#define TO_STRING_BUFF_SIZE 128
2021-02-08 02:30:29 +08:00
void varInitObject(Object* self, MSVM* vm, ObjectType type) {
2021-02-12 01:35:43 +08:00
self->type = type;
self->next = vm->first;
vm->first = self;
// TODO: set isGray = false;
2021-02-07 15:40:00 +08:00
}
#if VAR_NAN_TAGGING
// A union to reinterpret a double as raw bits and back.
typedef union {
2021-02-12 01:35:43 +08:00
uint64_t bits64;
uint32_t bits32[2];
double num;
2021-02-07 15:40:00 +08:00
} _DoubleBitsConv;
#endif
Var doubleToVar(double value) {
#if VAR_NAN_TAGGING
2021-02-12 01:35:43 +08:00
_DoubleBitsConv bits;
bits.num = value;
return bits.bits64;
2021-02-07 15:40:00 +08:00
#else
2021-02-12 01:35:43 +08:00
// TODO:
2021-02-07 15:40:00 +08:00
#endif // VAR_NAN_TAGGING
}
2021-02-11 01:23:48 +08:00
double varToDouble(Var value) {
2021-02-07 15:40:00 +08:00
#if VAR_NAN_TAGGING
2021-02-12 01:35:43 +08:00
_DoubleBitsConv bits;
bits.bits64 = value;
return bits.num;
2021-02-07 15:40:00 +08:00
#else
2021-02-12 01:35:43 +08:00
// TODO:
2021-02-07 15:40:00 +08:00
#endif // VAR_NAN_TAGGING
}
2021-02-08 02:30:29 +08:00
String* newString(MSVM* vm, const char* text, uint32_t length) {
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
ASSERT(length == 0 || text != NULL, "Unexpected NULL string.");
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
String* string = ALLOCATE_DYNAMIC(vm, String, length + 1, char);
varInitObject(&string->_super, vm, OBJ_STRING);
string->length = length;
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
if (length != 0) memcpy(string->data, text, length);
string->data[length] = '\0';
return string;
2021-02-07 15:40:00 +08:00
}
2021-02-13 01:40:19 +08:00
List* newList(MSVM* vm, uint32_t size) {
List* list = ALLOCATE(vm, List);
varInitObject(&list->_super, vm, OBJ_LIST);
varBufferInit(&list->elements);
if (size > 0) {
varBufferFill(&list->elements, vm, VAR_NULL, size);
list->elements.count = 0;
}
2021-02-13 21:57:59 +08:00
return list;
2021-02-13 01:40:19 +08:00
}
Range* newRange(MSVM* vm, double from, double to) {
Range* range = ALLOCATE(vm, Range);
varInitObject(&range->_super, vm, OBJ_RANGE);
range->from = from;
range->to = to;
return range;
}
2021-02-08 02:30:29 +08:00
Script* newScript(MSVM* vm) {
2021-02-12 01:35:43 +08:00
Script* script = ALLOCATE(vm, Script);
varInitObject(&script->_super, vm, OBJ_SCRIPT);
varBufferInit(&script->globals);
nameTableInit(&script->global_names);
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
varBufferInit(&script->literals);
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
vmPushTempRef(vm, &script->_super);
script->body = newFunction(vm, "@(ScriptLevel)", script, false);
vmPopTempRef(vm);
2021-02-09 16:21:10 +08:00
2021-02-12 01:35:43 +08:00
functionBufferInit(&script->functions);
nameTableInit(&script->function_names);
2021-02-09 16:21:10 +08:00
2021-02-12 01:35:43 +08:00
stringBufferInit(&script->names);
2021-02-11 01:23:48 +08:00
2021-02-12 01:35:43 +08:00
return script;
2021-02-07 15:40:00 +08:00
}
2021-02-08 02:30:29 +08:00
Function* newFunction(MSVM* vm, const char* name, Script* owner,
2021-02-07 15:40:00 +08:00
bool is_native) {
2021-02-12 01:35:43 +08:00
Function* func = ALLOCATE(vm, Function);
varInitObject(&func->_super, vm, OBJ_FUNC);
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
func->name = name;
func->owner = owner;
2021-02-13 01:40:19 +08:00
func->arity = -2; // -1 means variadic args.
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
func->is_native = is_native;
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
if (is_native) {
func->native = NULL;
} else {
vmPushTempRef(vm, &func->_super);
Fn* fn = ALLOCATE(vm, Fn);
vmPopTempRef(vm);
2021-02-07 15:40:00 +08:00
2021-02-12 01:35:43 +08:00
byteBufferInit(&fn->opcodes);
intBufferInit(&fn->oplines);
fn->stack_size = 0;
func->fn = fn;
}
return func;
2021-02-07 15:40:00 +08:00
}
2021-02-09 16:21:10 +08:00
2021-02-11 01:23:48 +08:00
// Utility functions //////////////////////////////////////////////////////////
2021-02-09 16:21:10 +08:00
bool isVauesSame(Var v1, Var v2) {
#if VAR_NAN_TAGGING
2021-02-12 01:35:43 +08:00
// Bit representation of each values are unique so just compare the bits.
return v1 == v2;
2021-02-09 16:21:10 +08:00
#else
#error TODO:
#endif
2021-02-11 01:23:48 +08:00
}
2021-02-12 01:35:43 +08:00
2021-02-13 01:40:19 +08:00
String* toString(MSVM* vm, Var v, bool recursive) {
2021-02-12 01:35:43 +08:00
if (IS_NULL(v)) {
return newString(vm, "null", 4);
} else if (IS_BOOL(v)) {
if (AS_BOOL(v)) {
return newString(vm, "true", 4);
} else {
return newString(vm, "false", 5);
}
} else if (IS_NUM(v)) {
char buff[TO_STRING_BUFF_SIZE];
int length = sprintf(buff, "%.14g", AS_NUM(v));
ASSERT(length < TO_STRING_BUFF_SIZE, "Buffer overflowed.");
return newString(vm, buff, length);
} else if (IS_OBJ(v)) {
Object* obj = AS_OBJ(v);
switch (obj->type) {
case OBJ_STRING:
2021-02-13 01:40:19 +08:00
{
// If recursive return with quotes (ex: [42, "hello", 0..10])
if (!recursive)
return newString(vm, ((String*)obj)->data, ((String*)obj)->length);
TODO; //< Add quotes around the string.
2021-02-12 01:35:43 +08:00
break;
2021-02-13 01:40:19 +08:00
}
2021-02-12 01:35:43 +08:00
2021-02-13 01:40:19 +08:00
case OBJ_LIST: return newString(vm, "[Array]", 7); // TODO;
case OBJ_MAP: return newString(vm, "[Map]", 5); // TODO;
case OBJ_RANGE: return newString(vm, "[Range]", 7); // TODO;
case OBJ_SCRIPT: return newString(vm, "[Script]", 8); // TODO;
case OBJ_FUNC: {
const char* name = ((Function*)obj)->name;
int length = (int)strlen(name); // TODO: Assert length.
char buff[TO_STRING_BUFF_SIZE];
memcpy(buff, "[func:", 6);
memcpy(buff + 6, name, length);
buff[6 + length] = ']';
return newString(vm, buff, 6 + length + 1);
}
case OBJ_USER: return newString(vm, "[UserObj]", 9); // TODO;
2021-02-12 01:35:43 +08:00
break;
}
}
UNREACHABLE();
return NULL;
}