2015-02-25 16:07:54 +01:00
|
|
|
#include <ctype.h>
|
2015-03-03 09:06:34 +01:00
|
|
|
#include <errno.h>
|
2016-07-06 19:08:00 +02:00
|
|
|
#include <float.h>
|
2013-11-10 06:01:18 +01:00
|
|
|
#include <math.h>
|
2013-10-27 19:28:15 +01:00
|
|
|
#include <string.h>
|
2015-09-15 16:46:09 +02:00
|
|
|
#include <time.h>
|
2013-10-27 19:28:15 +01:00
|
|
|
|
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
|
|
|
|
2015-09-13 19:03:02 +02:00
|
|
|
#include "wren_core.wren.inc"
|
2013-12-22 20:50:00 +01:00
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(bool_not)
|
2014-01-02 16:32:00 +01:00
|
|
|
{
|
|
|
|
|
RETURN_BOOL(!AS_BOOL(args[0]));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(bool_toString)
|
2014-01-02 16:32:00 +01:00
|
|
|
{
|
|
|
|
|
if (AS_BOOL(args[0]))
|
|
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(CONST_STRING(vm, "true"));
|
2014-01-02 16:32:00 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-03-16 06:32:20 +01:00
|
|
|
RETURN_VAL(CONST_STRING(vm, "false"));
|
2014-01-02 16:32:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(class_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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateFn(vm, args[1], "Argument")) return false;
|
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
|
|
|
|
2016-03-26 22:00:17 +01:00
|
|
|
ObjFiber* newFiber = wrenNewFiber(vm, AS_CLOSURE(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
|
|
|
|
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.
|
|
|
|
|
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
|
|
|
{
|
2015-09-30 07:57:03 +02:00
|
|
|
vm->fiber->error = args[1];
|
2015-10-04 04:04:11 +02:00
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
// If the error is explicitly null, it's not really an abort.
|
2015-10-04 05:43:12 +02:00
|
|
|
return IS_NULL(args[1]);
|
2015-01-01 19:40:14 +01:00
|
|
|
}
|
|
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
// Transfer execution to [fiber] coming from the current fiber whose stack has
|
|
|
|
|
// [args].
|
|
|
|
|
//
|
|
|
|
|
// [isCall] is true if [fiber] is being called and not transferred.
|
|
|
|
|
//
|
|
|
|
|
// [hasValue] is true if a value in [args] is being passed to the new fiber.
|
|
|
|
|
// Otherwise, `null` is implicitly being passed.
|
2015-10-04 05:43:12 +02:00
|
|
|
static bool runFiber(WrenVM* vm, ObjFiber* fiber, Value* args, bool isCall,
|
2016-03-04 02:00:33 +01:00
|
|
|
bool hasValue, const char* verb)
|
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
|
|
|
{
|
2017-03-31 03:57:29 +02:00
|
|
|
|
|
|
|
|
if (!IS_NULL(fiber->error))
|
|
|
|
|
{
|
|
|
|
|
RETURN_ERROR_FMT("Cannot $ an aborted fiber.", verb);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
if (isCall)
|
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-08-31 07:15:37 +02:00
|
|
|
if (fiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
|
2015-09-13 19:03:02 +02:00
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
// Remember who ran it.
|
|
|
|
|
fiber->caller = vm->fiber;
|
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-09-13 19:03:02 +02:00
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
if (fiber->numFrames == 0)
|
|
|
|
|
{
|
2016-03-04 02:11:52 +01:00
|
|
|
RETURN_ERROR_FMT("Cannot $ a finished fiber.", verb);
|
2015-08-31 07:15:37 +02:00
|
|
|
}
|
2015-09-13 19:03:02 +02:00
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
// When the calling fiber resumes, we'll store the result of the call in its
|
|
|
|
|
// stack. If the call has two arguments (the fiber and the value), we only
|
|
|
|
|
// need one slot for the result, so discard the other slot now.
|
|
|
|
|
if (hasValue) vm->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
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
// If the fiber was paused, make yield() or transfer() return the result.
|
|
|
|
|
if (fiber->stackTop > fiber->stack)
|
|
|
|
|
{
|
2015-09-30 07:57:03 +02:00
|
|
|
fiber->stackTop[-1] = hasValue ? args[1] : NULL_VAL;
|
2015-08-31 07:15:37 +02:00
|
|
|
}
|
2015-09-13 19:03:02 +02:00
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
vm->fiber = fiber;
|
2015-10-04 05:43:12 +02:00
|
|
|
return false;
|
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-08-31 07:15:37 +02: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
|
|
|
{
|
2016-03-04 02:00:33 +01:00
|
|
|
return runFiber(vm, AS_FIBER(args[0]), args, true, false, "call");
|
2015-08-31 07:15:37 +02: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
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
DEF_PRIMITIVE(fiber_call1)
|
|
|
|
|
{
|
2016-03-04 02:00:33 +01:00
|
|
|
return runFiber(vm, AS_FIBER(args[0]), args, true, true, "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
|
|
|
}
|
|
|
|
|
|
2015-03-07 21:32:11 +01:00
|
|
|
DEF_PRIMITIVE(fiber_current)
|
|
|
|
|
{
|
2015-10-04 04:04:11 +02:00
|
|
|
RETURN_OBJ(vm->fiber);
|
2015-03-07 21:32:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:24:04 +01:00
|
|
|
DEF_PRIMITIVE(fiber_error)
|
2014-10-15 15:36:42 +02:00
|
|
|
{
|
2015-09-30 07:57:03 +02:00
|
|
|
RETURN_VAL(AS_FIBER(args[0])->error);
|
2014-10-15 15:36:42 +02:00
|
|
|
}
|
|
|
|
|
|
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]);
|
2015-09-30 07:57:03 +02:00
|
|
|
RETURN_BOOL(runFiber->numFrames == 0 || !IS_NULL(runFiber->error));
|
2014-04-14 16:23:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
DEF_PRIMITIVE(fiber_suspend)
|
2014-04-14 16:23:05 +02:00
|
|
|
{
|
2015-08-31 07:15:37 +02:00
|
|
|
// Switching to a null fiber tells the interpreter to stop and exit.
|
2015-09-30 07:57:03 +02:00
|
|
|
vm->fiber = NULL;
|
2015-12-29 16:58:47 +01:00
|
|
|
vm->apiStack = NULL;
|
2015-10-04 05:43:12 +02:00
|
|
|
return false;
|
2014-04-14 16:23:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
DEF_PRIMITIVE(fiber_transfer)
|
2014-04-14 16:23:05 +02:00
|
|
|
{
|
2016-03-04 02:00:33 +01:00
|
|
|
return runFiber(vm, AS_FIBER(args[0]), args, false, false, "transfer to");
|
2015-08-31 07:15:37 +02:00
|
|
|
}
|
2014-04-14 16:23:05 +02:00
|
|
|
|
2015-08-31 07:15:37 +02:00
|
|
|
DEF_PRIMITIVE(fiber_transfer1)
|
|
|
|
|
{
|
2016-03-04 02:00:33 +01:00
|
|
|
return runFiber(vm, AS_FIBER(args[0]), args, false, true, "transfer to");
|
2014-04-14 16:23:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
DEF_PRIMITIVE(fiber_transferError)
|
2014-10-15 15:36:42 +02:00
|
|
|
{
|
2016-03-04 02:00:33 +01:00
|
|
|
runFiber(vm, AS_FIBER(args[0]), args, false, true, "transfer to");
|
2015-10-04 05:43:12 +02:00
|
|
|
vm->fiber->error = args[1];
|
|
|
|
|
return false;
|
2015-09-30 07:57:03 +02:00
|
|
|
}
|
2014-10-15 15:36:42 +02:00
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
DEF_PRIMITIVE(fiber_try)
|
|
|
|
|
{
|
2016-03-04 02:00:33 +01:00
|
|
|
runFiber(vm, AS_FIBER(args[0]), args, true, false, "try");
|
|
|
|
|
|
|
|
|
|
// If we're switching to a valid fiber to try, remember that we're trying it.
|
|
|
|
|
if (IS_NULL(vm->fiber->error)) vm->fiber->callerIsTrying = true;
|
2015-10-04 05:43:12 +02:00
|
|
|
return false;
|
2014-10-15 15:36:42 +02:00
|
|
|
}
|
|
|
|
|
|
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-10-04 04:04:11 +02:00
|
|
|
ObjFiber* current = vm->fiber;
|
|
|
|
|
vm->fiber = current->caller;
|
|
|
|
|
|
2015-03-07 21:32:11 +01:00
|
|
|
// Unhook this fiber from the one that called it.
|
2015-10-04 04:04:11 +02:00
|
|
|
current->caller = NULL;
|
|
|
|
|
current->callerIsTrying = false;
|
2015-09-13 19:03:02 +02:00
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
if (vm->fiber != NULL)
|
2015-03-07 21:32:11 +01:00
|
|
|
{
|
|
|
|
|
// Make the caller's run method return null.
|
2015-09-30 07:57:03 +02:00
|
|
|
vm->fiber->stackTop[-1] = NULL_VAL;
|
2015-03-07 21:32:11 +01:00
|
|
|
}
|
2015-10-04 04:04:11 +02:00
|
|
|
|
2015-10-04 05:43:12 +02:00
|
|
|
return false;
|
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_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-10-04 04:04:11 +02:00
|
|
|
ObjFiber* current = vm->fiber;
|
|
|
|
|
vm->fiber = current->caller;
|
|
|
|
|
|
2015-03-07 21:32:11 +01:00
|
|
|
// Unhook this fiber from the one that called it.
|
2015-10-04 04:04:11 +02:00
|
|
|
current->caller = NULL;
|
|
|
|
|
current->callerIsTrying = false;
|
2014-04-14 16:23:05 +02:00
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
if (vm->fiber != NULL)
|
2015-03-07 21:32:11 +01:00
|
|
|
{
|
|
|
|
|
// Make the caller's run method return the argument passed to yield.
|
2015-09-30 07:57:03 +02:00
|
|
|
vm->fiber->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-09-30 07:57:03 +02: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.
|
2015-10-04 04:04:11 +02:00
|
|
|
current->stackTop--;
|
2015-03-07 21:32:11 +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
|
|
|
|
2015-10-04 05:43:12 +02:00
|
|
|
return false;
|
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(fn_new)
|
2015-01-24 05:33:05 +01:00
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateFn(vm, args[1], "Argument")) return false;
|
2015-01-24 05:33:05 +01:00
|
|
|
|
|
|
|
|
// 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
|
|
|
{
|
2016-03-26 22:00:17 +01:00
|
|
|
RETURN_NUM(AS_CLOSURE(args[0])->fn->arity);
|
2015-01-24 05:33:05 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2016-08-04 07:42:31 +02:00
|
|
|
// Creates a new list of size args[1], with all elements initialized to args[2].
|
|
|
|
|
DEF_PRIMITIVE(list_filled)
|
2014-04-08 16:31:23 +02:00
|
|
|
{
|
2016-08-04 07:42:31 +02:00
|
|
|
if (!validateInt(vm, args[1], "Size")) return false;
|
|
|
|
|
if (AS_NUM(args[1]) < 0) RETURN_ERROR("Size cannot be negative.");
|
|
|
|
|
|
2016-07-17 04:01:50 +02:00
|
|
|
uint32_t size = (uint32_t)AS_NUM(args[1]);
|
|
|
|
|
ObjList* list = wrenNewList(vm, size);
|
2016-08-04 07:42:31 +02:00
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < size; i++)
|
2016-07-17 04:01:50 +02:00
|
|
|
{
|
2016-08-04 07:42:31 +02:00
|
|
|
list->elements.data[i] = args[2];
|
2016-07-17 04:01:50 +02:00
|
|
|
}
|
2016-08-04 07:42:31 +02:00
|
|
|
|
2016-07-17 04:01:50 +02:00
|
|
|
RETURN_OBJ(list);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-04 07:42:31 +02:00
|
|
|
DEF_PRIMITIVE(list_new)
|
2016-07-17 04:01:50 +02:00
|
|
|
{
|
2016-08-04 07:42:31 +02:00
|
|
|
RETURN_OBJ(wrenNewList(vm, 0));
|
2016-07-17 04:01:50 +02:00
|
|
|
}
|
|
|
|
|
|
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-11-11 16:55:48 +01:00
|
|
|
// Adds an element to the list and then returns the list itself. This is called
|
|
|
|
|
// by the compiler when compiling list literals instead of using add() to
|
|
|
|
|
// minimize stack churn.
|
|
|
|
|
DEF_PRIMITIVE(list_addCore)
|
|
|
|
|
{
|
|
|
|
|
wrenValueBufferWrite(vm, &AS_LIST(args[0])->elements, args[1]);
|
|
|
|
|
|
|
|
|
|
// Return the list.
|
|
|
|
|
RETURN_VAL(args[0]);
|
|
|
|
|
}
|
|
|
|
|
|
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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], list->elements.count + 1,
|
2015-03-22 20:22:47 +01:00
|
|
|
"Index");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
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
|
|
|
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateInt(vm, args[1], "Iterator")) return false;
|
2014-01-02 16:32:00 +01:00
|
|
|
|
|
|
|
|
// 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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], list->elements.count, "Iterator");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], list->elements.count, "Index");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], list->elements.count,
|
2015-03-22 20:22:47 +01:00
|
|
|
"Subscript");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
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-09-30 07:57:03 +02:00
|
|
|
uint32_t start = calculateRange(vm, AS_RANGE(args[1]), &count, &step);
|
2015-10-04 05:43:12 +02:00
|
|
|
if (start == UINT32_MAX) return false;
|
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-09-02 07:14:55 +02: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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], list->elements.count,
|
2015-03-22 20:22:47 +01:00
|
|
|
"Subscript");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
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-10-04 05:43:12 +02:00
|
|
|
if (!validateKey(vm, args[1])) return false;
|
2015-01-25 21:39:19 +01:00
|
|
|
|
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-10-04 05:43:12 +02:00
|
|
|
if (!validateKey(vm, args[1])) return false;
|
2015-01-25 21:39:19 +01:00
|
|
|
|
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-11-11 16:55:48 +01:00
|
|
|
// Adds an entry to the map and then returns the map itself. This is called by
|
|
|
|
|
// the compiler when compiling map literals instead of using [_]=(_) to
|
|
|
|
|
// minimize stack churn.
|
|
|
|
|
DEF_PRIMITIVE(map_addCore)
|
|
|
|
|
{
|
|
|
|
|
if (!validateKey(vm, args[1])) return false;
|
|
|
|
|
|
|
|
|
|
wrenMapSet(vm, AS_MAP(args[0]), args[1], args[2]);
|
|
|
|
|
|
|
|
|
|
// Return the map itself.
|
|
|
|
|
RETURN_VAL(args[0]);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateKey(vm, args[1])) return false;
|
2015-01-25 21:39:19 +01:00
|
|
|
|
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]))
|
|
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateInt(vm, args[1], "Iterator")) return false;
|
2015-01-25 19:27:38 +01:00
|
|
|
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateKey(vm, args[1])) return false;
|
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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], map->capacity, "Iterator");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
2015-01-25 19:27:38 +01:00
|
|
|
|
|
|
|
|
MapEntry* entry = &map->entries[index];
|
|
|
|
|
if (IS_UNDEFINED(entry->key))
|
|
|
|
|
{
|
2016-07-06 16:17:07 +02:00
|
|
|
RETURN_ERROR("Invalid map iterator.");
|
2015-01-25 19:27:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], map->capacity, "Iterator");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
2015-01-25 19:27:38 +01:00
|
|
|
|
|
|
|
|
MapEntry* entry = &map->entries[index];
|
|
|
|
|
if (IS_UNDEFINED(entry->key))
|
|
|
|
|
{
|
2016-07-06 16:17:07 +02:00
|
|
|
RETURN_ERROR("Invalid map iterator.");
|
2015-01-25 19:27:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateString(vm, args[1], "Argument")) return false;
|
2015-02-23 05:06:17 +01:00
|
|
|
|
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
|
|
|
|
2016-03-04 02:11:52 +01:00
|
|
|
if (errno == ERANGE) RETURN_ERROR("Number literal is too large.");
|
2015-03-03 09:06:34 +01:00
|
|
|
|
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) \
|
|
|
|
|
{ \
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateNum(vm, args[1], "Right operand")) 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_##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) \
|
|
|
|
|
{ \
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateNum(vm, args[1], "Right operand")) 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
|
|
|
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, -)
|
2017-09-21 02:27:02 +02:00
|
|
|
DEF_NUM_FN(round, round)
|
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_FN(sin, sin)
|
|
|
|
|
DEF_NUM_FN(sqrt, sqrt)
|
|
|
|
|
DEF_NUM_FN(tan, tan)
|
2016-10-31 20:52:32 +01:00
|
|
|
DEF_NUM_FN(log, log)
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateNum(vm, args[1], "Right operand")) return false;
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateNum(vm, args[1], "Right hand side of range")) return 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
|
|
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateNum(vm, args[1], "Right hand side of range")) return 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
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2016-10-31 20:52:13 +01:00
|
|
|
DEF_PRIMITIVE(num_pow)
|
|
|
|
|
{
|
|
|
|
|
RETURN_NUM(pow(AS_NUM(args[0]), AS_NUM(args[1])));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2015-09-30 17:41:43 +02:00
|
|
|
DEF_PRIMITIVE(num_isInfinity)
|
|
|
|
|
{
|
|
|
|
|
RETURN_BOOL(isinf(AS_NUM(args[0])));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEF_PRIMITIVE(num_isInteger)
|
|
|
|
|
{
|
|
|
|
|
double value = AS_NUM(args[0]);
|
|
|
|
|
if (isnan(value) || isinf(value)) RETURN_FALSE;
|
|
|
|
|
RETURN_BOOL(trunc(value) == value);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2016-08-04 20:15:55 +02:00
|
|
|
DEF_PRIMITIVE(num_largest)
|
2016-07-06 19:08:00 +02:00
|
|
|
{
|
|
|
|
|
RETURN_NUM(DBL_MAX);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-04 20:15:55 +02:00
|
|
|
DEF_PRIMITIVE(num_smallest)
|
2016-07-06 19:08:00 +02:00
|
|
|
{
|
2016-08-28 02:25:32 +02:00
|
|
|
RETURN_NUM(DBL_MIN);
|
2016-07-06 19:08:00 +02: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);
|
|
|
|
|
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateNum(vm, args[1], "Iterator")) 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
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateInt(vm, args[1], "Code point")) return false;
|
2015-03-27 15:43:36 +01:00
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], string->length, "Index");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
2015-03-28 04:44:07 +01:00
|
|
|
|
|
|
|
|
RETURN_NUM((uint8_t)string->value[index]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-11 08:52:18 +02:00
|
|
|
DEF_PRIMITIVE(string_byteCount)
|
|
|
|
|
{
|
|
|
|
|
RETURN_NUM(AS_STRING(args[0])->length);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-28 04:44:07 +01:00
|
|
|
DEF_PRIMITIVE(string_codePointAt)
|
|
|
|
|
{
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
|
2015-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], string->length, "Index");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
2015-03-28 04:44:07 +01:00
|
|
|
|
|
|
|
|
// 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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateString(vm, args[1], "Argument")) return false;
|
2014-01-03 19:47:26 +01:00
|
|
|
|
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
|
|
|
|
2016-07-14 05:53:01 +02:00
|
|
|
RETURN_BOOL(wrenStringFind(string, search, 0) != UINT32_MAX);
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateString(vm, args[1], "Argument")) return false;
|
2015-01-10 23:45:14 +01:00
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
|
|
|
|
|
2016-08-04 07:19:34 +02:00
|
|
|
// Edge case: If the search string is longer then return false right away.
|
2015-01-10 23:45:14 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2016-08-04 07:19:34 +02:00
|
|
|
DEF_PRIMITIVE(string_indexOf1)
|
2015-01-10 23:45:14 +01:00
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateString(vm, args[1], "Argument")) return false;
|
2015-01-10 23:45:14 +01:00
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
|
|
|
|
|
2016-07-14 05:53:01 +02:00
|
|
|
uint32_t index = wrenStringFind(string, search, 0);
|
|
|
|
|
RETURN_NUM(index == UINT32_MAX ? -1 : (int)index);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-04 07:19:34 +02:00
|
|
|
DEF_PRIMITIVE(string_indexOf2)
|
2016-07-14 05:53:01 +02:00
|
|
|
{
|
|
|
|
|
if (!validateString(vm, args[1], "Argument")) return false;
|
|
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
2016-08-04 07:19:34 +02:00
|
|
|
uint32_t start = validateIndex(vm, args[2], string->length, "Start");
|
|
|
|
|
if (start == UINT32_MAX) return false;
|
|
|
|
|
|
|
|
|
|
uint32_t index = wrenStringFind(string, search, start);
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateInt(vm, args[1], "Iterator")) return false;
|
2015-01-23 05:58:22 +01:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateInt(vm, args[1], "Iterator")) return false;
|
2015-03-28 04:44:07 +01:00
|
|
|
|
|
|
|
|
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-09-30 07:57:03 +02:00
|
|
|
uint32_t index = validateIndex(vm, args[1], string->length, "Iterator");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == UINT32_MAX) return false;
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateString(vm, args[1], "Argument")) return false;
|
2015-01-10 23:45:14 +01:00
|
|
|
|
|
|
|
|
ObjString* string = AS_STRING(args[0]);
|
|
|
|
|
ObjString* search = AS_STRING(args[1]);
|
|
|
|
|
|
2016-08-04 07:19:34 +02:00
|
|
|
// Edge case: If the search string is longer then return false right away.
|
2015-01-10 23:45:14 +01:00
|
|
|
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
|
|
|
{
|
2015-10-04 05:43:12 +02:00
|
|
|
if (!validateString(vm, args[1], "Right operand")) return false;
|
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]))
|
|
|
|
|
{
|
2015-09-30 07:57:03 +02:00
|
|
|
int index = validateIndex(vm, args[1], string->length, "Subscript");
|
2015-10-04 05:43:12 +02:00
|
|
|
if (index == -1) return false;
|
2015-01-17 08:20:56 +01:00
|
|
|
|
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-21 00:33:21 +01:00
|
|
|
int step;
|
2015-09-02 07:14:55 +02:00
|
|
|
uint32_t count = string->length;
|
2015-09-30 07:57:03 +02:00
|
|
|
int start = calculateRange(vm, AS_RANGE(args[1]), &count, &step);
|
2015-10-04 05:43:12 +02:00
|
|
|
if (start == -1) return false;
|
2015-01-17 08:20:56 +01:00
|
|
|
|
2015-09-02 07:14:55 +02:00
|
|
|
RETURN_VAL(wrenNewStringFromRange(vm, string, start, count, step));
|
2013-11-24 19:45:07 +01:00
|
|
|
}
|
|
|
|
|
|
2015-09-01 17:16:04 +02:00
|
|
|
DEF_PRIMITIVE(string_toString)
|
|
|
|
|
{
|
|
|
|
|
RETURN_VAL(args[0]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-15 16:46:09 +02:00
|
|
|
DEF_PRIMITIVE(system_clock)
|
|
|
|
|
{
|
|
|
|
|
RETURN_NUM((double)clock() / CLOCKS_PER_SEC);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-24 19:56:27 +02:00
|
|
|
DEF_PRIMITIVE(system_gc)
|
|
|
|
|
{
|
|
|
|
|
wrenCollectGarbage(vm);
|
|
|
|
|
RETURN_NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 07:43:54 +01:00
|
|
|
DEF_PRIMITIVE(system_getModuleVariable)
|
|
|
|
|
{
|
|
|
|
|
if (!validateString(vm, args[1], "Module")) return false;
|
|
|
|
|
if (!validateString(vm, args[2], "Variable")) return false;
|
|
|
|
|
|
|
|
|
|
Value result = wrenGetModuleVariable(vm, args[1], args[2]);
|
|
|
|
|
if (!IS_NULL(vm->fiber->error)) return false;
|
|
|
|
|
|
|
|
|
|
RETURN_VAL(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEF_PRIMITIVE(system_importModule)
|
|
|
|
|
{
|
2016-03-17 15:49:43 +01:00
|
|
|
if (!validateString(vm, args[1], "Module")) return false;
|
2016-02-27 07:43:54 +01:00
|
|
|
Value result = wrenImportModule(vm, args[1]);
|
|
|
|
|
if (!IS_NULL(vm->fiber->error)) return false;
|
|
|
|
|
|
|
|
|
|
// If we get null, the module is already loaded and there is no work to do.
|
|
|
|
|
if (IS_NULL(result)) RETURN_NULL;
|
|
|
|
|
|
|
|
|
|
// Otherwise, we should get a fiber that executes the module.
|
|
|
|
|
ASSERT(IS_FIBER(result), "Should get a fiber to execute.");
|
|
|
|
|
|
|
|
|
|
// We have two slots on the stack for this call, but we only need one for the
|
|
|
|
|
// return value of the fiber we're calling. Discard the other.
|
|
|
|
|
vm->fiber->stackTop--;
|
|
|
|
|
|
|
|
|
|
// Return to this module when that one is done.
|
|
|
|
|
AS_FIBER(result)->caller = vm->fiber;
|
|
|
|
|
vm->fiber = AS_FIBER(result);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-15 16:46:09 +02:00
|
|
|
DEF_PRIMITIVE(system_writeString)
|
|
|
|
|
{
|
2015-09-16 08:01:43 +02:00
|
|
|
if (vm->config.writeFn != NULL)
|
|
|
|
|
{
|
|
|
|
|
vm->config.writeFn(vm, AS_CSTRING(args[1]));
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-15 16:46:09 +02:00
|
|
|
RETURN_VAL(args[1]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-16 04:38:25 +02:00
|
|
|
// Creates either the Object or Class class in the core module with [name].
|
2015-08-06 16:13:11 +02:00
|
|
|
static ObjClass* defineClass(WrenVM* vm, ObjModule* module, 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-08-06 16:13:11 +02:00
|
|
|
wrenDefineVariable(vm, module, 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
|
|
|
|
2015-10-04 04:04:11 +02:00
|
|
|
// Defines one of the overloads of the special "call(...)" method on Fn.
|
|
|
|
|
//
|
|
|
|
|
// These methods have their own unique method type to handle pushing the
|
|
|
|
|
// function onto the callstack and checking its arity.
|
|
|
|
|
static void fnCall(WrenVM* vm, const char* signature)
|
|
|
|
|
{
|
|
|
|
|
int symbol = wrenSymbolTableEnsure(vm, &vm->methodNames, signature,
|
|
|
|
|
strlen(signature));
|
|
|
|
|
Method method;
|
|
|
|
|
method.type = METHOD_FN_CALL;
|
|
|
|
|
wrenBindMethod(vm, vm->fnClass, symbol, method);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 17:00:55 +01:00
|
|
|
void wrenInitializeCore(WrenVM* vm)
|
2013-10-27 19:28:15 +01:00
|
|
|
{
|
2015-10-16 03:17:42 +02:00
|
|
|
ObjModule* coreModule = wrenNewModule(vm, NULL);
|
2015-10-16 03:08:56 +02:00
|
|
|
wrenPushRoot(vm, (Obj*)coreModule);
|
|
|
|
|
|
|
|
|
|
// The core module's key is null in the module map.
|
|
|
|
|
wrenMapSet(vm, vm->modules, NULL_VAL, OBJ_VAL(coreModule));
|
|
|
|
|
wrenPopRoot(vm); // coreModule.
|
2015-09-13 19:03:02 +02: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-08-06 16:13:11 +02:00
|
|
|
vm->objectClass = defineClass(vm, coreModule, "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-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-08-06 16:13:11 +02:00
|
|
|
vm->classClass = defineClass(vm, coreModule, "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.
|
2015-08-06 16:13:11 +02:00
|
|
|
ObjClass* objectMetaclass = defineClass(vm, coreModule, "Object metaclass");
|
2015-05-01 16:55:28 +02:00
|
|
|
|
|
|
|
|
// 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-10-16 03:17:42 +02:00
|
|
|
wrenInterpretInModule(vm, NULL, coreModuleSource);
|
2015-04-03 17:00:55 +02:00
|
|
|
|
2015-08-06 16:13:11 +02:00
|
|
|
vm->boolClass = AS_CLASS(wrenFindVariable(vm, coreModule, "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-08-06 16:13:11 +02:00
|
|
|
vm->fiberClass = AS_CLASS(wrenFindVariable(vm, coreModule, "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-08-31 07:15:37 +02:00
|
|
|
PRIMITIVE(vm->fiberClass->obj.classObj, "suspend()", fiber_suspend);
|
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);
|
2015-08-31 07:15:37 +02:00
|
|
|
PRIMITIVE(vm->fiberClass, "transfer()", fiber_transfer);
|
|
|
|
|
PRIMITIVE(vm->fiberClass, "transfer(_)", fiber_transfer1);
|
2015-09-30 07:57:03 +02:00
|
|
|
PRIMITIVE(vm->fiberClass, "transferError(_)", fiber_transferError);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->fiberClass, "try()", fiber_try);
|
2014-01-04 20:08:31 +01:00
|
|
|
|
2015-08-06 16:13:11 +02:00
|
|
|
vm->fnClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Fn"));
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->fnClass->obj.classObj, "new(_)", fn_new);
|
|
|
|
|
|
|
|
|
|
PRIMITIVE(vm->fnClass, "arity", fn_arity);
|
2015-10-04 04:04:11 +02:00
|
|
|
fnCall(vm, "call()");
|
|
|
|
|
fnCall(vm, "call(_)");
|
|
|
|
|
fnCall(vm, "call(_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)");
|
|
|
|
|
fnCall(vm, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)");
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->fnClass, "toString", fn_toString);
|
2013-11-06 15:52:28 +01:00
|
|
|
|
2015-08-06 16:13:11 +02:00
|
|
|
vm->nullClass = AS_CLASS(wrenFindVariable(vm, coreModule, "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-08-06 16:13:11 +02:00
|
|
|
vm->numClass = AS_CLASS(wrenFindVariable(vm, coreModule, "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);
|
2016-08-04 20:15:55 +02:00
|
|
|
PRIMITIVE(vm->numClass->obj.classObj, "largest", num_largest);
|
|
|
|
|
PRIMITIVE(vm->numClass->obj.classObj, "smallest", num_smallest);
|
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);
|
2017-09-21 02:27:02 +02:00
|
|
|
PRIMITIVE(vm->numClass, "round", num_round);
|
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);
|
2016-10-31 20:52:32 +01:00
|
|
|
PRIMITIVE(vm->numClass, "log", num_log);
|
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);
|
2016-10-31 20:52:13 +01:00
|
|
|
PRIMITIVE(vm->numClass, "pow(_)", num_pow);
|
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, "fraction", num_fraction);
|
2015-09-30 17:41:43 +02:00
|
|
|
PRIMITIVE(vm->numClass, "isInfinity", num_isInfinity);
|
|
|
|
|
PRIMITIVE(vm->numClass, "isInteger", num_isInteger);
|
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, "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-08-06 16:13:11 +02:00
|
|
|
vm->stringClass = AS_CLASS(wrenFindVariable(vm, coreModule, "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-09-11 08:52:18 +02:00
|
|
|
PRIMITIVE(vm->stringClass, "byteAt_(_)", string_byteAt);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "byteCount_", string_byteCount);
|
2015-09-11 16:56:01 +02:00
|
|
|
PRIMITIVE(vm->stringClass, "codePointAt_(_)", string_codePointAt);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->stringClass, "contains(_)", string_contains);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "endsWith(_)", string_endsWith);
|
2016-08-04 07:19:34 +02:00
|
|
|
PRIMITIVE(vm->stringClass, "indexOf(_)", string_indexOf1);
|
|
|
|
|
PRIMITIVE(vm->stringClass, "indexOf(_,_)", string_indexOf2);
|
2015-03-02 16:24:04 +01:00
|
|
|
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-09-01 17:16:04 +02:00
|
|
|
PRIMITIVE(vm->stringClass, "toString", string_toString);
|
2013-10-28 06:45:40 +01:00
|
|
|
|
2015-08-06 16:13:11 +02:00
|
|
|
vm->listClass = AS_CLASS(wrenFindVariable(vm, coreModule, "List"));
|
2016-08-04 07:42:31 +02:00
|
|
|
PRIMITIVE(vm->listClass->obj.classObj, "filled(_,_)", list_filled);
|
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);
|
2015-11-11 16:55:48 +01:00
|
|
|
PRIMITIVE(vm->listClass, "addCore_(_)", list_addCore);
|
2015-03-02 16:24:04 +01:00
|
|
|
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-08-06 16:13:11 +02:00
|
|
|
vm->mapClass = AS_CLASS(wrenFindVariable(vm, coreModule, "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);
|
2015-11-11 16:55:48 +01:00
|
|
|
PRIMITIVE(vm->mapClass, "addCore_(_,_)", map_addCore);
|
2015-03-02 16:24:04 +01:00
|
|
|
PRIMITIVE(vm->mapClass, "clear()", map_clear);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "containsKey(_)", map_containsKey);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "count", map_count);
|
|
|
|
|
PRIMITIVE(vm->mapClass, "remove(_)", map_remove);
|
2016-07-06 16:17:07 +02:00
|
|
|
PRIMITIVE(vm->mapClass, "iterate(_)", map_iterate);
|
2015-03-02 16:24:04 +01:00
|
|
|
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-08-06 16:13:11 +02:00
|
|
|
vm->rangeClass = AS_CLASS(wrenFindVariable(vm, coreModule, "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
|
|
|
|
2015-09-15 16:46:09 +02:00
|
|
|
ObjClass* systemClass = AS_CLASS(wrenFindVariable(vm, coreModule, "System"));
|
|
|
|
|
PRIMITIVE(systemClass->obj.classObj, "clock", system_clock);
|
2015-10-24 19:56:27 +02:00
|
|
|
PRIMITIVE(systemClass->obj.classObj, "gc()", system_gc);
|
2016-02-27 07:43:54 +01:00
|
|
|
// TODO: Do we want to give these magic names that can't be called from
|
|
|
|
|
// regular code?
|
|
|
|
|
PRIMITIVE(systemClass->obj.classObj, "getModuleVariable(_,_)", system_getModuleVariable);
|
|
|
|
|
PRIMITIVE(systemClass->obj.classObj, "importModule(_)", system_importModule);
|
2015-09-15 16:46:09 +02:00
|
|
|
PRIMITIVE(systemClass->obj.classObj, "writeString_(_)", system_writeString);
|
2015-10-04 04:04:11 +02:00
|
|
|
|
2015-10-16 04:38:25 +02:00
|
|
|
// While bootstrapping the core types and running the core module, 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
|
|
|
}
|