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"
|
2015-04-04 06:22:58 +02:00
|
|
|
#include "wren_primitive.h"
|
2013-11-28 17:11:50 +01:00
|
|
|
#include "wren_value.h"
|
2013-10-27 19:28:15 +01:00
|
|
|
|
2014-02-04 17:44:59 +01:00
|
|
|
// This string literal is generated automatically from core. Do not edit.
|
2015-04-16 13:07:14 +02:00
|
|
|
static const char* coreLibSource =
|
2015-04-03 17:00:55 +02:00
|
|
|
"class Bool {}\n"
|
|
|
|
|
"class Fiber {}\n"
|
|
|
|
|
"class Fn {}\n"
|
|
|
|
|
"class Null {}\n"
|
|
|
|
|
"class Num {}\n"
|
|
|
|
|
"\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
"class Sequence {\n"
|
2015-03-28 18:18:45 +01:00
|
|
|
" all(f) {\n"
|
|
|
|
|
" var result = true\n"
|
|
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" result = f.call(element)\n"
|
|
|
|
|
" if (!result) return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" any(f) {\n"
|
|
|
|
|
" var result = false\n"
|
|
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" result = f.call(element)\n"
|
|
|
|
|
" if (result) return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-03-15 15:43:10 +01:00
|
|
|
" contains(element) {\n"
|
|
|
|
|
" for (item in this) {\n"
|
2015-03-28 18:18:45 +01:00
|
|
|
" if (element == item) return true\n"
|
2015-03-15 15:43:10 +01:00
|
|
|
" }\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"
|
2015-03-14 14:17:21 +01:00
|
|
|
" count(f) {\n"
|
|
|
|
|
" var result = 0\n"
|
|
|
|
|
" for (element in this) {\n"
|
2015-03-28 18:18:45 +01:00
|
|
|
" if (f.call(element)) result = result + 1\n"
|
2015-03-14 14:17:21 +01:00
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-03-28 20:35:20 +01:00
|
|
|
" each(f) {\n"
|
|
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" f.call(element)\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-06-30 16:39:43 +02:00
|
|
|
" isEmpty { iterate(null) ? false : true }\n"
|
|
|
|
|
"\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" map(transformation) { MapSequence.new(this, transformation) }\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
"\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" where(predicate) { WhereSequence.new(this, predicate) }\n"
|
2015-01-14 08:47:01 +01:00
|
|
|
"\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"
|
2015-03-27 22:59:58 +01:00
|
|
|
"\n"
|
2015-04-03 20:22:34 +02:00
|
|
|
" toList {\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" var result = List.new()\n"
|
2015-03-27 22:59:58 +01:00
|
|
|
" for (element in this) {\n"
|
|
|
|
|
" result.add(element)\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" return result\n"
|
|
|
|
|
" }\n"
|
2014-02-16 18:20:31 +01:00
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
2015-03-28 22:51:50 +01:00
|
|
|
"class MapSequence is Sequence {\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" this new(sequence, fn) {\n"
|
2015-04-01 16:31:15 +02:00
|
|
|
" _sequence = sequence\n"
|
|
|
|
|
" _fn = fn\n"
|
2015-03-28 22:51:50 +01:00
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-04-01 16:31:15 +02:00
|
|
|
" iterate(iterator) { _sequence.iterate(iterator) }\n"
|
|
|
|
|
" iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }\n"
|
2015-03-28 22:51:50 +01:00
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"class WhereSequence is Sequence {\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" this new(sequence, fn) {\n"
|
2015-04-01 16:31:15 +02:00
|
|
|
" _sequence = sequence\n"
|
|
|
|
|
" _fn = fn\n"
|
2015-03-28 22:51:50 +01:00
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-04-01 16:31:15 +02:00
|
|
|
" iterate(iterator) {\n"
|
|
|
|
|
" while (iterator = _sequence.iterate(iterator)) {\n"
|
|
|
|
|
" if (_fn.call(_sequence.iteratorValue(iterator))) break\n"
|
2015-03-28 22:51:50 +01:00
|
|
|
" }\n"
|
2015-04-01 16:31:15 +02:00
|
|
|
" return iterator\n"
|
2015-03-28 22:51:50 +01:00
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
2015-04-01 16:31:15 +02:00
|
|
|
" iteratorValue(iterator) { _sequence.iteratorValue(iterator) }\n"
|
2015-03-28 22:51:50 +01:00
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
2015-03-28 04:44:07 +01:00
|
|
|
"class String is Sequence {\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" bytes { StringByteSequence.new(this) }\n"
|
2015-03-28 04:44:07 +01:00
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"class StringByteSequence is Sequence {\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" this new(string) {\n"
|
2015-03-28 04:44:07 +01:00
|
|
|
" _string = string\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" [index] { _string.byteAt(index) }\n"
|
|
|
|
|
" iterate(iterator) { _string.iterateByte_(iterator) }\n"
|
|
|
|
|
" iteratorValue(iterator) { _string.byteAt(iterator) }\n"
|
|
|
|
|
"}\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-05-19 15:50:17 +02: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-07-10 18:18:22 +02:00
|
|
|
" keys { MapKeySequence.new(this) }\n"
|
|
|
|
|
" values { MapValueSequence.new(this) }\n"
|
2015-01-25 19:27:38 +01:00
|
|
|
"\n"
|
|
|
|
|
" toString {\n"
|
2015-05-19 15:50:17 +02:00
|
|
|
" var first = true\n"
|
|
|
|
|
" var result = \"{\"\n"
|
2015-01-25 19:27:38 +01:00
|
|
|
"\n"
|
2015-05-19 15:50:17 +02:00
|
|
|
" for (key in keys) {\n"
|
|
|
|
|
" if (!first) result = result + \", \"\n"
|
|
|
|
|
" first = false\n"
|
|
|
|
|
" result = result + key.toString + \": \" + this[key].toString\n"
|
2015-05-03 20:13:05 +02:00
|
|
|
" }\n"
|
2015-05-19 15:50:17 +02:00
|
|
|
"\n"
|
|
|
|
|
" return result + \"}\"\n"
|
2015-01-25 19:27:38 +01:00
|
|
|
" }\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"class MapKeySequence is Sequence {\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" this new(map) {\n"
|
2015-01-25 19:27:38 +01:00
|
|
|
" _map = map\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" iterate(n) { _map.iterate_(n) }\n"
|
|
|
|
|
" iteratorValue(iterator) { _map.keyIteratorValue_(iterator) }\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"class MapValueSequence is Sequence {\n"
|
2015-07-10 18:18:22 +02:00
|
|
|
" this new(map) {\n"
|
2015-01-25 19:27:38 +01:00
|
|
|
" _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
|
|
|
|
2015-06-30 16:39:43 +02:00
|
|
|
// A simple primitive that just returns "this". Used in a few different places:
|
|
|
|
|
//
|
2015-07-10 18:18:22 +02:00
|
|
|
// * The default new() initializer on Object needs no initialization so just
|
|
|
|
|
// uses this.
|
2015-06-30 16:39:43 +02:00
|
|
|
// * String's toString method obviously can use this.
|
|
|
|
|
DEF_PRIMITIVE(return_this)
|
|
|
|
|
{
|
|
|
|
|
RETURN_VAL(args[0]);
|
|
|
|
|
}
|
|
|
|
|
|
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_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-06-30 16:39:43 +02:00
|
|
|
DEF_PRIMITIVE(class_toString)
|
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-06-30 16:39:43 +02:00
|
|
|
RETURN_OBJ(AS_CLASS(args[0])->name);
|
2014-04-05 03:24:55 +02:00
|
|
|
}
|
|
|
|
|
|
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_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);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 20:42:20 +01:00
|
|
|
static PrimitiveResult callFn(WrenVM* vm, Value* args, int numArgs)
|
2014-02-04 18:34:05 +01:00
|
|
|
{
|
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-26 20:42:20 +01:00
|
|
|
DEF_PRIMITIVE(fn_call0) { return callFn(vm, args, 0); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call1) { return callFn(vm, args, 1); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call2) { return callFn(vm, args, 2); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call3) { return callFn(vm, args, 3); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call4) { return callFn(vm, args, 4); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call5) { return callFn(vm, args, 5); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call6) { return callFn(vm, args, 6); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call7) { return callFn(vm, args, 7); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call8) { return callFn(vm, args, 8); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call9) { return callFn(vm, args, 9); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call10) { return callFn(vm, args, 10); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call11) { return callFn(vm, args, 11); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call12) { return callFn(vm, args, 12); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call13) { return callFn(vm, args, 13); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call14) { return callFn(vm, args, 14); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call15) { return callFn(vm, args, 15); }
|
|
|
|
|
DEF_PRIMITIVE(fn_call16) { return callFn(vm, args, 16); }
|
2015-03-02 16:24:04 +01:00
|
|
|
|
|
|
|
|
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-07-10 18:18:22 +02:00
|
|
|
DEF_PRIMITIVE(list_new)
|
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
|
|
|
{
|
2015-03-22 20:22:47 +01:00
|
|
|
wrenValueBufferWrite(vm, &AS_LIST(args[0])->elements, 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
|
|
|
{
|
2015-03-22 20:22:47 +01:00
|
|
|
wrenValueBufferClear(vm, &AS_LIST(args[0])->elements);
|
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
|
|
|
{
|
2015-03-22 20:22:47 +01:00
|
|
|
RETURN_NUM(AS_LIST(args[0])->elements.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-22 20:22:47 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->elements.count + 1, 1,
|
|
|
|
|
"Index");
|
2015-03-21 20:22:04 +01:00
|
|
|
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]))
|
|
|
|
|
{
|
2015-03-22 20:22:47 +01:00
|
|
|
if (list->elements.count == 0) RETURN_FALSE;
|
2014-02-15 02:24:06 +01:00
|
|
|
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-22 20:22:47 +01:00
|
|
|
if (index < 0 || index >= list->elements.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-22 20:22:47 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->elements.count, 1, "Iterator");
|
2015-03-21 20:22:04 +01:00
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2014-01-02 16:32:00 +01:00
|
|
|
|
2015-03-22 20:22:47 +01:00
|
|
|
RETURN_VAL(list->elements.data[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-22 20:22:47 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->elements.count, 1, "Index");
|
2015-03-21 20:22:04 +01:00
|
|
|
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-22 20:22:47 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->elements.count, 1,
|
|
|
|
|
"Subscript");
|
2015-03-21 20:22:04 +01:00
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2014-01-30 18:12:44 +01:00
|
|
|
|
2015-03-22 20:22:47 +01:00
|
|
|
RETURN_VAL(list->elements.data[index]);
|
2014-01-30 18:12:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-22 20:22:47 +01:00
|
|
|
uint32_t count = list->elements.count;
|
2015-03-21 20:22:04 +01:00
|
|
|
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-03-22 20:22:47 +01:00
|
|
|
result->elements.data[i] = list->elements.data[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-22 20:22:47 +01:00
|
|
|
uint32_t index = validateIndex(vm, args, list->elements.count, 1,
|
|
|
|
|
"Subscript");
|
2015-03-21 20:22:04 +01:00
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
2013-12-21 18:37:59 +01:00
|
|
|
|
2015-03-22 20:22:47 +01:00
|
|
|
list->elements.data[index] = args[2];
|
2014-01-01 22:25:24 +01:00
|
|
|
RETURN_VAL(args[2]);
|
2013-12-21 18:37:59 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-10 18:18:22 +02:00
|
|
|
DEF_PRIMITIVE(map_new)
|
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.
|
2015-04-01 15:43:44 +02:00
|
|
|
while (*end != '\0' && isspace((unsigned char)*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-05-01 16:55:28 +02:00
|
|
|
DEF_PRIMITIVE(object_same)
|
|
|
|
|
{
|
|
|
|
|
RETURN_BOOL(wrenValuesEqual(args[1], args[2]));
|
|
|
|
|
}
|
|
|
|
|
|
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-06-19 16:58:07 +02:00
|
|
|
DEF_PRIMITIVE(object_is)
|
|
|
|
|
{
|
|
|
|
|
if (!IS_CLASS(args[1]))
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Right operand must be a class.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ObjClass *classObj = wrenGetClass(vm, args[0]);
|
|
|
|
|
ObjClass *baseClassObj = AS_CLASS(args[1]);
|
|
|
|
|
|
|
|
|
|
// Walk the superclass chain looking for the class.
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (baseClassObj == classObj) RETURN_BOOL(true);
|
|
|
|
|
|
|
|
|
|
classObj = classObj->superclass;
|
|
|
|
|
}
|
|
|
|
|
while (classObj != NULL);
|
|
|
|
|
|
|
|
|
|
RETURN_BOOL(false);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(object_toString)
|
2013-12-22 20:50:00 +01:00
|
|
|
{
|
2015-06-30 16:39:43 +02:00
|
|
|
Obj* obj = AS_OBJ(args[0]);
|
|
|
|
|
Value name = OBJ_VAL(obj->classObj->name);
|
|
|
|
|
RETURN_VAL(wrenStringFormat(vm, "instance of @", name));
|
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(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-27 15:43:36 +01:00
|
|
|
DEF_PRIMITIVE(string_fromCodePoint)
|
|
|
|
|
{
|
|
|
|
|
if (!validateInt(vm, args, 1, "Code point")) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
int codePoint = (int)AS_NUM(args[1]);
|
|
|
|
|
if (codePoint < 0)
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Code point cannot be negative.");
|
|
|
|
|
}
|
|
|
|
|
else if (codePoint > 0x10ffff)
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR("Code point cannot be greater than 0x10ffff.");
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-28 04:44:07 +01:00
|
|
|
RETURN_VAL(wrenStringFromCodePoint(vm, codePoint));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEF_PRIMITIVE(string_byteAt)
|
|
|
|
|
{
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
|
|
|
|
|
uint32_t index = validateIndex(vm, args, string->length, 1, "Index");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
RETURN_NUM((uint8_t)string->value[index]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEF_PRIMITIVE(string_codePointAt)
|
|
|
|
|
{
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
|
|
|
|
|
uint32_t index = validateIndex(vm, args, string->length, 1, "Index");
|
|
|
|
|
if (index == UINT32_MAX) return PRIM_ERROR;
|
|
|
|
|
|
|
|
|
|
// If we are in the middle of a UTF-8 sequence, indicate that.
|
|
|
|
|
const uint8_t* bytes = (uint8_t*)string->value;
|
|
|
|
|
if ((bytes[index] & 0xc0) == 0x80) RETURN_NUM(-1);
|
|
|
|
|
|
|
|
|
|
// Decode the UTF-8 sequence.
|
|
|
|
|
RETURN_NUM(wrenUtf8Decode((uint8_t*)string->value + index,
|
|
|
|
|
string->length - index));
|
2015-03-27 15:43:36 +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
|
|
|
|
refactor: remove unused WrenVM* parameter from buffer init, string find, and debug print functions
Remove the `WrenVM* vm` parameter from `wrenValueBufferInit`, `wrenByteBufferInit`,
`wrenIntBufferInit`, `wrenStringBufferInit`, `wrenSymbolTableInit`,
`wrenMethodBufferInit`, `wrenStringFind`, and `wrenDebugPrintStackTrace`
functions across the compiler, core, debug, utils, value, and VM modules.
Update all call sites and macro definitions to match the simplified signatures,
eliminating dead parameters that were never used within the function bodies.
2015-03-23 06:17:40 +01:00
|
|
|
RETURN_BOOL(wrenStringFind(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]);
|
|
|
|
|
|
refactor: remove unused WrenVM* parameter from buffer init, string find, and debug print functions
Remove the `WrenVM* vm` parameter from `wrenValueBufferInit`, `wrenByteBufferInit`,
`wrenIntBufferInit`, `wrenStringBufferInit`, `wrenSymbolTableInit`,
`wrenMethodBufferInit`, `wrenStringFind`, and `wrenDebugPrintStackTrace`
functions across the compiler, core, debug, utils, value, and VM modules.
Update all call sites and macro definitions to match the simplified signatures,
eliminating dead parameters that were never used within the function bodies.
2015-03-23 06:17:40 +01:00
|
|
|
uint32_t index = wrenStringFind(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-28 04:44:07 +01:00
|
|
|
DEF_PRIMITIVE(string_iterateByte)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (AS_NUM(args[1]) < 0) RETURN_FALSE;
|
|
|
|
|
uint32_t index = (uint32_t)AS_NUM(args[1]);
|
|
|
|
|
|
|
|
|
|
// Advance to the next byte.
|
|
|
|
|
index++;
|
|
|
|
|
if (index >= string->length) RETURN_FALSE;
|
|
|
|
|
|
|
|
|
|
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_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
|
|
|
}
|
|
|
|
|
|
2015-04-03 17:00:55 +02:00
|
|
|
// Creates either the Object or Class class in the core library with [name].
|
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
|
|
|
|
2015-04-03 17:00:55 +02: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);
|
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
|
2015-05-01 16:55:28 +02:00
|
|
|
// because it has no superclass.
|
2015-03-30 01:18:36 +02:00
|
|
|
vm->objectClass = defineClass(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);
|
2015-07-10 18:18:22 +02:00
|
|
|
PRIMITIVE(vm->objectClass, "this new()", return_this);
|
2015-06-19 16:58:07 +02:00
|
|
|
PRIMITIVE(vm->objectClass, "is(_)", object_is);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->objectClass, "toString", object_toString);
|
|
|
|
|
PRIMITIVE(vm->objectClass, "type", object_type);
|
2013-11-26 16:52:37 +01:00
|
|
|
|
2015-05-01 16:55:28 +02:00
|
|
|
// Now we can define Class, which is a subclass of Object.
|
2015-03-30 01:18:36 +02:00
|
|
|
vm->classClass = defineClass(vm, "Class");
|
2014-01-04 20:08:31 +01:00
|
|
|
wrenBindSuperclass(vm, vm->classClass, vm->objectClass);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->classClass, "name", class_name);
|
2015-03-14 17:48:45 +01:00
|
|
|
PRIMITIVE(vm->classClass, "supertype", class_supertype);
|
2015-06-30 16:39:43 +02:00
|
|
|
PRIMITIVE(vm->classClass, "toString", class_toString);
|
2014-04-03 02:42:30 +02:00
|
|
|
|
2015-05-01 16:55:28 +02:00
|
|
|
// Finally, we can define Object's metaclass which is a subclass of Class.
|
|
|
|
|
ObjClass* objectMetaclass = defineClass(vm, "Object metaclass");
|
|
|
|
|
|
|
|
|
|
// Wire up the metaclass relationships now that all three classes are built.
|
|
|
|
|
vm->objectClass->obj.classObj = objectMetaclass;
|
|
|
|
|
objectMetaclass->obj.classObj = vm->classClass;
|
|
|
|
|
vm->classClass->obj.classObj = vm->classClass;
|
|
|
|
|
|
|
|
|
|
// Do this after wiring up the metaclasses so objectMetaclass doesn't get
|
|
|
|
|
// collected.
|
|
|
|
|
wrenBindSuperclass(vm, objectMetaclass, vm->classClass);
|
|
|
|
|
|
|
|
|
|
PRIMITIVE(objectMetaclass, "same(_,_)", object_same);
|
|
|
|
|
|
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:
|
|
|
|
|
//
|
2015-05-01 16:55:28 +02:00
|
|
|
// .------------------------------------. .====.
|
|
|
|
|
// | .---------------. | # #
|
|
|
|
|
// v | v | v #
|
|
|
|
|
// .---------. .-------------------. .-------. #
|
|
|
|
|
// | Object |==>| Object metaclass |==>| Class |=="
|
|
|
|
|
// '---------' '-------------------' '-------'
|
|
|
|
|
// ^ ^ ^ ^ ^
|
|
|
|
|
// | .--------------' # | #
|
|
|
|
|
// | | # | #
|
|
|
|
|
// .---------. .-------------------. # | # -.
|
|
|
|
|
// | Base |==>| Base metaclass |======" | # |
|
|
|
|
|
// '---------' '-------------------' | # |
|
|
|
|
|
// ^ | # |
|
|
|
|
|
// | .------------------' # | Example classes
|
|
|
|
|
// | | # |
|
|
|
|
|
// .---------. .-------------------. # |
|
|
|
|
|
// | Derived |==>| Derived metaclass |==========" |
|
|
|
|
|
// '---------' '-------------------' -'
|
2013-12-22 05:44:37 +01:00
|
|
|
|
2015-04-03 17:00:55 +02:00
|
|
|
// The rest of the classes can now be defined normally.
|
2015-04-16 13:07:14 +02:00
|
|
|
wrenInterpret(vm, "", coreLibSource);
|
2015-04-03 17:00:55 +02:00
|
|
|
|
|
|
|
|
vm->boolClass = AS_CLASS(wrenFindVariable(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
|
|
|
|
2015-04-03 17:00:55 +02:00
|
|
|
vm->fiberClass = AS_CLASS(wrenFindVariable(vm, "Fiber"));
|
2015-03-02 16:24:04 +01:00
|
|
|
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
|
|
|
|
2015-04-03 17:00:55 +02:00
|
|
|
vm->fnClass = AS_CLASS(wrenFindVariable(vm, "Fn"));
|
2015-03-02 16:24:04 +01:00
|
|
|
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
|
|
|
|
2015-04-03 17:00:55 +02:00
|
|
|
vm->nullClass = AS_CLASS(wrenFindVariable(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
|
|
|
|
2015-04-03 17:00:55 +02:00
|
|
|
vm->numClass = AS_CLASS(wrenFindVariable(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-02-05 21:03:19 +01:00
|
|
|
vm->stringClass = AS_CLASS(wrenFindVariable(vm, "String"));
|
2015-03-27 15:43:36 +01:00
|
|
|
PRIMITIVE(vm->stringClass->obj.classObj, "fromCodePoint(_)", string_fromCodePoint);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->stringClass, "+(_)", string_plus);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "[_]", string_subscript);
|
2015-03-28 04:44:07 +01:00
|
|
|
PRIMITIVE(vm->stringClass, "byteAt(_)", string_byteAt);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "codePointAt(_)", string_codePointAt);
|
2015-03-02 16:24:04 +01:00
|
|
|
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);
|
2015-03-28 04:44:07 +01:00
|
|
|
PRIMITIVE(vm->stringClass, "iterateByte_(_)", string_iterateByte);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->stringClass, "iteratorValue(_)", string_iteratorValue);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "startsWith(_)", string_startsWith);
|
2015-06-30 16:39:43 +02:00
|
|
|
PRIMITIVE(vm->stringClass, "toString", return_this);
|
2013-10-28 06:45:40 +01:00
|
|
|
|
2015-02-05 21:03:19 +01:00
|
|
|
vm->listClass = AS_CLASS(wrenFindVariable(vm, "List"));
|
2015-07-10 18:18:22 +02:00
|
|
|
PRIMITIVE(vm->listClass->obj.classObj, "new()", list_new);
|
2015-03-02 16:24:04 +01:00
|
|
|
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-07-10 18:18:22 +02:00
|
|
|
PRIMITIVE(vm->mapClass->obj.classObj, "new()", map_new);
|
2015-03-02 16:24:04 +01:00
|
|
|
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
|
|
|
}
|