pocketlang/src/core.c

196 lines
5.4 KiB
C
Raw Normal View History

2021-02-11 01:23:48 +08:00
/*
* Copyright (c) 2021 Thakee Nathees
* Licensed under: MIT License
*/
#include "core.h"
#include "vm.h"
2021-02-12 01:35:43 +08:00
typedef struct {
const char* name; //< Name of the function.
int length; //< Length of the name.
Function fn; //< Native function pointer.
} _BuiltinFn;
// Count of builtin function +1 for termination.
#define BUILTIN_COUNT 50
2021-02-12 01:35:43 +08:00
// Array of all builtin functions.
_BuiltinFn builtins[BUILTIN_COUNT];
static void initializeBuiltinFN(MSVM* vm, _BuiltinFn* bfn, const char* name,
int arity, MiniScriptNativeFn ptr) {
bfn->name = name;
bfn->length = (name != NULL) ? (int)strlen(name) : 0;
varInitObject(&bfn->fn._super, vm, OBJ_FUNC);
bfn->fn.name = name;
bfn->fn.arity = arity;
bfn->fn.owner = NULL;
bfn->fn.is_native = true;
bfn->fn.native = ptr;
}
int findBuiltinFunction(const char* name, int length) {
for (int i = 0; i < BUILTIN_COUNT; i++) {
if (builtins[i].name == NULL) return -1;
if (length == builtins[i].length && strncmp(name, builtins[i].name, length) == 0) {
return i;
}
}
return -1;
}
Function* getBuiltinFunction(int index) {
ASSERT(index < BUILTIN_COUNT, "Index out of bound.");
return &builtins[index].fn;
}
#define FN_IS_PRIMITE_TYPE(name, check) \
void coreIs##name(MSVM* vm) { \
vm->rbp[0] = VAR_BOOL(check(vm->rbp[1])); \
}
#define FN_IS_OBJ_TYPE(name, _enum) \
void coreIs##name(MSVM* vm) { \
Var arg1 = vm->rbp[1]; \
if (IS_OBJ(arg1) && AS_OBJ(arg1)->type == _enum) { \
vm->rbp[0] = VAR_TRUE; \
} else { \
vm->rbp[0] = VAR_FALSE; \
} \
}
FN_IS_PRIMITE_TYPE(Null, IS_NULL)
FN_IS_PRIMITE_TYPE(Bool, IS_BOOL)
FN_IS_PRIMITE_TYPE(Num, IS_NUM)
FN_IS_OBJ_TYPE(String, OBJ_STRING)
FN_IS_OBJ_TYPE(Array, OBJ_ARRAY)
FN_IS_OBJ_TYPE(Map, OBJ_MAP)
FN_IS_OBJ_TYPE(Range, OBJ_RANGE)
FN_IS_OBJ_TYPE(Function, OBJ_FUNC)
FN_IS_OBJ_TYPE(Script, OBJ_SCRIPT)
FN_IS_OBJ_TYPE(UserObj, OBJ_USER)
2021-02-12 01:35:43 +08:00
void coreToString(MSVM* vm) {
Var arg1 = vm->rbp[1];
vm->rbp[0] = VAR_OBJ(&toString(vm, arg1)->_super);
}
void corePrint(MSVM* vm) {
Var arg1 = vm->rbp[1];
String* str; //< Will be cleaned by garbage collector;
// If it's already a string don't allocate a new string instead use it.
if (IS_OBJ(arg1) && AS_OBJ(arg1)->type == OBJ_STRING) {
str = (String*)AS_OBJ(arg1);
} else {
str = toString(vm, arg1);
}
vm->config.write_fn(vm, str->data);
vm->config.write_fn(vm, "\n");
}
void coreImport(MSVM* vm) {
Var arg1 = vm->rbp[1];
if (IS_OBJ(arg1) && AS_OBJ(arg1)->type == OBJ_STRING) {
TODO;
} else {
msSetRuntimeError(vm, "Expected a String argument.");
}
}
2021-02-12 01:35:43 +08:00
void initializeCore(MSVM* vm) {
int i = 0; //< Iterate through builtins.
2021-02-12 01:35:43 +08:00
// Initialize builtin functions.
initializeBuiltinFN(vm, &builtins[i++], "is_null", 1, coreIsNull);
initializeBuiltinFN(vm, &builtins[i++], "is_bool", 1, coreIsBool);
initializeBuiltinFN(vm, &builtins[i++], "is_num", 1, coreIsNum);
initializeBuiltinFN(vm, &builtins[i++], "is_string", 1, coreIsString);
initializeBuiltinFN(vm, &builtins[i++], "is_array", 1, coreIsArray);
initializeBuiltinFN(vm, &builtins[i++], "is_map", 1, coreIsMap);
initializeBuiltinFN(vm, &builtins[i++], "is_range", 1, coreIsRange);
initializeBuiltinFN(vm, &builtins[i++], "is_function", 1, coreIsFunction);
initializeBuiltinFN(vm, &builtins[i++], "is_script", 1, coreIsScript);
initializeBuiltinFN(vm, &builtins[i++], "is_userobj", 1, coreIsUserObj);
2021-02-12 01:35:43 +08:00
initializeBuiltinFN(vm, &builtins[i++], "to_string", 1, coreToString);
initializeBuiltinFN(vm, &builtins[i++], "print", 1, corePrint);
initializeBuiltinFN(vm, &builtins[i++], "import", 1, coreImport);
2021-02-12 01:35:43 +08:00
// Sentinal to mark the end of the array.
initializeBuiltinFN(vm, &builtins[i], NULL, 0, NULL);
}
2021-02-11 01:23:48 +08:00
// Validators /////////////////////////////////////////////////////////////////
// Check if a numeric value bool/number and set [value].
bool isNumeric(Var var, double* value) {
2021-02-12 01:35:43 +08:00
if (IS_BOOL(var)) {
*value = AS_BOOL(var);
return true;
}
if (IS_NUM(var)) {
*value = AS_NUM(var);
return true;
}
return false;
2021-02-11 01:23:48 +08:00
}
// Check if [var] is bool/number. if not set error and return false.
bool validateNumeric(MSVM* vm, Var var, double* value, const char* arg) {
2021-02-12 01:35:43 +08:00
if (isNumeric(var, value)) return true;
msSetRuntimeError(vm, "%s must be a numeric value.", arg);
return false;
2021-02-11 01:23:48 +08:00
}
// Operators //////////////////////////////////////////////////////////////////
Var varAdd(MSVM* vm, Var v1, Var v2) {
2021-02-12 01:35:43 +08:00
double d1, d2;
if (isNumeric(v1, &d1)) {
if (validateNumeric(vm, v2, &d2, "Right operand")) {
return VAR_NUM(d1 + d2);
}
return VAR_NULL;
}
TODO; //string addition/ array addition etc.
2021-02-12 01:35:43 +08:00
return VAR_NULL;
2021-02-11 01:23:48 +08:00
}
Var varSubtract(MSVM* vm, Var v1, Var v2) {
TODO;
2021-02-12 01:35:43 +08:00
return VAR_NULL;
2021-02-11 01:23:48 +08:00
}
Var varMultiply(MSVM* vm, Var v1, Var v2) {
2021-02-12 01:35:43 +08:00
double d1, d2;
if (isNumeric(v1, &d1)) {
if (validateNumeric(vm, v2, &d2, "Right operand")) {
return VAR_NUM(d1 * d2);
}
return VAR_NULL;
}
2021-02-11 01:23:48 +08:00
TODO;
2021-02-12 01:35:43 +08:00
return VAR_NULL;
2021-02-11 01:23:48 +08:00
}
Var varDivide(MSVM* vm, Var v1, Var v2) {
TODO;
2021-02-12 01:35:43 +08:00
return VAR_NULL;
}
bool varIterate(MSVM* vm, Var seq, Var* iterator, Var* value) {
TODO;
return false;
2021-02-11 01:23:48 +08:00
}