2013-11-10 06:01:18 +01:00
|
|
|
#include <math.h>
|
2013-10-28 06:45:40 +01:00
|
|
|
#include <stdio.h>
|
2013-10-27 19:28:15 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2013-11-22 17:55:22 +01:00
|
|
|
#include <time.h>
|
2013-10-27 19:28:15 +01:00
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
#include "wren_core.h"
|
2013-11-28 17:11:50 +01:00
|
|
|
#include "wren_value.h"
|
2013-10-27 19:28:15 +01:00
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
// Binds a native method named [name] (in Wren) implemented using C function
|
|
|
|
|
// [fn] to `ObjClass` [cls].
|
|
|
|
|
#define NATIVE(cls, name, fn) \
|
2013-10-27 19:28:15 +01:00
|
|
|
{ \
|
2013-11-09 20:18:27 +01:00
|
|
|
int symbol = ensureSymbol(&vm->methods, name, strlen(name)); \
|
2013-10-28 06:45:40 +01:00
|
|
|
cls->methods[symbol].type = METHOD_PRIMITIVE; \
|
2013-11-28 17:00:55 +01:00
|
|
|
cls->methods[symbol].primitive = native_##fn; \
|
2013-10-27 19:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
// Binds a "fiber native" method named [name] (in Wren) implemented using C
|
|
|
|
|
// function [fn] to `ObjClass` [cls]. Unlike regular native methods, fiber
|
|
|
|
|
// natives have access to the fiber itself and can do lower-level stuff like
|
|
|
|
|
// pushing callframes.
|
|
|
|
|
#define FIBER_NATIVE(cls, name, fn) \
|
2013-11-17 18:02:57 +01:00
|
|
|
{ \
|
|
|
|
|
int symbol = ensureSymbol(&vm->methods, name, strlen(name)); \
|
|
|
|
|
cls->methods[symbol].type = METHOD_FIBER; \
|
2013-11-28 17:00:55 +01:00
|
|
|
cls->methods[symbol].fiberPrimitive = native_##fn; \
|
2013-11-17 18:02:57 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
// Defines a native method whose C function name is [native]. This abstracts
|
|
|
|
|
// the actual type signature of a native function and makes it clear which C
|
|
|
|
|
// functions are intended to be invoked as natives.
|
|
|
|
|
#define DEF_NATIVE(native) \
|
|
|
|
|
static Value native_##native(WrenVM* vm, Value* args)
|
2013-11-17 18:02:57 +01:00
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
// Defines a fiber native method whose C function name is [native].
|
|
|
|
|
#define DEF_FIBER_NATIVE(native) \
|
2013-12-22 23:31:33 +01:00
|
|
|
static void native_##native(WrenVM* vm, ObjFiber* fiber, Value* args)
|
2013-10-28 06:45:40 +01:00
|
|
|
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Tune these.
|
2013-11-28 17:00:55 +01:00
|
|
|
// The initial (and minimum) capacity of a non-empty list object.
|
2013-11-27 03:02:10 +01:00
|
|
|
#define LIST_MIN_CAPACITY (16)
|
2013-11-28 17:00:55 +01:00
|
|
|
|
|
|
|
|
// The rate at which a list's capacity grows when the size exceeds the current
|
|
|
|
|
// capacity. The new capacity will be determined by *multiplying* the old
|
|
|
|
|
// capacity by this. Growing geometrically is necessary to ensure that adding
|
|
|
|
|
// to a list has O(1) amortized complexity.
|
2013-11-27 03:02:10 +01:00
|
|
|
#define LIST_GROW_FACTOR (2)
|
|
|
|
|
|
2013-12-22 20:50:00 +01:00
|
|
|
// This string literal is generated automatically from corelib.wren using
|
|
|
|
|
// make_corelib. Do not edit here.
|
|
|
|
|
const char* coreLibSource =
|
|
|
|
|
"class IO {\n"
|
|
|
|
|
" static write(obj) {\n"
|
|
|
|
|
" IO.write__native__(obj.toString)\n"
|
|
|
|
|
" return obj\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"class List {\n"
|
|
|
|
|
" toString {\n"
|
|
|
|
|
" var result = \"[\"\n"
|
|
|
|
|
" var i = 0\n"
|
|
|
|
|
" // TODO: Use for loop.\n"
|
|
|
|
|
" while (i < this.count) {\n"
|
|
|
|
|
" if (i > 0) result = result + \", \"\n"
|
|
|
|
|
" result = result + this[i].toString\n"
|
|
|
|
|
" i = i + 1\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" result = result + \"]\"\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"}\n";
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(bool_not)
|
2013-11-13 16:10:52 +01:00
|
|
|
{
|
2013-11-16 20:35:59 +01:00
|
|
|
return BOOL_VAL(!AS_BOOL(args[0]));
|
2013-11-13 16:10:52 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(bool_toString)
|
2013-11-04 06:38:58 +01:00
|
|
|
{
|
|
|
|
|
if (AS_BOOL(args[0]))
|
|
|
|
|
{
|
refactor: rename internal value creation functions to wren-prefixed public API names
Move `allocate`, `initObj`, `newClass`, and related static helpers from `vm.c` into `value.c` with consistent `wren` prefix, and update all call sites in `compiler.c`, `primitives.c`, and `vm.c` to use the new names (`wrenNewFunction`, `wrenNewString`, `wrenNewClass`, `wrenNewInstance`, `wrenNewList`). Remove the old declarations from `vm.h` and add comprehensive documentation comments to `value.h` explaining the NaN-tagging representation and type system.
2013-11-28 05:00:03 +01:00
|
|
|
return wrenNewString(vm, "true", 4);
|
2013-11-04 06:38:58 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
refactor: rename internal value creation functions to wren-prefixed public API names
Move `allocate`, `initObj`, `newClass`, and related static helpers from `vm.c` into `value.c` with consistent `wren` prefix, and update all call sites in `compiler.c`, `primitives.c`, and `vm.c` to use the new names (`wrenNewFunction`, `wrenNewString`, `wrenNewClass`, `wrenNewInstance`, `wrenNewList`). Remove the old declarations from `vm.h` and add comprehensive documentation comments to `value.h` explaining the NaN-tagging representation and type system.
2013-11-28 05:00:03 +01:00
|
|
|
return wrenNewString(vm, "false", 5);
|
2013-11-04 06:38:58 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-15 03:25:28 +01:00
|
|
|
// The call instruction leading to this primitive has one argument for the
|
|
|
|
|
// receiver plus as many arguments as were passed. When we push the block onto
|
|
|
|
|
// the callstack, we again use as many arguments. That ensures that the result
|
|
|
|
|
// of evaluating the block goes into the slot that the caller of *this*
|
|
|
|
|
// primitive is expecting.
|
feat: implement closures with upvalue support and statement/expression separation
Add closure objects that wrap functions with captured upvalues, enabling
first-class closures that close over local variables from enclosing scopes.
Introduce new bytecode instructions (CODE_CLOSURE, CODE_LOAD_UPVALUE,
CODE_STORE_UPVALUE, CODE_CLOSE_UPVALUE, CODE_RETURN) and a CompilerUpvalue
tracking system with a MAX_UPVALUES limit of 256. Refactor the grammar to
strictly separate statements from expressions, fixing a bug where block
expressions incorrectly popped locals while temporaries remained on the
stack. Rename internal functions (wrenCallFunction, wrenDebugDumpInstruction,
wrenDebugDumpStack) and add Upvalue allocation, closure creation, and
debug dump support for the new instructions.
2013-12-04 16:43:50 +01:00
|
|
|
DEF_FIBER_NATIVE(fn_call0) { wrenCallFunction(fiber, args[0], 1); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call1) { wrenCallFunction(fiber, args[0], 2); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call2) { wrenCallFunction(fiber, args[0], 3); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call3) { wrenCallFunction(fiber, args[0], 4); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call4) { wrenCallFunction(fiber, args[0], 5); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call5) { wrenCallFunction(fiber, args[0], 6); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call6) { wrenCallFunction(fiber, args[0], 7); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call7) { wrenCallFunction(fiber, args[0], 8); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call8) { wrenCallFunction(fiber, args[0], 9); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call9) { wrenCallFunction(fiber, args[0], 10); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call10) { wrenCallFunction(fiber, args[0], 11); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call11) { wrenCallFunction(fiber, args[0], 12); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call12) { wrenCallFunction(fiber, args[0], 13); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call13) { wrenCallFunction(fiber, args[0], 14); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call14) { wrenCallFunction(fiber, args[0], 15); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call15) { wrenCallFunction(fiber, args[0], 16); }
|
|
|
|
|
DEF_FIBER_NATIVE(fn_call16) { wrenCallFunction(fiber, args[0], 17); }
|
2013-11-15 03:25:28 +01:00
|
|
|
|
2013-11-27 08:11:11 +01:00
|
|
|
// Grows [list] if needed to ensure it can hold [count] elements.
|
|
|
|
|
static void ensureListCapacity(WrenVM* vm, ObjList* list, int count)
|
|
|
|
|
{
|
|
|
|
|
if (list->capacity >= count) return;
|
|
|
|
|
|
|
|
|
|
int capacity = list->capacity * LIST_GROW_FACTOR;
|
|
|
|
|
if (capacity < LIST_MIN_CAPACITY) capacity = LIST_MIN_CAPACITY;
|
|
|
|
|
|
|
|
|
|
list->capacity *= 2;
|
|
|
|
|
list->elements = wrenReallocate(vm, list->elements,
|
|
|
|
|
list->capacity * sizeof(Value), capacity * sizeof(Value));
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Handle allocation failure.
|
2013-11-27 08:11:11 +01:00
|
|
|
list->capacity = capacity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validates that [index] is an integer within `[0, count)`. Also allows
|
|
|
|
|
// negative indices which map backwards from the end. Returns the valid positive
|
|
|
|
|
// index value, or -1 if the index wasn't valid (not a number, not an int, out
|
|
|
|
|
// of bounds).
|
|
|
|
|
static int validateIndex(Value index, int count)
|
|
|
|
|
{
|
|
|
|
|
if (!IS_NUM(index)) return -1;
|
|
|
|
|
|
|
|
|
|
double indexNum = AS_NUM(index);
|
|
|
|
|
int intIndex = (int)indexNum;
|
|
|
|
|
// Make sure the index is an integer.
|
|
|
|
|
if (indexNum != intIndex) return -1;
|
|
|
|
|
|
|
|
|
|
// Negative indices count from the end.
|
|
|
|
|
if (indexNum < 0) indexNum = count + indexNum;
|
|
|
|
|
|
|
|
|
|
// Check bounds.
|
|
|
|
|
if (indexNum < 0 || indexNum >= count) return -1;
|
feat: implement closures with upvalue support and statement/expression separation
Add closure objects that wrap functions with captured upvalues, enabling
first-class closures that close over local variables from enclosing scopes.
Introduce new bytecode instructions (CODE_CLOSURE, CODE_LOAD_UPVALUE,
CODE_STORE_UPVALUE, CODE_CLOSE_UPVALUE, CODE_RETURN) and a CompilerUpvalue
tracking system with a MAX_UPVALUES limit of 256. Refactor the grammar to
strictly separate statements from expressions, fixing a bug where block
expressions incorrectly popped locals while temporaries remained on the
stack. Rename internal functions (wrenCallFunction, wrenDebugDumpInstruction,
wrenDebugDumpStack) and add Upvalue allocation, closure creation, and
debug dump support for the new instructions.
2013-12-04 16:43:50 +01:00
|
|
|
|
2013-11-27 08:11:11 +01:00
|
|
|
return indexNum;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(list_add)
|
2013-11-27 03:02:10 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
|
2013-11-27 08:11:11 +01:00
|
|
|
ensureListCapacity(vm, list, list->count + 1);
|
2013-11-27 03:02:10 +01:00
|
|
|
list->elements[list->count++] = args[1];
|
|
|
|
|
return args[1];
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(list_clear)
|
2013-11-27 08:11:11 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
2013-12-14 23:17:16 +01:00
|
|
|
wrenReallocate(vm, list->elements, 0, 0);
|
2013-12-22 23:31:33 +01:00
|
|
|
list->elements = NULL;
|
2013-11-27 08:11:11 +01:00
|
|
|
list->capacity = 0;
|
|
|
|
|
list->count = 0;
|
|
|
|
|
return NULL_VAL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(list_count)
|
2013-11-24 22:38:31 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
return NUM_VAL(list->count);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(list_insert)
|
2013-11-25 04:08:46 +01:00
|
|
|
{
|
2013-11-27 08:11:11 +01:00
|
|
|
ObjList* list = AS_LIST(args[0]);
|
2013-11-25 04:08:46 +01:00
|
|
|
|
feat: implement list_removeAt primitive with capacity shrink and test suite
Add DEF_PRIMITIVE(list_removeAt) to src/primitives.c that removes an element at a given index from an ObjList, shifts remaining elements up, shrinks capacity when excess is detected via LIST_GROW_FACTOR, and returns the removed Value. Register the primitive as "removeAt " on vm->listClass. Create test/list/remove_at.wren covering removal at positive indices 0,1,2, negative indices -1,-2,-3, out-of-bounds cases returning null, and verification that the removed value is returned.
2013-11-27 19:20:32 +01:00
|
|
|
// count + 1 here so you can "insert" at the very end.
|
2013-11-27 08:11:11 +01:00
|
|
|
int index = validateIndex(args[2], list->count + 1);
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Instead of returning null here, should signal an error explicitly
|
|
|
|
|
// somehow.
|
2013-11-27 08:11:11 +01:00
|
|
|
if (index == -1) return NULL_VAL;
|
2013-11-25 04:08:46 +01:00
|
|
|
|
2013-11-27 08:11:11 +01:00
|
|
|
ensureListCapacity(vm, list, list->count + 1);
|
2013-11-25 04:08:46 +01:00
|
|
|
|
2013-11-27 08:11:11 +01:00
|
|
|
// Shift items down.
|
|
|
|
|
for (int i = list->count; i > index; i--)
|
|
|
|
|
{
|
|
|
|
|
list->elements[i] = list->elements[i - 1];
|
|
|
|
|
}
|
2013-11-25 04:08:46 +01:00
|
|
|
|
2013-11-27 08:11:11 +01:00
|
|
|
list->elements[index] = args[1];
|
|
|
|
|
list->count++;
|
|
|
|
|
return args[1];
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-25 06:04:11 +01:00
|
|
|
DEF_NATIVE(list_iterate)
|
|
|
|
|
{
|
|
|
|
|
// If we're starting the iteration, return the first index.
|
|
|
|
|
if (IS_NULL(args[1])) return NUM_VAL(0);
|
|
|
|
|
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
double index = AS_NUM(args[1]);
|
|
|
|
|
// TODO: Handle arg not a number or not an integer.
|
|
|
|
|
|
|
|
|
|
// Stop if we're out of elements.
|
|
|
|
|
if (index >= list->count - 1) return FALSE_VAL;
|
|
|
|
|
|
|
|
|
|
// Otherwise, move to the next index.
|
|
|
|
|
return NUM_VAL(index + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEF_NATIVE(list_iteratorValue)
|
|
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
double index = AS_NUM(args[1]);
|
|
|
|
|
// TODO: Handle index out of bounds or not integer.
|
|
|
|
|
return list->elements[(int)index];
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(list_removeAt)
|
feat: implement list_removeAt primitive with capacity shrink and test suite
Add DEF_PRIMITIVE(list_removeAt) to src/primitives.c that removes an element at a given index from an ObjList, shifts remaining elements up, shrinks capacity when excess is detected via LIST_GROW_FACTOR, and returns the removed Value. Register the primitive as "removeAt " on vm->listClass. Create test/list/remove_at.wren covering removal at positive indices 0,1,2, negative indices -1,-2,-3, out-of-bounds cases returning null, and verification that the removed value is returned.
2013-11-27 19:20:32 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
int index = validateIndex(args[1], list->count);
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Instead of returning null here, should signal an error explicitly
|
|
|
|
|
// somehow.
|
feat: implement list_removeAt primitive with capacity shrink and test suite
Add DEF_PRIMITIVE(list_removeAt) to src/primitives.c that removes an element at a given index from an ObjList, shifts remaining elements up, shrinks capacity when excess is detected via LIST_GROW_FACTOR, and returns the removed Value. Register the primitive as "removeAt " on vm->listClass. Create test/list/remove_at.wren covering removal at positive indices 0,1,2, negative indices -1,-2,-3, out-of-bounds cases returning null, and verification that the removed value is returned.
2013-11-27 19:20:32 +01:00
|
|
|
if (index == -1) return NULL_VAL;
|
|
|
|
|
|
|
|
|
|
Value removed = list->elements[index];
|
|
|
|
|
|
|
|
|
|
// Shift items up.
|
|
|
|
|
for (int i = index; i < list->count - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
list->elements[i] = list->elements[i + 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have too much excess capacity, shrink it.
|
|
|
|
|
if (list->capacity / LIST_GROW_FACTOR >= list->count)
|
|
|
|
|
{
|
|
|
|
|
wrenReallocate(vm, list->elements, sizeof(Value) * list->capacity,
|
|
|
|
|
sizeof(Value) * (list->capacity / LIST_GROW_FACTOR));
|
|
|
|
|
list->capacity /= LIST_GROW_FACTOR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list->count--;
|
|
|
|
|
return removed;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(list_subscript)
|
2013-11-27 08:11:11 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
|
|
|
|
|
int index = validateIndex(args[1], list->count);
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Instead of returning null here, should signal an error explicitly
|
|
|
|
|
// somehow.
|
2013-11-27 08:11:11 +01:00
|
|
|
if (index == -1) return NULL_VAL;
|
2013-11-25 04:08:46 +01:00
|
|
|
|
|
|
|
|
return list->elements[index];
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-21 18:37:59 +01:00
|
|
|
DEF_NATIVE(list_subscriptSetter)
|
|
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
|
|
|
|
|
int index = validateIndex(args[1], list->count);
|
|
|
|
|
// TODO: Instead of returning null here, should signal an error explicitly
|
|
|
|
|
// somehow.
|
|
|
|
|
if (index == -1) return NULL_VAL;
|
|
|
|
|
|
|
|
|
|
list->elements[index] = args[2];
|
|
|
|
|
return args[2];
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-08 03:47:40 +01:00
|
|
|
DEF_NATIVE(null_toString)
|
|
|
|
|
{
|
|
|
|
|
return wrenNewString(vm, "null", 4);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_abs)
|
2013-10-27 19:28:15 +01:00
|
|
|
{
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(fabs(AS_NUM(args[0])));
|
2013-10-27 19:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_toString)
|
2013-11-02 07:27:28 +01:00
|
|
|
{
|
2013-12-24 00:38:00 +01:00
|
|
|
// According to Lua implementation, this should be enough for longest number
|
|
|
|
|
// formatted using %.14g.
|
|
|
|
|
char buffer[21];
|
|
|
|
|
sprintf(buffer, "%.14g", AS_NUM(args[0]));
|
|
|
|
|
return (Value)wrenNewString(vm, buffer, strlen(buffer));
|
2013-11-02 07:27:28 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_negate)
|
2013-11-13 16:10:52 +01:00
|
|
|
{
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(-AS_NUM(args[0]));
|
2013-11-13 16:10:52 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_minus)
|
2013-10-31 15:04:44 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
// TODO: Handle unsupported operand types better.
|
|
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(AS_NUM(args[0]) - AS_NUM(args[1]));
|
2013-10-31 15:04:44 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_plus)
|
2013-10-31 15:04:44 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Handle coercion to string if RHS is a string.
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(AS_NUM(args[0]) + AS_NUM(args[1]));
|
2013-10-31 15:04:44 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_multiply)
|
2013-10-31 15:04:44 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(AS_NUM(args[0]) * AS_NUM(args[1]));
|
2013-10-31 15:04:44 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_divide)
|
2013-10-31 15:04:44 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(AS_NUM(args[0]) / AS_NUM(args[1]));
|
2013-10-31 15:04:44 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_mod)
|
2013-11-10 06:01:18 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(fmod(AS_NUM(args[0]), AS_NUM(args[1])));
|
2013-11-10 06:01:18 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_lt)
|
2013-11-04 06:38:58 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:35:59 +01:00
|
|
|
return BOOL_VAL(AS_NUM(args[0]) < AS_NUM(args[1]));
|
2013-11-04 06:38:58 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_gt)
|
2013-11-04 06:38:58 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:35:59 +01:00
|
|
|
return BOOL_VAL(AS_NUM(args[0]) > AS_NUM(args[1]));
|
2013-11-04 06:38:58 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_lte)
|
2013-11-04 06:38:58 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:35:59 +01:00
|
|
|
return BOOL_VAL(AS_NUM(args[0]) <= AS_NUM(args[1]));
|
2013-11-04 06:38:58 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_gte)
|
2013-11-04 06:38:58 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
2013-11-16 20:35:59 +01:00
|
|
|
return BOOL_VAL(AS_NUM(args[0]) >= AS_NUM(args[1]));
|
2013-11-04 06:38:58 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_eqeq)
|
2013-11-05 18:57:57 +01:00
|
|
|
{
|
2013-11-16 20:35:59 +01:00
|
|
|
if (!IS_NUM(args[1])) return FALSE_VAL;
|
|
|
|
|
return BOOL_VAL(AS_NUM(args[0]) == AS_NUM(args[1]));
|
2013-11-05 18:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(num_bangeq)
|
2013-11-05 18:57:57 +01:00
|
|
|
{
|
2013-11-16 20:35:59 +01:00
|
|
|
if (!IS_NUM(args[1])) return TRUE_VAL;
|
|
|
|
|
return BOOL_VAL(AS_NUM(args[0]) != AS_NUM(args[1]));
|
2013-11-05 18:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2013-12-05 07:09:31 +01:00
|
|
|
DEF_NATIVE(num_bitwiseNot)
|
|
|
|
|
{
|
|
|
|
|
// Bitwise operators always work on 32-bit unsigned ints.
|
|
|
|
|
uint32_t value = (uint32_t)AS_NUM(args[0]);
|
|
|
|
|
return NUM_VAL(~value);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(object_eqeq)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
2013-11-27 03:02:10 +01:00
|
|
|
return BOOL_VAL(wrenValuesEqual(args[0], args[1]));
|
2013-11-26 16:52:37 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(object_bangeq)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
2013-11-27 03:02:10 +01:00
|
|
|
return BOOL_VAL(!wrenValuesEqual(args[0], args[1]));
|
2013-11-26 16:52:37 +01:00
|
|
|
}
|
|
|
|
|
|
2013-12-19 16:02:27 +01:00
|
|
|
DEF_NATIVE(object_new)
|
|
|
|
|
{
|
|
|
|
|
// This is the default argument-less constructor that all objects inherit.
|
|
|
|
|
// It just returns "this".
|
|
|
|
|
return args[0];
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-22 20:50:00 +01:00
|
|
|
DEF_NATIVE(object_toString)
|
|
|
|
|
{
|
|
|
|
|
return wrenNewString(vm, "<object>", 8);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(object_type)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
|
|
|
|
return OBJ_VAL(wrenGetClass(vm, args[0]));
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(string_contains)
|
2013-10-27 19:28:15 +01:00
|
|
|
{
|
2013-11-17 02:41:09 +01:00
|
|
|
const char* string = AS_CSTRING(args[0]);
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Check type of arg first!
|
2013-11-17 02:41:09 +01:00
|
|
|
const char* search = AS_CSTRING(args[1]);
|
2013-10-27 19:28:15 +01:00
|
|
|
|
2013-10-28 14:53:51 +01:00
|
|
|
// Corner case, the empty string contains the empty string.
|
2013-11-17 19:04:02 +01:00
|
|
|
if (strlen(string) == 0 && strlen(search) == 0) return TRUE_VAL;
|
2013-10-28 14:53:51 +01:00
|
|
|
|
2013-11-17 19:04:02 +01:00
|
|
|
return BOOL_VAL(strstr(string, search) != NULL);
|
2013-10-27 19:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(string_count)
|
2013-10-27 19:28:15 +01:00
|
|
|
{
|
2013-11-17 02:41:09 +01:00
|
|
|
double count = strlen(AS_CSTRING(args[0]));
|
2013-11-16 20:41:29 +01:00
|
|
|
return NUM_VAL(count);
|
2013-10-27 19:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(string_toString)
|
2013-11-02 07:27:28 +01:00
|
|
|
{
|
|
|
|
|
return args[0];
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(string_plus)
|
2013-10-31 15:04:44 +01:00
|
|
|
{
|
2013-12-22 23:31:33 +01:00
|
|
|
if (!IS_STRING(args[1])) return NULL_VAL;
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Handle coercion to string of RHS.
|
2013-10-31 15:04:44 +01:00
|
|
|
|
2013-11-17 02:41:09 +01:00
|
|
|
const char* left = AS_CSTRING(args[0]);
|
|
|
|
|
const char* right = AS_CSTRING(args[1]);
|
2013-10-31 15:04:44 +01:00
|
|
|
|
2013-11-02 07:27:28 +01:00
|
|
|
size_t leftLength = strlen(left);
|
|
|
|
|
size_t rightLength = strlen(right);
|
2013-10-31 15:04:44 +01:00
|
|
|
|
refactor: rename internal value creation functions to wren-prefixed public API names
Move `allocate`, `initObj`, `newClass`, and related static helpers from `vm.c` into `value.c` with consistent `wren` prefix, and update all call sites in `compiler.c`, `primitives.c`, and `vm.c` to use the new names (`wrenNewFunction`, `wrenNewString`, `wrenNewClass`, `wrenNewInstance`, `wrenNewList`). Remove the old declarations from `vm.h` and add comprehensive documentation comments to `value.h` explaining the NaN-tagging representation and type system.
2013-11-28 05:00:03 +01:00
|
|
|
Value value = wrenNewString(vm, NULL, leftLength + rightLength);
|
2013-11-17 02:41:09 +01:00
|
|
|
ObjString* string = AS_STRING(value);
|
2013-11-12 17:32:35 +01:00
|
|
|
strcpy(string->value, left);
|
|
|
|
|
strcpy(string->value + leftLength, right);
|
|
|
|
|
string->value[leftLength + rightLength] = '\0';
|
|
|
|
|
|
2013-11-16 20:26:32 +01:00
|
|
|
return value;
|
2013-10-31 15:04:44 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(string_eqeq)
|
2013-11-05 18:57:57 +01:00
|
|
|
{
|
2013-11-16 20:35:59 +01:00
|
|
|
if (!IS_STRING(args[1])) return FALSE_VAL;
|
2013-11-17 02:41:09 +01:00
|
|
|
const char* a = AS_CSTRING(args[0]);
|
|
|
|
|
const char* b = AS_CSTRING(args[1]);
|
2013-11-16 20:35:59 +01:00
|
|
|
return BOOL_VAL(strcmp(a, b) == 0);
|
2013-11-05 18:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(string_bangeq)
|
2013-11-05 18:57:57 +01:00
|
|
|
{
|
2013-11-16 20:35:59 +01:00
|
|
|
if (!IS_STRING(args[1])) return TRUE_VAL;
|
2013-11-17 02:41:09 +01:00
|
|
|
const char* a = AS_CSTRING(args[0]);
|
|
|
|
|
const char* b = AS_CSTRING(args[1]);
|
2013-11-16 20:35:59 +01:00
|
|
|
return BOOL_VAL(strcmp(a, b) != 0);
|
2013-11-05 18:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(string_subscript)
|
2013-11-24 19:45:07 +01:00
|
|
|
{
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Instead of returning null here, all of these failure cases should
|
|
|
|
|
// signal an error explicitly somehow.
|
2013-11-24 19:45:07 +01:00
|
|
|
if (!IS_NUM(args[1])) return NULL_VAL;
|
|
|
|
|
|
|
|
|
|
double indexNum = AS_NUM(args[1]);
|
|
|
|
|
int index = (int)indexNum;
|
|
|
|
|
// Make sure the index is an integer.
|
|
|
|
|
if (indexNum != index) return NULL_VAL;
|
|
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
|
|
|
|
|
// Negative indices count from the end.
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Strings should cache their length.
|
2013-11-24 19:45:07 +01:00
|
|
|
int length = (int)strlen(string->value);
|
|
|
|
|
if (index < 0) index = length + index;
|
|
|
|
|
|
|
|
|
|
// Check bounds.
|
|
|
|
|
if (index < 0 || index >= length) return NULL_VAL;
|
|
|
|
|
|
|
|
|
|
// The result is a one-character string.
|
2013-12-15 00:28:18 +01:00
|
|
|
// TODO: Handle UTF-8.
|
refactor: rename internal value creation functions to wren-prefixed public API names
Move `allocate`, `initObj`, `newClass`, and related static helpers from `vm.c` into `value.c` with consistent `wren` prefix, and update all call sites in `compiler.c`, `primitives.c`, and `vm.c` to use the new names (`wrenNewFunction`, `wrenNewString`, `wrenNewClass`, `wrenNewInstance`, `wrenNewList`). Remove the old declarations from `vm.h` and add comprehensive documentation comments to `value.h` explaining the NaN-tagging representation and type system.
2013-11-28 05:00:03 +01:00
|
|
|
Value value = wrenNewString(vm, NULL, 2);
|
2013-11-24 19:45:07 +01:00
|
|
|
ObjString* result = AS_STRING(value);
|
|
|
|
|
result->value[0] = AS_CSTRING(args[0])[index];
|
|
|
|
|
result->value[1] = '\0';
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-24 00:38:00 +01:00
|
|
|
DEF_NATIVE(io_writeString)
|
2013-10-28 06:45:40 +01:00
|
|
|
{
|
2013-11-27 03:02:10 +01:00
|
|
|
wrenPrintValue(args[1]);
|
2013-10-28 06:45:40 +01:00
|
|
|
printf("\n");
|
|
|
|
|
return args[1];
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
DEF_NATIVE(os_clock)
|
2013-11-22 17:55:22 +01:00
|
|
|
{
|
|
|
|
|
double time = (double)clock() / CLOCKS_PER_SEC;
|
|
|
|
|
return NUM_VAL(time);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
static ObjClass* defineClass(WrenVM* vm, const char* name)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
2013-12-22 05:44:37 +01:00
|
|
|
ObjClass* classObj = wrenNewClass(vm, vm->objectClass, 0);
|
2013-11-26 16:52:37 +01:00
|
|
|
int symbol = addSymbol(&vm->globalSymbols, name, strlen(name));
|
|
|
|
|
vm->globals[symbol] = OBJ_VAL(classObj);
|
|
|
|
|
return classObj;
|
|
|
|
|
}
|
feat: add `is` operator for type checking and refactor primitives registration
Add TOKEN_IS token and CODE_IS bytecode to support runtime type checking via the `is` keyword. Refactor primitive registration by replacing `registerPrimitives` with `loadCore`, which compiles a core library string to define built-in classes (Bool, Class, Function, Num, Null, String, IO) and then attaches primitive methods to them. Update Primitive typedef to remove unused numArgs parameter, and add findGlobal helper to retrieve globals by name. Include test files for class syntax, class instantiation, and the new `is` operator.
2013-11-08 02:07:32 +01:00
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
void wrenInitializeCore(WrenVM* vm)
|
2013-10-27 19:28:15 +01:00
|
|
|
{
|
2013-12-22 05:44:37 +01:00
|
|
|
// Define the root Object class. This has to be done a little specially
|
|
|
|
|
// because it has no superclass and an unusual metaclass (Class).
|
|
|
|
|
vm->objectClass = wrenNewSingleClass(vm, 0);
|
|
|
|
|
int objectSymbol = addSymbol(&vm->globalSymbols, "Object", strlen("Object"));
|
|
|
|
|
vm->globals[objectSymbol] = OBJ_VAL(vm->objectClass);
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
NATIVE(vm->objectClass, "== ", object_eqeq);
|
|
|
|
|
NATIVE(vm->objectClass, "!= ", object_bangeq);
|
2013-12-19 16:02:27 +01:00
|
|
|
NATIVE(vm->objectClass, "new", object_new);
|
2013-12-22 20:50:00 +01:00
|
|
|
NATIVE(vm->objectClass, "toString", object_toString);
|
2013-11-28 17:00:55 +01:00
|
|
|
NATIVE(vm->objectClass, "type", object_type);
|
2013-11-26 16:52:37 +01:00
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
// Now we can define Class, which is a subclass of Object, but Object's
|
|
|
|
|
// metaclass.
|
|
|
|
|
vm->classClass = wrenNewSingleClass(vm, 0);
|
|
|
|
|
int classSymbol = addSymbol(&vm->globalSymbols, "Class", strlen("Class"));
|
|
|
|
|
vm->globals[classSymbol] = OBJ_VAL(vm->classClass);
|
|
|
|
|
|
|
|
|
|
// Now that Object and Class are defined, we can wire them up to each other.
|
|
|
|
|
wrenBindSuperclass(vm->classClass, vm->objectClass);
|
|
|
|
|
vm->objectClass->metaclass = vm->classClass;
|
|
|
|
|
vm->classClass->metaclass = vm->classClass;
|
|
|
|
|
|
|
|
|
|
// The core class diagram ends up looking like this, where single lines point
|
|
|
|
|
// to a class's superclass, and double lines point to its metaclass:
|
|
|
|
|
//
|
|
|
|
|
// __________ /====\
|
|
|
|
|
// / \ // \\
|
|
|
|
|
// v \ v \\
|
|
|
|
|
// .---------. .--------------. //
|
|
|
|
|
// | Object |==>| Class |==/
|
|
|
|
|
// '---------' '--------------'
|
|
|
|
|
// ^ ^
|
|
|
|
|
// | |
|
|
|
|
|
// .---------. .--------------. \
|
|
|
|
|
// | Base |==>| Base.type | |
|
|
|
|
|
// '---------' '--------------' |
|
|
|
|
|
// ^ ^ | Hypothetical example classes
|
|
|
|
|
// | | |
|
|
|
|
|
// .---------. .--------------. |
|
|
|
|
|
// | Derived |==>| Derived.type | |
|
|
|
|
|
// '---------' '--------------' /
|
|
|
|
|
|
|
|
|
|
// The rest of the classes can not be defined normally.
|
|
|
|
|
vm->boolClass = defineClass(vm, "Bool");
|
2013-11-28 17:00:55 +01:00
|
|
|
NATIVE(vm->boolClass, "toString", bool_toString);
|
|
|
|
|
NATIVE(vm->boolClass, "!", bool_not);
|
2013-11-04 06:38:58 +01:00
|
|
|
|
2013-12-22 23:31:33 +01:00
|
|
|
vm->fiberClass = defineClass(vm, "Fiber");
|
|
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
vm->fnClass = defineClass(vm, "Function");
|
2013-11-28 17:00:55 +01:00
|
|
|
FIBER_NATIVE(vm->fnClass, "call", fn_call0);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call1);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call2);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call3);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call4);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call5);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call6);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call7);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call8);
|
2013-11-30 00:08:27 +01:00
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call9);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call10);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call11);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call12);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call13);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call14);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call15);
|
|
|
|
|
FIBER_NATIVE(vm->fnClass, "call ", fn_call16);
|
2013-11-06 15:52:28 +01:00
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
vm->nullClass = defineClass(vm, "Null");
|
2013-12-08 03:47:40 +01:00
|
|
|
NATIVE(vm->nullClass, "toString", null_toString);
|
feat: add `is` operator for type checking and refactor primitives registration
Add TOKEN_IS token and CODE_IS bytecode to support runtime type checking via the `is` keyword. Refactor primitive registration by replacing `registerPrimitives` with `loadCore`, which compiles a core library string to define built-in classes (Bool, Class, Function, Num, Null, String, IO) and then attaches primitive methods to them. Update Primitive typedef to remove unused numArgs parameter, and add findGlobal helper to retrieve globals by name. Include test files for class syntax, class instantiation, and the new `is` operator.
2013-11-08 02:07:32 +01:00
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
vm->numClass = defineClass(vm, "Num");
|
2013-11-28 17:00:55 +01:00
|
|
|
NATIVE(vm->numClass, "abs", num_abs);
|
|
|
|
|
NATIVE(vm->numClass, "toString", num_toString)
|
|
|
|
|
NATIVE(vm->numClass, "-", num_negate);
|
|
|
|
|
NATIVE(vm->numClass, "- ", num_minus);
|
|
|
|
|
NATIVE(vm->numClass, "+ ", num_plus);
|
|
|
|
|
NATIVE(vm->numClass, "* ", num_multiply);
|
|
|
|
|
NATIVE(vm->numClass, "/ ", num_divide);
|
|
|
|
|
NATIVE(vm->numClass, "% ", num_mod);
|
|
|
|
|
NATIVE(vm->numClass, "< ", num_lt);
|
|
|
|
|
NATIVE(vm->numClass, "> ", num_gt);
|
|
|
|
|
NATIVE(vm->numClass, "<= ", num_lte);
|
|
|
|
|
NATIVE(vm->numClass, ">= ", num_gte);
|
2013-12-05 07:09:31 +01:00
|
|
|
NATIVE(vm->numClass, "~", num_bitwiseNot);
|
|
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
// These are defined just so that 0 and -0 are equal, which is specified by
|
|
|
|
|
// IEEE 754 even though they have different bit representations.
|
2013-11-28 17:00:55 +01:00
|
|
|
NATIVE(vm->numClass, "== ", num_eqeq);
|
|
|
|
|
NATIVE(vm->numClass, "!= ", num_bangeq);
|
2013-10-31 15:04:44 +01:00
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
vm->stringClass = defineClass(vm, "String");
|
2013-11-28 17:00:55 +01:00
|
|
|
NATIVE(vm->stringClass, "contains ", string_contains);
|
|
|
|
|
NATIVE(vm->stringClass, "count", string_count);
|
|
|
|
|
NATIVE(vm->stringClass, "toString", string_toString)
|
|
|
|
|
NATIVE(vm->stringClass, "+ ", string_plus);
|
|
|
|
|
NATIVE(vm->stringClass, "== ", string_eqeq);
|
|
|
|
|
NATIVE(vm->stringClass, "!= ", string_bangeq);
|
|
|
|
|
NATIVE(vm->stringClass, "[ ]", string_subscript);
|
2013-10-28 06:45:40 +01:00
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
ObjClass* osClass = defineClass(vm, "OS");
|
2013-11-28 17:00:55 +01:00
|
|
|
NATIVE(osClass->metaclass, "clock", os_clock);
|
2013-10-31 15:04:44 +01:00
|
|
|
|
2013-12-22 20:50:00 +01:00
|
|
|
wrenInterpret(vm, coreLibSource);
|
|
|
|
|
|
|
|
|
|
vm->listClass = AS_CLASS(findGlobal(vm, "List"));
|
|
|
|
|
NATIVE(vm->listClass, "add ", list_add);
|
|
|
|
|
NATIVE(vm->listClass, "clear", list_clear);
|
|
|
|
|
NATIVE(vm->listClass, "count", list_count);
|
|
|
|
|
NATIVE(vm->listClass, "insert ", list_insert);
|
2013-12-25 06:04:11 +01:00
|
|
|
NATIVE(vm->listClass, "iterate ", list_iterate);
|
|
|
|
|
NATIVE(vm->listClass, "iteratorValue ", list_iteratorValue);
|
2013-12-22 20:50:00 +01:00
|
|
|
NATIVE(vm->listClass, "removeAt ", list_removeAt);
|
|
|
|
|
NATIVE(vm->listClass, "[ ]", list_subscript);
|
|
|
|
|
NATIVE(vm->listClass, "[ ]=", list_subscriptSetter);
|
|
|
|
|
|
|
|
|
|
ObjClass* ioClass = AS_CLASS(findGlobal(vm, "IO"));
|
2013-12-24 00:38:00 +01:00
|
|
|
NATIVE(ioClass->metaclass, "write__native__ ", io_writeString);
|
2013-11-06 00:40:21 +01:00
|
|
|
}
|