2015-02-25 16:07:54 +01:00
|
|
|
#include <ctype.h>
|
2015-03-03 09:06:34 +01:00
|
|
|
#include <errno.h>
|
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>
|
|
|
|
|
|
2015-02-25 06:09:04 +01:00
|
|
|
#include "wren_common.h"
|
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
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
// Binds a primitive method named [name] (in Wren) implemented using C function
|
2013-11-28 17:00:55 +01:00
|
|
|
// [fn] to `ObjClass` [cls].
|
2015-03-02 16:24:04 +01:00
|
|
|
#define PRIMITIVE(cls, name, function) \
|
2013-10-27 19:28:15 +01:00
|
|
|
{ \
|
refactor: extract SymbolTable into dedicated wren_utils module with prefixed API
Move SymbolTable struct and its associated functions (initSymbolTable, clearSymbolTable, addSymbol, findSymbol, ensureSymbol, getSymbolName) from wren_vm.c and wren_value.h into new wren_utils.c and wren_utils.h files. Rename all functions with wrenSymbolTable prefix for consistent naming convention, update all call sites across compiler, core, debug, and VM files, and relocate MAX_SYMBOLS constant to wren_common.h.
2014-01-02 05:57:58 +01:00
|
|
|
int symbol = wrenSymbolTableEnsure(vm, \
|
2014-04-07 03:59:53 +02:00
|
|
|
&vm->methodNames, name, strlen(name)); \
|
2014-01-04 20:08:31 +01:00
|
|
|
Method method; \
|
|
|
|
|
method.type = METHOD_PRIMITIVE; \
|
2015-03-02 16:24:04 +01:00
|
|
|
method.fn.primitive = prim_##function; \
|
2014-01-04 20:08:31 +01:00
|
|
|
wrenBindMethod(vm, cls, symbol, method); \
|
2013-10-27 19:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
// Defines a primitive method whose C function name is [name]. This abstracts
|
|
|
|
|
// the actual type signature of a primitive function and makes it clear which C
|
|
|
|
|
// functions are invoked as primitives.
|
|
|
|
|
#define DEF_PRIMITIVE(name) \
|
|
|
|
|
static PrimitiveResult prim_##name(WrenVM* vm, ObjFiber* fiber, Value* args)
|
2014-01-01 22:25:24 +01:00
|
|
|
|
|
|
|
|
#define RETURN_VAL(value) do { args[0] = value; return PRIM_VALUE; } while (0)
|
2013-11-17 18:02:57 +01:00
|
|
|
|
2014-01-29 00:31:11 +01:00
|
|
|
#define RETURN_OBJ(obj) RETURN_VAL(OBJ_VAL(obj))
|
2014-01-01 22:25:24 +01:00
|
|
|
#define RETURN_BOOL(value) RETURN_VAL(BOOL_VAL(value))
|
|
|
|
|
#define RETURN_FALSE RETURN_VAL(FALSE_VAL)
|
|
|
|
|
#define RETURN_NULL RETURN_VAL(NULL_VAL)
|
|
|
|
|
#define RETURN_NUM(value) RETURN_VAL(NUM_VAL(value))
|
|
|
|
|
#define RETURN_TRUE RETURN_VAL(TRUE_VAL)
|
|
|
|
|
|
|
|
|
|
#define RETURN_ERROR(msg) \
|
|
|
|
|
do { \
|
2015-03-16 06:32:20 +01:00
|
|
|
args[0] = wrenStringFormat(vm, "$", msg); \
|
2014-01-01 22:25:24 +01:00
|
|
|
return PRIM_ERROR; \
|
|
|
|
|
} while (0);
|
2013-10-28 06:45:40 +01:00
|
|
|
|
2014-02-04 17:44:59 +01:00
|
|
|
// This string literal is generated automatically from core. Do not edit.
|
|
|
|
|
static const char* libSource =
|
2014-02-16 18:20:31 +01:00
|
|
|
"class Sequence {\n"
|
2015-03-15 15:43:10 +01:00
|
|
|
" contains(element) {\n"
|
|
|
|
|
" for (item in this) {\n"
|
|
|
|
|
" if (element == item) {\n"
|
|
|
|
|
" return true\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return false\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-03-06 16:01:02 +01:00
|
|
|
" count {\n"
|
|
|
|
|
" var result = 0\n"
|
|
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" result = result + 1\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2014-02-18 18:54:55 +01:00
|
|
|
" map(f) {\n"
|
2015-01-26 07:49:30 +01:00
|
|
|
" var result = new List\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" result.add(f.call(element))\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2014-02-18 18:54:55 +01:00
|
|
|
" where(f) {\n"
|
2015-01-26 07:49:30 +01:00
|
|
|
" var result = new List\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" if (f.call(element)) result.add(element)\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
2015-01-14 08:47:01 +01:00
|
|
|
"\n"
|
2015-01-15 08:19:31 +01:00
|
|
|
" all(f) {\n"
|
2015-01-14 08:47:01 +01:00
|
|
|
" for (element in this) {\n"
|
2015-01-15 07:42:15 +01:00
|
|
|
" if (!f.call(element)) return false\n"
|
2015-01-14 08:47:01 +01:00
|
|
|
" }\n"
|
|
|
|
|
" return true\n"
|
|
|
|
|
" }\n"
|
2015-01-15 16:29:49 +01:00
|
|
|
"\n"
|
2015-02-28 21:45:39 +01:00
|
|
|
" any(f) {\n"
|
|
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" if (f.call(element)) return true\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return false\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-01-15 16:29:49 +01:00
|
|
|
" reduce(acc, f) {\n"
|
|
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" acc = f.call(acc, element)\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return acc\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-01-16 09:24:18 +01:00
|
|
|
" reduce(f) {\n"
|
|
|
|
|
" var iter = iterate(null)\n"
|
|
|
|
|
" if (!iter) Fiber.abort(\"Can't reduce an empty sequence.\")\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" // Seed with the first element.\n"
|
|
|
|
|
" var result = iteratorValue(iter)\n"
|
|
|
|
|
" while (iter = iterate(iter)) {\n"
|
|
|
|
|
" result = f.call(result, iteratorValue(iter))\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
2015-01-15 16:29:49 +01:00
|
|
|
"\n"
|
2015-01-24 05:45:23 +01:00
|
|
|
" join { join(\"\") }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" join(sep) {\n"
|
|
|
|
|
" var first = true\n"
|
|
|
|
|
" var result = \"\"\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" if (!first) result = result + sep\n"
|
|
|
|
|
" first = false\n"
|
|
|
|
|
" result = result + element.toString\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
2015-02-16 19:21:29 +01:00
|
|
|
"class String is Sequence {}\n"
|
2015-01-23 05:58:22 +01:00
|
|
|
"\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
"class List is Sequence {\n"
|
2014-04-06 17:37:37 +02:00
|
|
|
" addAll(other) {\n"
|
|
|
|
|
" for (element in other) {\n"
|
|
|
|
|
" add(element)\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return other\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-01-24 05:45:23 +01:00
|
|
|
" toString { \"[\" + join(\", \") + \"]\" }\n"
|
2014-02-14 18:09:02 +01:00
|
|
|
"\n"
|
2014-04-09 02:54:37 +02:00
|
|
|
" +(other) {\n"
|
2014-02-15 05:10:41 +01:00
|
|
|
" var result = this[0..-1]\n"
|
2014-04-09 02:54:37 +02:00
|
|
|
" for (element in other) {\n"
|
2014-02-15 02:24:06 +01:00
|
|
|
" result.add(element)\n"
|
2014-02-14 18:09:02 +01:00
|
|
|
" }\n"
|
2014-02-15 02:24:06 +01:00
|
|
|
" return result\n"
|
2014-02-14 18:09:02 +01:00
|
|
|
" }\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
"class Map {\n"
|
2015-01-25 19:27:38 +01:00
|
|
|
" keys { new MapKeySequence(this) }\n"
|
|
|
|
|
" values { new MapValueSequence(this) }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" toString {\n"
|
|
|
|
|
" var first = true\n"
|
|
|
|
|
" var result = \"{\"\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" for (key in keys) {\n"
|
|
|
|
|
" if (!first) result = result + \", \"\n"
|
|
|
|
|
" first = false\n"
|
|
|
|
|
" result = result + key.toString + \": \" + this[key].toString\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" return result + \"}\"\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"class MapKeySequence is Sequence {\n"
|
|
|
|
|
" new(map) {\n"
|
|
|
|
|
" _map = map\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" iterate(n) { _map.iterate_(n) }\n"
|
|
|
|
|
" iteratorValue(iterator) { _map.keyIteratorValue_(iterator) }\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"class MapValueSequence is Sequence {\n"
|
|
|
|
|
" new(map) {\n"
|
|
|
|
|
" _map = map\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" iterate(n) { _map.iterate_(n) }\n"
|
|
|
|
|
" iteratorValue(iterator) { _map.valueIteratorValue_(iterator) }\n"
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
"class Range is Sequence {}\n";
|
2013-12-22 20:50:00 +01:00
|
|
|
|
2014-04-05 03:24:55 +02:00
|
|
|
// Validates that the given argument in [args] is a function. Returns true if
|
|
|
|
|
// it is. If not, reports an error and returns false.
|
|
|
|
|
static bool validateFn(WrenVM* vm, Value* args, int index, const char* argName)
|
|
|
|
|
{
|
|
|
|
|
if (IS_FN(args[index]) || IS_CLOSURE(args[index])) return true;
|
|
|
|
|
|
2015-03-16 06:32:20 +01:00
|
|
|
args[0] = wrenStringFormat(vm, "$ must be a function.", argName);
|
2014-04-05 03:24:55 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-02 16:32:00 +01:00
|
|
|
// Validates that the given argument in [args] is a Num. Returns true if it is.
|
|
|
|
|
// If not, reports an error and returns false.
|
|
|
|
|
static bool validateNum(WrenVM* vm, Value* args, int index, const char* argName)
|
|
|
|
|
{
|
|
|
|
|
if (IS_NUM(args[index])) return true;
|
|
|
|
|
|
2015-03-16 06:32:20 +01:00
|
|
|
args[0] = wrenStringFormat(vm, "$ must be a number.", argName);
|
2014-01-30 18:12:44 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validates that [value] is an integer. Returns true if it is. If not, reports
|
|
|
|
|
// an error and returns false.
|
|
|
|
|
static bool validateIntValue(WrenVM* vm, Value* args, double value,
|
|
|
|
|
const char* argName)
|
|
|
|
|
{
|
|
|
|
|
if (trunc(value) == value) return true;
|
|
|
|
|
|
2015-03-16 07:17:08 +01:00
|
|
|
args[0] = wrenStringFormat(vm, "$ must be an integer.", argName);
|
2014-01-02 16:32:00 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validates that the given argument in [args] is an integer. Returns true if
|
|
|
|
|
// it is. If not, reports an error and returns false.
|
|
|
|
|
static bool validateInt(WrenVM* vm, Value* args, int index, const char* argName)
|
|
|
|
|
{
|
|
|
|
|
// Make sure it's a number first.
|
|
|
|
|
if (!validateNum(vm, args, index, argName)) return false;
|
|
|
|
|
|
2014-01-30 18:12:44 +01:00
|
|
|
return validateIntValue(vm, args, AS_NUM(args[index]), argName);
|
2014-01-02 16:32:00 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-30 18:12:44 +01:00
|
|
|
// Validates that [value] is an integer within `[0, count)`. Also allows
|
2014-01-02 16:32:00 +01:00
|
|
|
// negative indices which map backwards from the end. Returns the valid positive
|
2015-03-21 20:22:04 +01:00
|
|
|
// index value. If invalid, reports an error and returns `UINT32_MAX`.
|
|
|
|
|
static uint32_t validateIndexValue(WrenVM* vm, Value* args, uint32_t count,
|
|
|
|
|
double value, const char* argName)
|
2014-01-02 16:32:00 +01:00
|
|
|
{
|
2015-03-21 20:22:04 +01:00
|
|
|
if (!validateIntValue(vm, args, value, argName)) return UINT32_MAX;
|
2014-01-02 16:32:00 +01:00
|
|
|
|
|
|
|
|
// Negative indices count from the end.
|
2015-03-21 20:22:04 +01:00
|
|
|
if (value < 0) value = count + value;
|
2014-01-02 16:32:00 +01:00
|
|
|
|
|
|
|
|
// Check bounds.
|
2015-03-21 20:22:04 +01:00
|
|
|
if (value >= 0 && value < count) return (uint32_t)value;
|
2014-01-02 16:32:00 +01:00
|
|
|
|
2015-03-16 07:17:08 +01:00
|
|
|
args[0] = wrenStringFormat(vm, "$ out of bounds.", argName);
|
2015-03-21 20:22:04 +01:00
|
|
|
return UINT32_MAX;
|
2014-01-02 16:32:00 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-25 21:39:19 +01:00
|
|
|
// Validates that [key] is a valid object for use as a map key. Returns true if
|
|
|
|
|
// it is. If not, reports an error and returns false.
|
|
|
|
|
static bool validateKey(WrenVM* vm, Value* args, int index)
|
|
|
|
|
{
|
|
|
|
|
Value arg = args[index];
|
|
|
|
|
if (IS_BOOL(arg) || IS_CLASS(arg) || IS_NULL(arg) ||
|
|
|
|
|
IS_NUM(arg) || IS_RANGE(arg) || IS_STRING(arg))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-16 06:32:20 +01:00
|
|
|
args[0] = CONST_STRING(vm, "Key must be a value type.");
|
2015-01-25 21:39:19 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-30 18:12:44 +01:00
|
|
|
// Validates that the argument at [argIndex] is an integer within `[0, count)`.
|
|
|
|
|
// Also allows negative indices which map backwards from the end. Returns the
|
2015-03-21 20:22:04 +01:00
|
|
|
// valid positive index value. If invalid, reports an error and returns
|
|
|
|
|
// `UINT32_MAX`.
|
|
|
|
|
static uint32_t validateIndex(WrenVM* vm, Value* args, uint32_t count,
|
|
|
|
|
int arg, const char* argName)
|
2014-01-30 18:12:44 +01:00
|
|
|
{
|
2015-03-21 20:22:04 +01:00
|
|
|
if (!validateNum(vm, args, arg, argName)) return UINT32_MAX;
|
2014-01-30 18:12:44 +01:00
|
|
|
|
2015-03-21 20:22:04 +01:00
|
|
|
return validateIndexValue(vm, args, count, AS_NUM(args[arg]), argName);
|
2014-01-30 18:12:44 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-03 19:47:26 +01:00
|
|
|
// Validates that the given argument in [args] is a String. Returns true if it
|
|
|
|
|
// is. If not, reports an error and returns false.
|
|
|
|
|
static bool validateString(WrenVM* vm, Value* args, int index,
|
|
|
|
|
const char* argName)
|
|
|
|
|
{
|
|
|
|
|
if (IS_STRING(args[index])) return true;
|
|
|
|
|
|
2015-03-16 06:32:20 +01:00
|
|
|
args[0] = wrenStringFormat(vm, "$ must be a string.", argName);
|
2014-01-03 19:47:26 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-21 00:33:21 +01:00
|
|
|
// Given a [range] and the [length] of the object being operated on, determines
|
|
|
|
|
// the series of elements that should be chosen from the underlying object.
|
|
|
|
|
// Handles ranges that count backwards from the end as well as negative ranges.
|
|
|
|
|
//
|
2015-03-21 20:22:04 +01:00
|
|
|
// Returns the index from which the range should start or `UINT32_MAX` if the
|
|
|
|
|
// range is invalid. After calling, [length] will be updated with the number of
|
|
|
|
|
// elements in the resulting sequence. [step] will be direction that the range
|
|
|
|
|
// is going: `1` if the range is increasing from the start index or `-1` if the
|
|
|
|
|
// range is decreasing.
|
|
|
|
|
static uint32_t calculateRange(WrenVM* vm, Value* args, ObjRange* range,
|
|
|
|
|
uint32_t* length, int* step)
|
2015-01-21 00:33:21 +01:00
|
|
|
{
|
2015-03-21 20:32:31 +01:00
|
|
|
*step = 0;
|
|
|
|
|
|
2015-01-21 00:33:21 +01:00
|
|
|
// Corner case: an empty range at zero is allowed on an empty sequence.
|
|
|
|
|
// This way, list[0..-1] and list[0...list.count] can be used to copy a list
|
|
|
|
|
// even when empty.
|
|
|
|
|
if (*length == 0 && range->from == 0 &&
|
|
|
|
|
range->to == (range->isInclusive ? -1 : 0)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t from = validateIndexValue(vm, args, *length, range->from,
|
|
|
|
|
"Range start");
|
|
|
|
|
if (from == UINT32_MAX) return UINT32_MAX;
|
2015-01-17 08:20:56 +01:00
|
|
|
|
2015-03-21 20:22:04 +01:00
|
|
|
// Bounds check the end manually to handle exclusive ranges.
|
|
|
|
|
double value = range->to;
|
|
|
|
|
if (!validateIntValue(vm, args, value, "Range end")) return UINT32_MAX;
|
2015-01-17 08:20:56 +01:00
|
|
|
|
2015-03-21 20:22:04 +01:00
|
|
|
// Negative indices count from the end.
|
|
|
|
|
if (value < 0) value = *length + value;
|
2015-01-17 08:20:56 +01:00
|
|
|
|
2015-03-21 20:22:04 +01:00
|
|
|
// Convert the exclusive range to an inclusive one.
|
|
|
|
|
if (!range->isInclusive)
|
2015-01-17 08:20:56 +01:00
|
|
|
{
|
2015-03-21 20:22:04 +01:00
|
|
|
// An exclusive range with the same start and end points is empty.
|
|
|
|
|
if (value == from)
|
2015-01-17 08:20:56 +01:00
|
|
|
{
|
2015-03-21 20:22:04 +01:00
|
|
|
*length = 0;
|
|
|
|
|
return from;
|
2015-01-17 08:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-21 20:22:04 +01:00
|
|
|
// Shift the endpoint to make it inclusive, handling both increasing and
|
|
|
|
|
// decreasing ranges.
|
|
|
|
|
value += value >= from ? -1 : 1;
|
2015-01-17 08:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-21 20:22:04 +01:00
|
|
|
// Check bounds.
|
|
|
|
|
if (value < 0 || value >= *length)
|
|
|
|
|
{
|
|
|
|
|
args[0] = CONST_STRING(vm, "Range end out of bounds.");
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t to = (uint32_t)value;
|
|
|
|
|
*length = abs(from - to) + 1;
|
2015-01-21 00:33:21 +01:00
|
|
|
*step = from < to ? 1 : -1;
|
|
|
|
|
return from;
|
2015-01-17 08:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(bool_not)
|
2014-01-02 16:32:00 +01:00
|
|
|
{
|
|
|
|
|
RETURN_BOOL(!AS_BOOL(args[0]));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(bool_toString)
|
2014-01-02 16:32:00 +01:00
|
|
|
{
|
|
|
|
|
if (AS_BOOL(args[0]))
|
|
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(CONST_STRING(vm, "true"));
|
2014-01-02 16:32:00 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(CONST_STRING(vm, "false"));
|
2014-01-02 16:32:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(class_instantiate)
|
2014-04-03 02:42:30 +02:00
|
|
|
{
|
2015-03-21 20:22:04 +01:00
|
|
|
RETURN_VAL(wrenNewInstance(vm, AS_CLASS(args[0])));
|
2014-04-03 02:42:30 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(class_name)
|
2014-01-29 00:31:11 +01:00
|
|
|
{
|
2015-03-21 20:22:04 +01:00
|
|
|
RETURN_OBJ(AS_CLASS(args[0])->name);
|
2014-01-29 00:31:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-14 17:48:45 +01:00
|
|
|
DEF_PRIMITIVE(class_supertype)
|
|
|
|
|
{
|
|
|
|
|
ObjClass* classObj = AS_CLASS(args[0]);
|
|
|
|
|
|
|
|
|
|
// Object has no superclass.
|
|
|
|
|
if (classObj->superclass == NULL) RETURN_NULL;
|
feat: reverse argument order of List.insert to index-first convention
The previous signature `insert(element, index)` was counter-intuitive and inconsistent with every major language's list API. This commit swaps the parameters to `insert(index, element)`, matching the convention used by Ruby, JavaScript, C++, Lua, C#, Java, and Python. All documentation, C implementation, and test files are updated to reflect the new order.
2015-03-15 22:51:24 +01:00
|
|
|
|
2015-03-14 17:48:45 +01:00
|
|
|
RETURN_OBJ(classObj->superclass);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_instantiate)
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
{
|
2014-04-05 03:24:55 +02:00
|
|
|
// Return the Fiber class itself. When we then call "new" on it, it will
|
|
|
|
|
// create the fiber.
|
|
|
|
|
RETURN_VAL(args[0]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_new)
|
2014-04-05 03:24:55 +02:00
|
|
|
{
|
|
|
|
|
if (!validateFn(vm, args, 1, "Argument")) return PRIM_ERROR;
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
|
|
|
|
|
ObjFiber* newFiber = wrenNewFiber(vm, AS_OBJ(args[1]));
|
|
|
|
|
|
2014-01-13 04:37:11 +01:00
|
|
|
// The compiler expects the first slot of a function to hold the receiver.
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
// Since a fiber's stack is invoked directly, it doesn't have one, so put it
|
|
|
|
|
// in here.
|
|
|
|
|
// TODO: Is there a cleaner solution?
|
|
|
|
|
// TODO: If we make growable stacks, make sure this grows it.
|
|
|
|
|
newFiber->stack[0] = NULL_VAL;
|
2014-12-31 19:34:27 +01:00
|
|
|
newFiber->stackTop++;
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
|
2014-01-29 00:31:11 +01:00
|
|
|
RETURN_OBJ(newFiber);
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_abort)
|
2015-01-01 19:40:14 +01:00
|
|
|
{
|
|
|
|
|
if (!validateString(vm, args, 1, "Error message")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
// Move the error message to the return position.
|
|
|
|
|
args[0] = args[1];
|
|
|
|
|
return PRIM_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_call)
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
{
|
|
|
|
|
ObjFiber* runFiber = AS_FIBER(args[0]);
|
|
|
|
|
|
2014-04-14 16:23:05 +02:00
|
|
|
if (runFiber->numFrames == 0) RETURN_ERROR("Cannot call a finished fiber.");
|
|
|
|
|
if (runFiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
|
2014-11-28 20:21:01 +01:00
|
|
|
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
// Remember who ran it.
|
|
|
|
|
runFiber->caller = fiber;
|
|
|
|
|
|
|
|
|
|
// If the fiber was yielded, make the yield call return null.
|
2014-12-31 19:34:27 +01:00
|
|
|
if (runFiber->stackTop > runFiber->stack)
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
{
|
2014-12-31 19:34:27 +01:00
|
|
|
*(runFiber->stackTop - 1) = NULL_VAL;
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PRIM_RUN_FIBER;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_call1)
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
{
|
|
|
|
|
ObjFiber* runFiber = AS_FIBER(args[0]);
|
|
|
|
|
|
2014-04-14 16:23:05 +02:00
|
|
|
if (runFiber->numFrames == 0) RETURN_ERROR("Cannot call a finished fiber.");
|
|
|
|
|
if (runFiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
|
2014-01-13 15:58:27 +01:00
|
|
|
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
// Remember who ran it.
|
|
|
|
|
runFiber->caller = fiber;
|
|
|
|
|
|
|
|
|
|
// If the fiber was yielded, make the yield call return the value passed to
|
|
|
|
|
// run.
|
2014-12-31 19:34:27 +01:00
|
|
|
if (runFiber->stackTop > runFiber->stack)
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
{
|
2014-12-31 19:34:27 +01:00
|
|
|
*(runFiber->stackTop - 1) = args[1];
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// When the calling fiber resumes, we'll store the result of the run call
|
|
|
|
|
// in its stack. Since fiber.run(value) has two arguments (the fiber and the
|
|
|
|
|
// value) and we only need one slot for the result, discard the other slot
|
|
|
|
|
// now.
|
2014-12-31 19:34:27 +01:00
|
|
|
fiber->stackTop--;
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
|
|
|
|
|
return PRIM_RUN_FIBER;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-07 21:32:11 +01:00
|
|
|
DEF_PRIMITIVE(fiber_current)
|
|
|
|
|
{
|
|
|
|
|
RETURN_OBJ(fiber);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_error)
|
2014-10-15 15:36:42 +02:00
|
|
|
{
|
|
|
|
|
ObjFiber* runFiber = AS_FIBER(args[0]);
|
|
|
|
|
if (runFiber->error == NULL) RETURN_NULL;
|
|
|
|
|
RETURN_OBJ(runFiber->error);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_isDone)
|
2014-04-14 16:23:05 +02:00
|
|
|
{
|
|
|
|
|
ObjFiber* runFiber = AS_FIBER(args[0]);
|
2014-10-15 15:36:42 +02:00
|
|
|
RETURN_BOOL(runFiber->numFrames == 0 || runFiber->error != NULL);
|
2014-04-14 16:23:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_run)
|
2014-04-14 16:23:05 +02:00
|
|
|
{
|
|
|
|
|
ObjFiber* runFiber = AS_FIBER(args[0]);
|
|
|
|
|
|
|
|
|
|
if (runFiber->numFrames == 0) RETURN_ERROR("Cannot run a finished fiber.");
|
|
|
|
|
|
|
|
|
|
// If the fiber was yielded, make the yield call return null.
|
2014-12-31 19:34:27 +01:00
|
|
|
if (runFiber->caller == NULL && runFiber->stackTop > runFiber->stack)
|
2014-04-14 16:23:05 +02:00
|
|
|
{
|
2014-12-31 19:34:27 +01:00
|
|
|
*(runFiber->stackTop - 1) = NULL_VAL;
|
2014-04-14 16:23:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unlike run, this does not remember the calling fiber. Instead, it
|
|
|
|
|
// remember's *that* fiber's caller. You can think of it like tail call
|
|
|
|
|
// elimination. The switched-from fiber is discarded and when the switched
|
|
|
|
|
// to fiber completes or yields, control passes to the switched-from fiber's
|
|
|
|
|
// caller.
|
|
|
|
|
runFiber->caller = fiber->caller;
|
|
|
|
|
|
|
|
|
|
return PRIM_RUN_FIBER;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_run1)
|
2014-04-14 16:23:05 +02:00
|
|
|
{
|
|
|
|
|
ObjFiber* runFiber = AS_FIBER(args[0]);
|
|
|
|
|
|
|
|
|
|
if (runFiber->numFrames == 0) RETURN_ERROR("Cannot run a finished fiber.");
|
|
|
|
|
|
|
|
|
|
// If the fiber was yielded, make the yield call return the value passed to
|
|
|
|
|
// run.
|
2014-12-31 19:34:27 +01:00
|
|
|
if (runFiber->caller == NULL && runFiber->stackTop > runFiber->stack)
|
2014-04-14 16:23:05 +02:00
|
|
|
{
|
2014-12-31 19:34:27 +01:00
|
|
|
*(runFiber->stackTop - 1) = args[1];
|
2014-04-14 16:23:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unlike run, this does not remember the calling fiber. Instead, it
|
|
|
|
|
// remember's *that* fiber's caller. You can think of it like tail call
|
|
|
|
|
// elimination. The switched-from fiber is discarded and when the switched
|
|
|
|
|
// to fiber completes or yields, control passes to the switched-from fiber's
|
|
|
|
|
// caller.
|
|
|
|
|
runFiber->caller = fiber->caller;
|
|
|
|
|
|
|
|
|
|
return PRIM_RUN_FIBER;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_try)
|
2014-10-15 15:36:42 +02:00
|
|
|
{
|
|
|
|
|
ObjFiber* runFiber = AS_FIBER(args[0]);
|
|
|
|
|
|
|
|
|
|
if (runFiber->numFrames == 0) RETURN_ERROR("Cannot try a finished fiber.");
|
|
|
|
|
if (runFiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
|
|
|
|
|
|
|
|
|
|
// Remember who ran it.
|
|
|
|
|
runFiber->caller = fiber;
|
|
|
|
|
runFiber->callerIsTrying = true;
|
|
|
|
|
|
|
|
|
|
// If the fiber was yielded, make the yield call return null.
|
2014-12-31 19:34:27 +01:00
|
|
|
if (runFiber->stackTop > runFiber->stack)
|
2014-10-15 15:36:42 +02:00
|
|
|
{
|
2014-12-31 19:34:27 +01:00
|
|
|
*(runFiber->stackTop - 1) = NULL_VAL;
|
2014-10-15 15:36:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PRIM_RUN_FIBER;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_yield)
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
{
|
2015-03-07 21:32:11 +01:00
|
|
|
// Unhook this fiber from the one that called it.
|
2014-04-14 16:23:05 +02:00
|
|
|
ObjFiber* caller = fiber->caller;
|
|
|
|
|
fiber->caller = NULL;
|
2014-10-15 15:36:42 +02:00
|
|
|
fiber->callerIsTrying = false;
|
2014-04-14 16:23:05 +02:00
|
|
|
|
2015-03-07 21:32:11 +01:00
|
|
|
// If we don't have any other pending fibers, jump all the way out of the
|
|
|
|
|
// interpreter.
|
|
|
|
|
if (caller == NULL)
|
|
|
|
|
{
|
|
|
|
|
args[0] = NULL_VAL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Make the caller's run method return null.
|
|
|
|
|
*(caller->stackTop - 1) = NULL_VAL;
|
|
|
|
|
|
|
|
|
|
// Return the fiber to resume.
|
|
|
|
|
args[0] = OBJ_VAL(caller);
|
|
|
|
|
}
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
|
|
|
|
|
return PRIM_RUN_FIBER;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_yield1)
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
{
|
2015-03-07 21:32:11 +01:00
|
|
|
// Unhook this fiber from the one that called it.
|
2014-04-14 16:23:05 +02:00
|
|
|
ObjFiber* caller = fiber->caller;
|
|
|
|
|
fiber->caller = NULL;
|
2014-10-15 15:36:42 +02:00
|
|
|
fiber->callerIsTrying = false;
|
2014-04-14 16:23:05 +02:00
|
|
|
|
2015-03-07 21:32:11 +01:00
|
|
|
// If we don't have any other pending fibers, jump all the way out of the
|
|
|
|
|
// interpreter.
|
|
|
|
|
if (caller == NULL)
|
|
|
|
|
{
|
|
|
|
|
args[0] = NULL_VAL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Make the caller's run method return the argument passed to yield.
|
|
|
|
|
*(caller->stackTop - 1) = args[1];
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
|
2015-03-07 21:32:11 +01:00
|
|
|
// When the yielding fiber resumes, we'll store the result of the yield call
|
|
|
|
|
// in its stack. Since Fiber.yield(value) has two arguments (the Fiber class
|
|
|
|
|
// and the value) and we only need one slot for the result, discard the other
|
|
|
|
|
// slot now.
|
|
|
|
|
fiber->stackTop--;
|
|
|
|
|
|
|
|
|
|
// Return the fiber to resume.
|
|
|
|
|
args[0] = OBJ_VAL(caller);
|
|
|
|
|
}
|
feat: implement fiber primitives with create, run, yield and caller tracking
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
2014-01-12 20:02:07 +01:00
|
|
|
|
|
|
|
|
return PRIM_RUN_FIBER;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fn_instantiate)
|
2015-01-24 05:33:05 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
// Return the Fn class itself. When we then call "new" on it, it will return
|
|
|
|
|
// the block.
|
2015-01-24 05:33:05 +01:00
|
|
|
RETURN_VAL(args[0]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fn_new)
|
2015-01-24 05:33:05 +01:00
|
|
|
{
|
|
|
|
|
if (!validateFn(vm, args, 1, "Argument")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
// The block argument is already a function, so just return it.
|
|
|
|
|
RETURN_VAL(args[1]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fn_arity)
|
2015-01-24 05:33:05 +01:00
|
|
|
{
|
|
|
|
|
RETURN_NUM(AS_FN(args[0])->arity);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-04 18:34:05 +01:00
|
|
|
static PrimitiveResult callFunction(WrenVM* vm, Value* args, int numArgs)
|
|
|
|
|
{
|
2014-02-10 16:53:09 +01:00
|
|
|
ObjFn* fn;
|
|
|
|
|
if (IS_CLOSURE(args[0]))
|
|
|
|
|
{
|
|
|
|
|
fn = AS_CLOSURE(args[0])->fn;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fn = AS_FN(args[0]);
|
|
|
|
|
}
|
2014-02-15 20:21:24 +01:00
|
|
|
|
2015-01-24 05:33:05 +01:00
|
|
|
if (numArgs < fn->arity) RETURN_ERROR("Function expects more arguments.");
|
2014-02-15 20:21:24 +01:00
|
|
|
|
2014-02-04 18:34:05 +01:00
|
|
|
return PRIM_CALL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fn_call0) { return callFunction(vm, args, 0); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call1) { return callFunction(vm, args, 1); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call2) { return callFunction(vm, args, 2); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call3) { return callFunction(vm, args, 3); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call4) { return callFunction(vm, args, 4); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call5) { return callFunction(vm, args, 5); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call6) { return callFunction(vm, args, 6); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call7) { return callFunction(vm, args, 7); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call8) { return callFunction(vm, args, 8); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call9) { return callFunction(vm, args, 9); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call10) { return callFunction(vm, args, 10); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call11) { return callFunction(vm, args, 11); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call12) { return callFunction(vm, args, 12); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call13) { return callFunction(vm, args, 13); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call14) { return callFunction(vm, args, 14); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call15) { return callFunction(vm, args, 15); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call16) { return callFunction(vm, args, 16); }
|
|
|
|
|
|
|
|
|
|
DEF_PRIMITIVE(fn_toString)
|
2014-02-15 20:36:01 +01:00
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(CONST_STRING(vm, "<fn>"));
|
2014-02-15 20:36:01 +01:00
|
|
|
}
|
2014-01-02 16:32:00 +01:00
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_instantiate)
|
2014-04-08 16:31:23 +02:00
|
|
|
{
|
|
|
|
|
RETURN_OBJ(wrenNewList(vm, 0));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_add)
|
2013-11-27 03:02:10 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
wrenListAdd(vm, AS_LIST(args[0]), args[1]);
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_VAL(args[1]);
|
2013-11-27 03:02:10 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_clear)
|
2013-11-27 08:11:11 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
2015-03-02 16:31:46 +01:00
|
|
|
DEALLOCATE(vm, list->elements);
|
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;
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_NULL;
|
2013-11-27 08:11:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_count)
|
2013-11-24 22:38:31 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_NUM(AS_LIST(args[0])->count);
|
2013-11-24 22:38:31 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(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.
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->count + 1, 1, "Index");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2013-11-25 04:08:46 +01:00
|
|
|
|
feat: reverse argument order of List.insert to index-first convention
The previous signature `insert(element, index)` was counter-intuitive and inconsistent with every major language's list API. This commit swaps the parameters to `insert(index, element)`, matching the convention used by Ruby, JavaScript, C++, Lua, C#, Java, and Python. All documentation, C implementation, and test files are updated to reflect the new order.
2015-03-15 22:51:24 +01:00
|
|
|
wrenListInsert(vm, list, args[2], index);
|
|
|
|
|
RETURN_VAL(args[2]);
|
2013-11-27 08:11:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_iterate)
|
2013-12-25 06:04:11 +01:00
|
|
|
{
|
2014-02-15 02:24:06 +01:00
|
|
|
ObjList* list = AS_LIST(args[0]);
|
|
|
|
|
|
2013-12-25 06:04:11 +01:00
|
|
|
// If we're starting the iteration, return the first index.
|
2014-02-15 02:24:06 +01:00
|
|
|
if (IS_NULL(args[1]))
|
|
|
|
|
{
|
|
|
|
|
if (list->count == 0) RETURN_FALSE;
|
|
|
|
|
RETURN_NUM(0);
|
|
|
|
|
}
|
2013-12-25 06:04:11 +01:00
|
|
|
|
2014-01-02 16:32:00 +01:00
|
|
|
if (!validateInt(vm, args, 1, "Iterator")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
// Stop if we're out of bounds.
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
double index = AS_NUM(args[1]);
|
2015-03-21 20:22:04 +01:00
|
|
|
if (index < 0 || index >= list->count - 1) RETURN_FALSE;
|
2013-12-25 06:04:11 +01:00
|
|
|
|
|
|
|
|
// Otherwise, move to the next index.
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_NUM(index + 1);
|
2013-12-25 06:04:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_iteratorValue)
|
2013-12-25 06:04:11 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->count, 1, "Iterator");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2014-01-02 16:32:00 +01:00
|
|
|
|
|
|
|
|
RETURN_VAL(list->elements[index]);
|
2013-12-25 06:04:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(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]);
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->count, 1, "Index");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
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
|
|
|
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_VAL(wrenListRemoveAt(vm, list, index));
|
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
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_subscript)
|
2013-11-27 08:11:11 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
2013-11-25 04:08:46 +01:00
|
|
|
|
2014-01-30 18:12:44 +01:00
|
|
|
if (IS_NUM(args[1]))
|
|
|
|
|
{
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->count, 1, "Subscript");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2014-01-30 18:12:44 +01:00
|
|
|
|
|
|
|
|
RETURN_VAL(list->elements[index]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!IS_RANGE(args[1]))
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Subscript must be a number or a range.");
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-21 00:33:21 +01:00
|
|
|
int step;
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t count = list->count;
|
|
|
|
|
uint32_t start = calculateRange(vm, args, AS_RANGE(args[1]), &count, &step);
|
|
|
|
|
if (start == UINT32_MAX) return PRIM_ERROR;
|
2014-01-30 18:12:44 +01:00
|
|
|
|
2015-01-21 00:33:21 +01:00
|
|
|
ObjList* result = wrenNewList(vm, count);
|
2015-03-21 20:22:04 +01:00
|
|
|
for (uint32_t i = 0; i < count; i++)
|
2014-01-30 18:12:44 +01:00
|
|
|
{
|
2015-01-21 00:33:21 +01:00
|
|
|
result->elements[i] = list->elements[start + (i * step)];
|
2014-01-30 18:12:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RETURN_OBJ(result);
|
2013-11-25 04:08:46 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(list_subscriptSetter)
|
2013-12-21 18:37:59 +01:00
|
|
|
{
|
|
|
|
|
ObjList* list = AS_LIST(args[0]);
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->count, 1, "Subscript");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2013-12-21 18:37:59 +01:00
|
|
|
|
|
|
|
|
list->elements[index] = args[2];
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_VAL(args[2]);
|
2013-12-21 18:37:59 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_instantiate)
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
{
|
|
|
|
|
RETURN_OBJ(wrenNewMap(vm));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_subscript)
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
{
|
2015-01-25 21:39:19 +01:00
|
|
|
if (!validateKey(vm, args, 1)) return PRIM_ERROR;
|
|
|
|
|
|
2015-01-26 02:42:36 +01:00
|
|
|
ObjMap* map = AS_MAP(args[0]);
|
2015-03-07 21:41:18 +01:00
|
|
|
Value value = wrenMapGet(map, args[1]);
|
|
|
|
|
if (IS_UNDEFINED(value)) RETURN_NULL;
|
2015-01-25 21:39:19 +01:00
|
|
|
|
2015-03-07 21:41:18 +01:00
|
|
|
RETURN_VAL(value);
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_subscriptSetter)
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
{
|
2015-01-25 21:39:19 +01:00
|
|
|
if (!validateKey(vm, args, 1)) return PRIM_ERROR;
|
|
|
|
|
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
wrenMapSet(vm, AS_MAP(args[0]), args[1], args[2]);
|
|
|
|
|
RETURN_VAL(args[2]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_clear)
|
2015-01-25 17:39:44 +01:00
|
|
|
{
|
2015-01-26 02:42:36 +01:00
|
|
|
wrenMapClear(vm, AS_MAP(args[0]));
|
2015-01-25 17:39:44 +01:00
|
|
|
RETURN_NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_containsKey)
|
2015-01-25 21:39:19 +01:00
|
|
|
{
|
|
|
|
|
if (!validateKey(vm, args, 1)) return PRIM_ERROR;
|
|
|
|
|
|
2015-03-07 21:41:18 +01:00
|
|
|
RETURN_BOOL(!IS_UNDEFINED(wrenMapGet(AS_MAP(args[0]), args[1])));
|
2015-01-25 21:39:19 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_count)
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
{
|
|
|
|
|
RETURN_NUM(AS_MAP(args[0])->count);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_iterate)
|
2015-01-25 19:27:38 +01:00
|
|
|
{
|
|
|
|
|
ObjMap* map = AS_MAP(args[0]);
|
|
|
|
|
|
|
|
|
|
if (map->count == 0) RETURN_FALSE;
|
|
|
|
|
|
2015-02-25 06:56:33 +01:00
|
|
|
// If we're starting the iteration, start at the first used entry.
|
|
|
|
|
uint32_t index = 0;
|
|
|
|
|
|
|
|
|
|
// Otherwise, start one past the last entry we stopped at.
|
2015-01-25 19:27:38 +01:00
|
|
|
if (!IS_NULL(args[1]))
|
|
|
|
|
{
|
|
|
|
|
if (!validateInt(vm, args, 1, "Iterator")) return PRIM_ERROR;
|
|
|
|
|
|
2015-02-25 06:56:33 +01:00
|
|
|
if (AS_NUM(args[1]) < 0) RETURN_FALSE;
|
|
|
|
|
index = (uint32_t)AS_NUM(args[1]);
|
|
|
|
|
|
|
|
|
|
if (index >= map->capacity) RETURN_FALSE;
|
|
|
|
|
|
|
|
|
|
// Advance the iterator.
|
|
|
|
|
index++;
|
2015-01-25 19:27:38 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-25 06:56:33 +01:00
|
|
|
// Find a used entry, if any.
|
|
|
|
|
for (; index < map->capacity; index++)
|
2015-01-25 19:27:38 +01:00
|
|
|
{
|
|
|
|
|
if (!IS_UNDEFINED(map->entries[index].key)) RETURN_NUM(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we get here, walked all of the entries.
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_remove)
|
2015-01-26 02:42:36 +01:00
|
|
|
{
|
|
|
|
|
if (!validateKey(vm, args, 1)) return PRIM_ERROR;
|
2015-01-26 04:50:54 +01:00
|
|
|
|
2015-01-26 02:42:36 +01:00
|
|
|
RETURN_VAL(wrenMapRemoveKey(vm, AS_MAP(args[0]), args[1]));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_keyIteratorValue)
|
2015-01-25 19:27:38 +01:00
|
|
|
{
|
|
|
|
|
ObjMap* map = AS_MAP(args[0]);
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, map->capacity, 1, "Iterator");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2015-01-25 19:27:38 +01:00
|
|
|
|
|
|
|
|
MapEntry* entry = &map->entries[index];
|
|
|
|
|
if (IS_UNDEFINED(entry->key))
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Invalid map iterator value.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RETURN_VAL(entry->key);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(map_valueIteratorValue)
|
2015-01-25 19:27:38 +01:00
|
|
|
{
|
|
|
|
|
ObjMap* map = AS_MAP(args[0]);
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, map->capacity, 1, "Iterator");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2015-01-25 19:27:38 +01:00
|
|
|
|
|
|
|
|
MapEntry* entry = &map->entries[index];
|
|
|
|
|
if (IS_UNDEFINED(entry->key))
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Invalid map iterator value.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RETURN_VAL(entry->value);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(null_not)
|
2015-01-16 06:50:01 +01:00
|
|
|
{
|
|
|
|
|
RETURN_VAL(TRUE_VAL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(null_toString)
|
2013-12-08 03:47:40 +01:00
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(CONST_STRING(vm, "null"));
|
2013-12-08 03:47:40 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(num_fromString)
|
2015-02-23 05:06:17 +01:00
|
|
|
{
|
|
|
|
|
if (!validateString(vm, args, 1, "Argument")) return PRIM_ERROR;
|
|
|
|
|
|
2015-02-25 16:07:54 +01:00
|
|
|
ObjString* string = AS_STRING(args[1]);
|
|
|
|
|
|
|
|
|
|
// Corner case: Can't parse an empty string.
|
|
|
|
|
if (string->length == 0) RETURN_NULL;
|
2015-02-23 05:06:17 +01:00
|
|
|
|
2015-03-03 09:06:34 +01:00
|
|
|
errno = 0;
|
2015-02-23 05:06:17 +01:00
|
|
|
char* end;
|
2015-02-25 16:07:54 +01:00
|
|
|
double number = strtod(string->value, &end);
|
|
|
|
|
|
|
|
|
|
// Skip past any trailing whitespace.
|
|
|
|
|
while (*end != '\0' && isspace(*end)) end++;
|
2015-02-23 05:06:17 +01:00
|
|
|
|
2015-03-03 09:06:34 +01:00
|
|
|
if (errno == ERANGE)
|
|
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
args[0] = CONST_STRING(vm, "Number literal is too large.");
|
2015-03-03 09:06:34 +01:00
|
|
|
return PRIM_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-25 16:07:54 +01:00
|
|
|
// We must have consumed the entire string. Otherwise, it contains non-number
|
|
|
|
|
// characters and we can't parse it.
|
|
|
|
|
if (end < string->value + string->length) RETURN_NULL;
|
2015-02-23 05:06:17 +01:00
|
|
|
|
|
|
|
|
RETURN_NUM(number);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-19 21:12:50 +01:00
|
|
|
DEF_PRIMITIVE(num_pi)
|
|
|
|
|
{
|
|
|
|
|
RETURN_NUM(3.14159265358979323846);
|
|
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
// Defines a primitive on Num that calls infix [op] and returns [type].
|
|
|
|
|
#define DEF_NUM_INFIX(name, op, type) \
|
|
|
|
|
DEF_PRIMITIVE(num_##name) \
|
|
|
|
|
{ \
|
|
|
|
|
if (!validateNum(vm, args, 1, "Right operand")) return PRIM_ERROR; \
|
|
|
|
|
RETURN_##type(AS_NUM(args[0]) op AS_NUM(args[1])); \
|
|
|
|
|
}
|
2013-10-31 15:04:44 +01:00
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_NUM_INFIX(minus, -, NUM)
|
|
|
|
|
DEF_NUM_INFIX(plus, +, NUM)
|
|
|
|
|
DEF_NUM_INFIX(multiply, *, NUM)
|
|
|
|
|
DEF_NUM_INFIX(divide, /, NUM)
|
|
|
|
|
DEF_NUM_INFIX(lt, <, BOOL)
|
|
|
|
|
DEF_NUM_INFIX(gt, >, BOOL)
|
|
|
|
|
DEF_NUM_INFIX(lte, <=, BOOL)
|
|
|
|
|
DEF_NUM_INFIX(gte, >=, BOOL)
|
|
|
|
|
|
|
|
|
|
// Defines a primitive on Num that call infix bitwise [op].
|
|
|
|
|
#define DEF_NUM_BITWISE(name, op) \
|
|
|
|
|
DEF_PRIMITIVE(num_bitwise##name) \
|
|
|
|
|
{ \
|
|
|
|
|
if (!validateNum(vm, args, 1, "Right operand")) return PRIM_ERROR; \
|
|
|
|
|
uint32_t left = (uint32_t)AS_NUM(args[0]); \
|
|
|
|
|
uint32_t right = (uint32_t)AS_NUM(args[1]); \
|
|
|
|
|
RETURN_NUM(left op right); \
|
|
|
|
|
}
|
2013-10-31 15:04:44 +01:00
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_NUM_BITWISE(And, &)
|
|
|
|
|
DEF_NUM_BITWISE(Or, |)
|
|
|
|
|
DEF_NUM_BITWISE(Xor, ^)
|
|
|
|
|
DEF_NUM_BITWISE(LeftShift, <<)
|
|
|
|
|
DEF_NUM_BITWISE(RightShift, >>)
|
2013-10-31 15:04:44 +01:00
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
// Defines a primitive method on Num that returns the result of [fn].
|
|
|
|
|
#define DEF_NUM_FN(name, fn) \
|
|
|
|
|
DEF_PRIMITIVE(num_##name) \
|
|
|
|
|
{ \
|
|
|
|
|
RETURN_NUM(fn(AS_NUM(args[0]))); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEF_NUM_FN(abs, fabs)
|
|
|
|
|
DEF_NUM_FN(acos, acos)
|
|
|
|
|
DEF_NUM_FN(asin, asin)
|
|
|
|
|
DEF_NUM_FN(atan, atan)
|
|
|
|
|
DEF_NUM_FN(ceil, ceil)
|
|
|
|
|
DEF_NUM_FN(cos, cos)
|
|
|
|
|
DEF_NUM_FN(floor, floor)
|
|
|
|
|
DEF_NUM_FN(negate, -)
|
|
|
|
|
DEF_NUM_FN(sin, sin)
|
|
|
|
|
DEF_NUM_FN(sqrt, sqrt)
|
|
|
|
|
DEF_NUM_FN(tan, tan)
|
2013-10-31 15:04:44 +01:00
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(num_mod)
|
2013-11-10 06:01:18 +01:00
|
|
|
{
|
2014-01-02 16:32:00 +01:00
|
|
|
if (!validateNum(vm, args, 1, "Right operand")) return PRIM_ERROR;
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_NUM(fmod(AS_NUM(args[0]), AS_NUM(args[1])));
|
2013-11-10 06:01:18 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(num_eqeq)
|
2013-11-05 18:57:57 +01:00
|
|
|
{
|
2014-01-01 22:25:24 +01:00
|
|
|
if (!IS_NUM(args[1])) RETURN_FALSE;
|
|
|
|
|
RETURN_BOOL(AS_NUM(args[0]) == AS_NUM(args[1]));
|
2013-11-05 18:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(num_bangeq)
|
2013-11-05 18:57:57 +01:00
|
|
|
{
|
2014-01-01 22:25:24 +01:00
|
|
|
if (!IS_NUM(args[1])) RETURN_TRUE;
|
|
|
|
|
RETURN_BOOL(AS_NUM(args[0]) != AS_NUM(args[1]));
|
2013-11-05 18:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(num_bitwiseNot)
|
2013-12-05 07:09:31 +01:00
|
|
|
{
|
|
|
|
|
// Bitwise operators always work on 32-bit unsigned ints.
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_NUM(~(uint32_t)AS_NUM(args[0]));
|
2013-12-05 07:09:31 +01:00
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_dotDot)
|
2014-02-24 16:27:43 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
if (!validateNum(vm, args, 1, "Right hand side of range")) return PRIM_ERROR;
|
2014-02-24 16:27:43 +01:00
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
double from = AS_NUM(args[0]);
|
|
|
|
|
double to = AS_NUM(args[1]);
|
|
|
|
|
RETURN_VAL(wrenNewRange(vm, from, to, true));
|
2014-02-24 16:27:43 +01:00
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_dotDotDot)
|
2014-02-24 16:27:43 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
if (!validateNum(vm, args, 1, "Right hand side of range")) return PRIM_ERROR;
|
2014-02-24 16:27:43 +01:00
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
double from = AS_NUM(args[0]);
|
|
|
|
|
double to = AS_NUM(args[1]);
|
|
|
|
|
RETURN_VAL(wrenNewRange(vm, from, to, false));
|
2014-02-24 16:27:43 +01:00
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_atan2)
|
2015-02-16 11:29:14 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_NUM(atan2(AS_NUM(args[0]), AS_NUM(args[1])));
|
2015-02-16 11:29:14 +01:00
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_fraction)
|
2015-02-16 11:29:14 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
double dummy;
|
|
|
|
|
RETURN_NUM(modf(AS_NUM(args[0]) , &dummy));
|
2015-02-16 11:29:14 +01:00
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_isNan)
|
2015-02-16 11:29:14 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_BOOL(isnan(AS_NUM(args[0])));
|
2015-02-16 11:29:14 +01:00
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_sign)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
double value = AS_NUM(args[0]);
|
|
|
|
|
if (value > 0)
|
|
|
|
|
{
|
|
|
|
|
RETURN_NUM(1);
|
|
|
|
|
}
|
|
|
|
|
else if (value < 0)
|
|
|
|
|
{
|
|
|
|
|
RETURN_NUM(-1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RETURN_NUM(0);
|
|
|
|
|
}
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_toString)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_VAL(wrenNumToString(vm, AS_NUM(args[0])));
|
|
|
|
|
}
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
DEF_PRIMITIVE(num_truncate)
|
|
|
|
|
{
|
|
|
|
|
double integer;
|
|
|
|
|
modf(AS_NUM(args[0]) , &integer);
|
|
|
|
|
RETURN_NUM(integer);
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_not)
|
2015-01-16 06:50:01 +01:00
|
|
|
{
|
|
|
|
|
RETURN_VAL(FALSE_VAL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_eqeq)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
2015-01-26 08:26:59 +01:00
|
|
|
RETURN_BOOL(wrenValuesEqual(args[0], args[1]));
|
2013-11-26 16:52:37 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_bangeq)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
2015-01-26 08:26:59 +01:00
|
|
|
RETURN_BOOL(!wrenValuesEqual(args[0], args[1]));
|
2013-11-26 16:52:37 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_new)
|
2013-12-19 16:02:27 +01:00
|
|
|
{
|
|
|
|
|
// This is the default argument-less constructor that all objects inherit.
|
|
|
|
|
// It just returns "this".
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_VAL(args[0]);
|
2013-12-19 16:02:27 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_toString)
|
2013-12-22 20:50:00 +01:00
|
|
|
{
|
2014-01-29 00:31:11 +01:00
|
|
|
if (IS_CLASS(args[0]))
|
|
|
|
|
{
|
|
|
|
|
RETURN_OBJ(AS_CLASS(args[0])->name);
|
|
|
|
|
}
|
|
|
|
|
else if (IS_INSTANCE(args[0]))
|
|
|
|
|
{
|
|
|
|
|
ObjInstance* instance = AS_INSTANCE(args[0]);
|
2015-03-16 06:32:20 +01:00
|
|
|
Value name = OBJ_VAL(instance->obj.classObj->name);
|
|
|
|
|
RETURN_VAL(wrenStringFormat(vm, "instance of @", name));
|
2014-01-29 00:31:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(CONST_STRING(vm, "<object>"));
|
2013-12-22 20:50:00 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_type)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
2014-01-29 00:31:11 +01:00
|
|
|
RETURN_OBJ(wrenGetClass(vm, args[0]));
|
2013-11-26 16:52:37 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_instantiate)
|
2014-04-03 02:42:30 +02:00
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Must provide a class to 'new' to construct.");
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_from)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_NUM(AS_RANGE(args[0])->from);
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_to)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_NUM(AS_RANGE(args[0])->to);
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_min)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
|
|
|
|
ObjRange* range = AS_RANGE(args[0]);
|
|
|
|
|
RETURN_NUM(fmin(range->from, range->to));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_max)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
|
|
|
|
ObjRange* range = AS_RANGE(args[0]);
|
|
|
|
|
RETURN_NUM(fmax(range->from, range->to));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_isInclusive)
|
2014-01-20 22:20:22 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_BOOL(AS_RANGE(args[0])->isInclusive);
|
2014-01-20 22:20:22 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_iterate)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
|
|
|
|
ObjRange* range = AS_RANGE(args[0]);
|
|
|
|
|
|
2014-01-20 22:20:22 +01:00
|
|
|
// Special case: empty range.
|
|
|
|
|
if (range->from == range->to && !range->isInclusive) RETURN_FALSE;
|
|
|
|
|
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
// Start the iteration.
|
|
|
|
|
if (IS_NULL(args[1])) RETURN_NUM(range->from);
|
|
|
|
|
|
|
|
|
|
if (!validateNum(vm, args, 1, "Iterator")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
double iterator = AS_NUM(args[1]);
|
|
|
|
|
|
2014-01-20 22:20:22 +01:00
|
|
|
// Iterate towards [to] from [from].
|
|
|
|
|
if (range->from < range->to)
|
|
|
|
|
{
|
|
|
|
|
iterator++;
|
|
|
|
|
if (iterator > range->to) RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
iterator--;
|
|
|
|
|
if (iterator < range->to) RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!range->isInclusive && iterator == range->to) RETURN_FALSE;
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
|
2014-01-20 22:20:22 +01:00
|
|
|
RETURN_NUM(iterator);
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_iteratorValue)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
|
|
|
|
// Assume the iterator is a number so that is the value of the range.
|
|
|
|
|
RETURN_VAL(args[1]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(range_toString)
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
{
|
|
|
|
|
ObjRange* range = AS_RANGE(args[0]);
|
2015-03-16 06:32:20 +01:00
|
|
|
|
|
|
|
|
Value from = wrenNumToString(vm, range->from);
|
|
|
|
|
wrenPushRoot(vm, AS_OBJ(from));
|
|
|
|
|
|
|
|
|
|
Value to = wrenNumToString(vm, range->to);
|
|
|
|
|
wrenPushRoot(vm, AS_OBJ(to));
|
|
|
|
|
|
|
|
|
|
Value result = wrenStringFormat(vm, "@$@", from,
|
|
|
|
|
range->isInclusive ? ".." : "...", to);
|
|
|
|
|
|
|
|
|
|
wrenPopRoot(vm);
|
|
|
|
|
wrenPopRoot(vm);
|
|
|
|
|
RETURN_VAL(result);
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_contains)
|
2013-10-27 19:28:15 +01:00
|
|
|
{
|
2014-01-03 19:47:26 +01:00
|
|
|
if (!validateString(vm, args, 1, "Argument")) return PRIM_ERROR;
|
|
|
|
|
|
2015-01-07 22:05:33 +01:00
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
2013-10-27 19:28:15 +01:00
|
|
|
|
2015-02-05 05:23:50 +01:00
|
|
|
RETURN_BOOL(wrenStringFind(vm, string, search) != UINT32_MAX);
|
2013-10-27 19:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_count)
|
2013-10-27 19:28:15 +01:00
|
|
|
{
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_NUM(AS_STRING(args[0])->length);
|
2013-10-27 19:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_endsWith)
|
2015-01-10 23:45:14 +01:00
|
|
|
{
|
|
|
|
|
if (!validateString(vm, args, 1, "Argument")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
|
|
|
|
|
|
|
|
|
// Corner case, if the search string is longer than return false right away.
|
|
|
|
|
if (search->length > string->length) RETURN_FALSE;
|
|
|
|
|
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
RETURN_BOOL(memcmp(string->value + string->length - search->length,
|
|
|
|
|
search->value, search->length) == 0);
|
2015-01-10 23:45:14 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_indexOf)
|
2015-01-10 23:45:14 +01:00
|
|
|
{
|
|
|
|
|
if (!validateString(vm, args, 1, "Argument")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
|
|
|
|
|
2015-02-04 13:38:15 +01:00
|
|
|
uint32_t index = wrenStringFind(vm, string, search);
|
2015-02-05 05:23:50 +01:00
|
|
|
RETURN_NUM(index == UINT32_MAX ? -1 : (int)index);
|
2015-01-10 23:45:14 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_iterate)
|
2015-01-23 05:58:22 +01:00
|
|
|
{
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
|
|
|
|
|
// If we're starting the iteration, return the first index.
|
|
|
|
|
if (IS_NULL(args[1]))
|
|
|
|
|
{
|
|
|
|
|
if (string->length == 0) RETURN_FALSE;
|
|
|
|
|
RETURN_NUM(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!validateInt(vm, args, 1, "Iterator")) return PRIM_ERROR;
|
|
|
|
|
|
2015-02-25 06:56:33 +01:00
|
|
|
if (AS_NUM(args[1]) < 0) RETURN_FALSE;
|
|
|
|
|
uint32_t index = (uint32_t)AS_NUM(args[1]);
|
2015-01-23 05:58:22 +01:00
|
|
|
|
|
|
|
|
// Advance to the beginning of the next UTF-8 sequence.
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
index++;
|
2015-02-25 06:56:33 +01:00
|
|
|
if (index >= string->length) RETURN_FALSE;
|
2015-01-23 05:58:22 +01:00
|
|
|
} while ((string->value[index] & 0xc0) == 0x80);
|
|
|
|
|
|
|
|
|
|
RETURN_NUM(index);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_iteratorValue)
|
2015-01-23 05:58:22 +01:00
|
|
|
{
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
2015-03-21 20:22:04 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, string->length, 1, "Iterator");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2015-01-23 05:58:22 +01:00
|
|
|
|
|
|
|
|
RETURN_VAL(wrenStringCodePointAt(vm, string, index));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_startsWith)
|
2015-01-10 23:45:14 +01:00
|
|
|
{
|
|
|
|
|
if (!validateString(vm, args, 1, "Argument")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
|
|
|
|
|
|
|
|
|
// Corner case, if the search string is longer than return false right away.
|
|
|
|
|
if (search->length > string->length) RETURN_FALSE;
|
|
|
|
|
|
|
|
|
|
RETURN_BOOL(memcmp(string->value, search->value, search->length) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_toString)
|
2013-11-02 07:27:28 +01:00
|
|
|
{
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_VAL(args[0]);
|
2013-11-02 07:27:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_plus)
|
2013-10-31 15:04:44 +01:00
|
|
|
{
|
2014-04-09 06:17:49 +02:00
|
|
|
if (!validateString(vm, args, 1, "Right operand")) return PRIM_ERROR;
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(wrenStringFormat(vm, "@@", args[0], args[1]));
|
2013-10-31 15:04:44 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(string_subscript)
|
2013-11-24 19:45:07 +01:00
|
|
|
{
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
|
2015-01-17 08:20:56 +01:00
|
|
|
if (IS_NUM(args[1]))
|
|
|
|
|
{
|
|
|
|
|
int index = validateIndex(vm, args, string->length, 1, "Subscript");
|
|
|
|
|
if (index == -1) return PRIM_ERROR;
|
|
|
|
|
|
2015-01-23 01:38:03 +01:00
|
|
|
RETURN_VAL(wrenStringCodePointAt(vm, string, index));
|
2015-01-17 08:20:56 +01:00
|
|
|
}
|
2013-11-24 19:45:07 +01:00
|
|
|
|
2015-01-17 08:20:56 +01:00
|
|
|
if (!IS_RANGE(args[1]))
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Subscript must be a number or a range.");
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 01:38:03 +01:00
|
|
|
// TODO: Handle UTF-8 here.
|
2015-03-18 15:09:03 +01:00
|
|
|
/*
|
2015-01-21 00:33:21 +01:00
|
|
|
int step;
|
|
|
|
|
int count = string->length;
|
|
|
|
|
int start = calculateRange(vm, args, AS_RANGE(args[1]), &count, &step);
|
|
|
|
|
if (start == -1) return PRIM_ERROR;
|
2015-01-17 08:20:56 +01:00
|
|
|
|
2015-03-16 06:32:20 +01:00
|
|
|
ObjString* result = wrenNewUninitializedString(vm, count);
|
2015-01-21 00:33:21 +01:00
|
|
|
for (int i = 0; i < count; i++)
|
2015-01-17 08:20:56 +01:00
|
|
|
{
|
2015-01-21 00:33:21 +01:00
|
|
|
result->value[i] = string->value[start + (i * step)];
|
2015-01-17 08:20:56 +01:00
|
|
|
}
|
2015-01-21 00:33:21 +01:00
|
|
|
result->value[count] = '\0';
|
2015-01-17 08:20:56 +01:00
|
|
|
|
|
|
|
|
RETURN_OBJ(result);
|
2015-03-18 15:09:03 +01:00
|
|
|
*/
|
|
|
|
|
RETURN_ERROR("Subscript ranges for strings are not implemented yet.");
|
2013-11-24 19:45:07 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:31:11 +01:00
|
|
|
static ObjClass* defineSingleClass(WrenVM* vm, const char* name)
|
|
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
ObjString* nameString = AS_STRING(wrenStringFormat(vm, "$", name));
|
2015-01-21 16:56:06 +01:00
|
|
|
wrenPushRoot(vm, (Obj*)nameString);
|
2014-01-29 00:31:11 +01:00
|
|
|
|
|
|
|
|
ObjClass* classObj = wrenNewSingleClass(vm, 0, nameString);
|
2015-03-16 06:32:20 +01:00
|
|
|
wrenDefineVariable(vm, NULL, name, nameString->length, OBJ_VAL(classObj));
|
2014-01-29 00:31:11 +01:00
|
|
|
|
2015-01-21 16:56:06 +01:00
|
|
|
wrenPopRoot(vm);
|
2014-01-29 00:31:11 +01:00
|
|
|
return classObj;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
static ObjClass* defineClass(WrenVM* vm, const char* name)
|
2013-11-26 16:52:37 +01:00
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
ObjString* nameString = AS_STRING(wrenStringFormat(vm, "$", name));
|
2015-01-21 16:56:06 +01:00
|
|
|
wrenPushRoot(vm, (Obj*)nameString);
|
2014-01-29 00:31:11 +01:00
|
|
|
|
|
|
|
|
ObjClass* classObj = wrenNewClass(vm, vm->objectClass, 0, nameString);
|
2015-03-16 06:32:20 +01:00
|
|
|
wrenDefineVariable(vm, NULL, name, nameString->length, OBJ_VAL(classObj));
|
2014-01-29 00:31:11 +01:00
|
|
|
|
2015-01-21 16:56:06 +01:00
|
|
|
wrenPopRoot(vm);
|
2013-11-26 16:52:37 +01:00
|
|
|
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).
|
2014-01-29 00:31:11 +01:00
|
|
|
vm->objectClass = defineSingleClass(vm, "Object");
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->objectClass, "!", object_not);
|
|
|
|
|
PRIMITIVE(vm->objectClass, "==(_)", object_eqeq);
|
|
|
|
|
PRIMITIVE(vm->objectClass, "!=(_)", object_bangeq);
|
|
|
|
|
PRIMITIVE(vm->objectClass, "new", object_new);
|
|
|
|
|
PRIMITIVE(vm->objectClass, "toString", object_toString);
|
|
|
|
|
PRIMITIVE(vm->objectClass, "type", object_type);
|
|
|
|
|
PRIMITIVE(vm->objectClass, "<instantiate>", object_instantiate);
|
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.
|
2014-01-29 00:31:11 +01:00
|
|
|
vm->classClass = defineSingleClass(vm, "Class");
|
2013-12-22 05:44:37 +01:00
|
|
|
|
|
|
|
|
// Now that Object and Class are defined, we can wire them up to each other.
|
2014-01-04 20:08:31 +01:00
|
|
|
wrenBindSuperclass(vm, vm->classClass, vm->objectClass);
|
2014-12-07 23:29:50 +01:00
|
|
|
vm->objectClass->obj.classObj = vm->classClass;
|
|
|
|
|
vm->classClass->obj.classObj = vm->classClass;
|
2013-12-22 05:44:37 +01:00
|
|
|
|
2014-04-03 02:42:30 +02:00
|
|
|
// Define the methods specific to Class after wiring up its superclass to
|
|
|
|
|
// prevent the inherited ones from overwriting them.
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->classClass, "<instantiate>", class_instantiate);
|
|
|
|
|
PRIMITIVE(vm->classClass, "name", class_name);
|
2015-03-14 17:48:45 +01:00
|
|
|
PRIMITIVE(vm->classClass, "supertype", class_supertype);
|
2014-04-03 02:42:30 +02:00
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
// 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:
|
|
|
|
|
//
|
2014-11-28 20:21:01 +01:00
|
|
|
// .------------. .========.
|
|
|
|
|
// | | || ||
|
|
|
|
|
// v | v ||
|
|
|
|
|
// .---------. .--------------. ||
|
|
|
|
|
// | Object |==>| Class |==='
|
2013-12-22 05:44:37 +01:00
|
|
|
// '---------' '--------------'
|
|
|
|
|
// ^ ^
|
|
|
|
|
// | |
|
2014-11-28 20:21:01 +01:00
|
|
|
// .---------. .--------------. -.
|
2013-12-22 05:44:37 +01:00
|
|
|
// | Base |==>| Base.type | |
|
|
|
|
|
// '---------' '--------------' |
|
|
|
|
|
// ^ ^ | Hypothetical example classes
|
|
|
|
|
// | | |
|
|
|
|
|
// .---------. .--------------. |
|
|
|
|
|
// | Derived |==>| Derived.type | |
|
2014-11-28 20:21:01 +01:00
|
|
|
// '---------' '--------------' -'
|
2013-12-22 05:44:37 +01:00
|
|
|
|
|
|
|
|
// The rest of the classes can not be defined normally.
|
|
|
|
|
vm->boolClass = defineClass(vm, "Bool");
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->boolClass, "toString", bool_toString);
|
|
|
|
|
PRIMITIVE(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");
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->fiberClass->obj.classObj, "<instantiate>", fiber_instantiate);
|
|
|
|
|
PRIMITIVE(vm->fiberClass->obj.classObj, "new(_)", fiber_new);
|
|
|
|
|
PRIMITIVE(vm->fiberClass->obj.classObj, "abort(_)", fiber_abort);
|
2015-03-07 21:32:11 +01:00
|
|
|
PRIMITIVE(vm->fiberClass->obj.classObj, "current", fiber_current);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->fiberClass->obj.classObj, "yield()", fiber_yield);
|
|
|
|
|
PRIMITIVE(vm->fiberClass->obj.classObj, "yield(_)", fiber_yield1);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "call()", fiber_call);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "call(_)", fiber_call1);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "error", fiber_error);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "isDone", fiber_isDone);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "run()", fiber_run);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "run(_)", fiber_run1);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "try()", fiber_try);
|
2014-01-04 20:08:31 +01:00
|
|
|
|
2014-04-03 02:42:30 +02:00
|
|
|
vm->fnClass = defineClass(vm, "Fn");
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->fnClass->obj.classObj, "<instantiate>", fn_instantiate);
|
|
|
|
|
PRIMITIVE(vm->fnClass->obj.classObj, "new(_)", fn_new);
|
|
|
|
|
|
|
|
|
|
PRIMITIVE(vm->fnClass, "arity", fn_arity);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call()", fn_call0);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_)", fn_call1);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_)", fn_call2);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_)", fn_call3);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_)", fn_call4);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_)", fn_call5);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_)", fn_call6);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_)", fn_call7);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_)", fn_call8);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_)", fn_call9);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_)", fn_call10);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_)", fn_call11);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_)", fn_call12);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call13);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call14);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call15);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call16);
|
|
|
|
|
PRIMITIVE(vm->fnClass, "toString", fn_toString);
|
2013-11-06 15:52:28 +01:00
|
|
|
|
2013-12-22 05:44:37 +01:00
|
|
|
vm->nullClass = defineClass(vm, "Null");
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->nullClass, "!", null_not);
|
|
|
|
|
PRIMITIVE(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
|
|
|
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
vm->numClass = defineClass(vm, "Num");
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->numClass->obj.classObj, "fromString(_)", num_fromString);
|
2015-03-19 21:12:50 +01:00
|
|
|
PRIMITIVE(vm->numClass->obj.classObj, "pi", num_pi);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->numClass, "-(_)", num_minus);
|
|
|
|
|
PRIMITIVE(vm->numClass, "+(_)", num_plus);
|
|
|
|
|
PRIMITIVE(vm->numClass, "*(_)", num_multiply);
|
|
|
|
|
PRIMITIVE(vm->numClass, "/(_)", num_divide);
|
|
|
|
|
PRIMITIVE(vm->numClass, "<(_)", num_lt);
|
|
|
|
|
PRIMITIVE(vm->numClass, ">(_)", num_gt);
|
|
|
|
|
PRIMITIVE(vm->numClass, "<=(_)", num_lte);
|
|
|
|
|
PRIMITIVE(vm->numClass, ">=(_)", num_gte);
|
|
|
|
|
PRIMITIVE(vm->numClass, "&(_)", num_bitwiseAnd);
|
|
|
|
|
PRIMITIVE(vm->numClass, "|(_)", num_bitwiseOr);
|
|
|
|
|
PRIMITIVE(vm->numClass, "^(_)", num_bitwiseXor);
|
|
|
|
|
PRIMITIVE(vm->numClass, "<<(_)", num_bitwiseLeftShift);
|
|
|
|
|
PRIMITIVE(vm->numClass, ">>(_)", num_bitwiseRightShift);
|
|
|
|
|
PRIMITIVE(vm->numClass, "abs", num_abs);
|
2015-03-14 14:52:16 +01:00
|
|
|
PRIMITIVE(vm->numClass, "acos", num_acos);
|
|
|
|
|
PRIMITIVE(vm->numClass, "asin", num_asin);
|
|
|
|
|
PRIMITIVE(vm->numClass, "atan", num_atan);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->numClass, "ceil", num_ceil);
|
|
|
|
|
PRIMITIVE(vm->numClass, "cos", num_cos);
|
|
|
|
|
PRIMITIVE(vm->numClass, "floor", num_floor);
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
PRIMITIVE(vm->numClass, "-", num_negate);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->numClass, "sin", num_sin);
|
|
|
|
|
PRIMITIVE(vm->numClass, "sqrt", num_sqrt);
|
2015-03-14 14:40:23 +01:00
|
|
|
PRIMITIVE(vm->numClass, "tan", num_tan);
|
refactor: remove inline local variable declarations in list primitives and delete redundant math primitives from wren_core.c
Consolidate temporary variable usage in list_add, list_count, and list_iterate by directly inlining AS_LIST/AS_NUM calls. Remove the entire block of num_abs, num_acos, num_asin, num_atan, num_atan2, num_ceil, num_cos, num_floor, and num_fraction primitive definitions to eliminate boilerplate.
2015-03-21 22:57:43 +01:00
|
|
|
PRIMITIVE(vm->numClass, "%(_)", num_mod);
|
|
|
|
|
PRIMITIVE(vm->numClass, "~", num_bitwiseNot);
|
|
|
|
|
PRIMITIVE(vm->numClass, "..(_)", num_dotDot);
|
|
|
|
|
PRIMITIVE(vm->numClass, "...(_)", num_dotDotDot);
|
|
|
|
|
PRIMITIVE(vm->numClass, "atan(_)", num_atan2);
|
|
|
|
|
PRIMITIVE(vm->numClass, "fraction", num_fraction);
|
|
|
|
|
PRIMITIVE(vm->numClass, "isNan", num_isNan);
|
|
|
|
|
PRIMITIVE(vm->numClass, "sign", num_sign);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->numClass, "toString", num_toString);
|
2015-03-04 00:29:19 +01:00
|
|
|
PRIMITIVE(vm->numClass, "truncate", num_truncate);
|
2015-01-16 06:50:01 +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.
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->numClass, "==(_)", num_eqeq);
|
|
|
|
|
PRIMITIVE(vm->numClass, "!=(_)", num_bangeq);
|
feat: replace Wren Range class with native C object for performance
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
2014-01-20 17:45:15 +01:00
|
|
|
|
2015-01-23 05:58:22 +01:00
|
|
|
wrenInterpret(vm, "", libSource);
|
|
|
|
|
|
2015-02-05 21:03:19 +01:00
|
|
|
vm->stringClass = AS_CLASS(wrenFindVariable(vm, "String"));
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->stringClass, "+(_)", string_plus);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "[_]", string_subscript);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "contains(_)", string_contains);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "count", string_count);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "endsWith(_)", string_endsWith);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "indexOf(_)", string_indexOf);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "iterate(_)", string_iterate);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "iteratorValue(_)", string_iteratorValue);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "startsWith(_)", string_startsWith);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "toString", string_toString);
|
2013-10-28 06:45:40 +01:00
|
|
|
|
2015-02-05 21:03:19 +01:00
|
|
|
vm->listClass = AS_CLASS(wrenFindVariable(vm, "List"));
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->listClass->obj.classObj, "<instantiate>", list_instantiate);
|
|
|
|
|
PRIMITIVE(vm->listClass, "[_]", list_subscript);
|
|
|
|
|
PRIMITIVE(vm->listClass, "[_]=(_)", list_subscriptSetter);
|
|
|
|
|
PRIMITIVE(vm->listClass, "add(_)", list_add);
|
|
|
|
|
PRIMITIVE(vm->listClass, "clear()", list_clear);
|
|
|
|
|
PRIMITIVE(vm->listClass, "count", list_count);
|
|
|
|
|
PRIMITIVE(vm->listClass, "insert(_,_)", list_insert);
|
|
|
|
|
PRIMITIVE(vm->listClass, "iterate(_)", list_iterate);
|
|
|
|
|
PRIMITIVE(vm->listClass, "iteratorValue(_)", list_iteratorValue);
|
|
|
|
|
PRIMITIVE(vm->listClass, "removeAt(_)", list_removeAt);
|
2013-12-22 20:50:00 +01:00
|
|
|
|
2015-02-05 21:03:19 +01:00
|
|
|
vm->mapClass = AS_CLASS(wrenFindVariable(vm, "Map"));
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->mapClass->obj.classObj, "<instantiate>", map_instantiate);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "[_]", map_subscript);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "[_]=(_)", map_subscriptSetter);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "clear()", map_clear);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "containsKey(_)", map_containsKey);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "count", map_count);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "remove(_)", map_remove);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "iterate_(_)", map_iterate);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "keyIteratorValue_(_)", map_keyIteratorValue);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "valueIteratorValue_(_)", map_valueIteratorValue);
|
feat: add initial Map class with hash table, subscript, and count support
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
2015-01-25 07:27:35 +01:00
|
|
|
|
2015-02-05 21:03:19 +01:00
|
|
|
vm->rangeClass = AS_CLASS(wrenFindVariable(vm, "Range"));
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->rangeClass, "from", range_from);
|
|
|
|
|
PRIMITIVE(vm->rangeClass, "to", range_to);
|
|
|
|
|
PRIMITIVE(vm->rangeClass, "min", range_min);
|
|
|
|
|
PRIMITIVE(vm->rangeClass, "max", range_max);
|
|
|
|
|
PRIMITIVE(vm->rangeClass, "isInclusive", range_isInclusive);
|
|
|
|
|
PRIMITIVE(vm->rangeClass, "iterate(_)", range_iterate);
|
|
|
|
|
PRIMITIVE(vm->rangeClass, "iteratorValue(_)", range_iteratorValue);
|
|
|
|
|
PRIMITIVE(vm->rangeClass, "toString", range_toString);
|
2015-01-23 05:58:22 +01:00
|
|
|
|
|
|
|
|
// While bootstrapping the core types and running the core library, a number
|
2015-02-17 16:21:51 +01:00
|
|
|
// of string objects have been created, many of which were instantiated
|
|
|
|
|
// before stringClass was stored in the VM. Some of them *must* be created
|
|
|
|
|
// first -- the ObjClass for string itself has a reference to the ObjString
|
|
|
|
|
// for its name.
|
2015-01-23 05:58:22 +01:00
|
|
|
//
|
2015-02-17 16:21:51 +01:00
|
|
|
// These all currently have a NULL classObj pointer, so go back and assign
|
|
|
|
|
// them now that the string class is known.
|
2015-01-23 05:58:22 +01:00
|
|
|
for (Obj* obj = vm->first; obj != NULL; obj = obj->next)
|
|
|
|
|
{
|
|
|
|
|
if (obj->type == OBJ_STRING) obj->classObj = vm->stringClass;
|
|
|
|
|
}
|
2013-11-06 00:40:21 +01:00
|
|
|
}
|