"Auxiliary" -> "optional".

Fixes #309.
This commit is contained in:
Bob Nystrom
2015-10-24 09:23:25 -07:00
parent 545a4cbf7e
commit f145662158
14 changed files with 152 additions and 152 deletions
+55
View File
@@ -0,0 +1,55 @@
#include "wren_opt_meta.h"
#if WREN_OPT_META
#include <string.h>
#include "wren_vm.h"
#include "wren_opt_meta.wren.inc"
void metaCompile(WrenVM* vm)
{
// Evaluate the code in the module where the calling function was defined.
// That's one stack frame back from the top since the top-most frame is the
// helper eval() method in Meta itself.
Value callingFn = OBJ_VAL(vm->fiber->frames[vm->fiber->numFrames - 2].fn);
ObjModule* module = IS_FN(callingFn)
? AS_FN(callingFn)->module
: AS_CLOSURE(callingFn)->fn->module;
// Compile it.
ObjFn* fn = wrenCompile(vm, module, wrenGetArgumentString(vm, 1), false);
if (fn == NULL) return;
// Return the result. We can't use the public API for this since we have a
// bare ObjFn.
*vm->foreignCallSlot = OBJ_VAL(fn);
vm->foreignCallSlot = NULL;
}
static WrenForeignMethodFn bindMetaForeignMethods(WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature)
{
// There is only one foreign method in the meta module.
ASSERT(strcmp(module, "meta") == 0, "Should be in meta module.");
ASSERT(strcmp(className, "Meta") == 0, "Should be in Meta class.");
ASSERT(isStatic, "Should be static.");
ASSERT(strcmp(signature, "compile_(_)") == 0, "Should be compile method.");
return metaCompile;
}
void wrenLoadMetaModule(WrenVM* vm)
{
WrenBindForeignMethodFn previousBindFn = vm->config.bindForeignMethodFn;
vm->config.bindForeignMethodFn = bindMetaForeignMethods;
wrenInterpretInModule(vm, "meta", metaModuleSource);
vm->config.bindForeignMethodFn = previousBindFn;
}
#endif
+14
View File
@@ -0,0 +1,14 @@
#ifndef wren_opt_meta_h
#define wren_opt_meta_h
#include "wren_common.h"
#include "wren.h"
// This module defines the Meta class and its associated methods.
#if WREN_OPT_META
void wrenLoadMetaModule(WrenVM* vm);
#endif
#endif
+13
View File
@@ -0,0 +1,13 @@
class Meta {
static eval(source) {
if (!(source is String)) Fiber.abort("Source code must be a string.")
var fn = compile_(source)
// TODO: Include compile errors.
if (fn == null) Fiber.abort("Could not compile source code.")
Fiber.new(fn).call()
}
foreign static compile_(source)
}
+15
View File
@@ -0,0 +1,15 @@
// Generated automatically from src/optional/wren_opt_meta.wren. Do not edit.
static const char* metaModuleSource =
"class Meta {\n"
" static eval(source) {\n"
" if (!(source is String)) Fiber.abort(\"Source code must be a string.\")\n"
"\n"
" var fn = compile_(source)\n"
" // TODO: Include compile errors.\n"
" if (fn == null) Fiber.abort(\"Could not compile source code.\")\n"
"\n"
" Fiber.new(fn).call()\n"
" }\n"
"\n"
" foreign static compile_(source)\n"
"}\n";
+156
View File
@@ -0,0 +1,156 @@
#include "wren_opt_random.h"
#if WREN_OPT_RANDOM
#include <string.h>
#include <time.h>
#include "wren.h"
#include "wren_vm.h"
#include "wren_opt_random.wren.inc"
// Implements the well equidistributed long-period linear PRNG (WELL512a).
//
// https://en.wikipedia.org/wiki/Well_equidistributed_long-period_linear
typedef struct
{
uint32_t state[16];
uint32_t index;
} Well512;
// Code from: http://www.lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
static uint32_t advanceState(Well512* well)
{
uint32_t a, b, c, d;
a = well->state[well->index];
c = well->state[(well->index + 13) & 15];
b = a ^ c ^ (a << 16) ^ (c << 15);
c = well->state[(well->index + 9) & 15];
c ^= (c >> 11);
a = well->state[well->index] = b ^ c;
d = a ^ ((a << 5) & 0xda442d24U);
well->index = (well->index + 15) & 15;
a = well->state[well->index];
well->state[well->index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
return well->state[well->index];
}
static void randomAllocate(WrenVM* vm)
{
Well512* well = (Well512*)wrenAllocateForeign(vm, sizeof(Well512));
well->index = 0;
}
static void randomSeed0(WrenVM* vm)
{
Well512* well = (Well512*)wrenGetArgumentForeign(vm, 0);
srand((uint32_t)time(NULL));
for (int i = 0; i < 16; i++)
{
well->state[i] = rand();
}
}
static void randomSeed1(WrenVM* vm)
{
Well512* well = (Well512*)wrenGetArgumentForeign(vm, 0);
srand((uint32_t)wrenGetArgumentDouble(vm, 1));
for (int i = 0; i < 16; i++)
{
well->state[i] = rand();
}
}
static void randomSeed16(WrenVM* vm)
{
Well512* well = (Well512*)wrenGetArgumentForeign(vm, 0);
for (int i = 0; i < 16; i++)
{
well->state[i] = (uint32_t)wrenGetArgumentDouble(vm, i + 1);
}
}
static void randomFloat(WrenVM* vm)
{
Well512* well = (Well512*)wrenGetArgumentForeign(vm, 0);
// A double has 53 bits of precision in its mantissa, and we'd like to take
// full advantage of that, so we need 53 bits of random source data.
// First, start with 32 random bits, shifted to the left 21 bits.
double result = (double)advanceState(well) * (1 << 21);
// Then add another 21 random bits.
result += (double)(advanceState(well) & ((1 << 21) - 1));
// Now we have a number from 0 - (2^53). Divide be the range to get a double
// from 0 to 1.0 (half-inclusive).
result /= 9007199254740992.0;
wrenReturnDouble(vm, result);
}
static void randomInt0(WrenVM* vm)
{
Well512* well = (Well512*)wrenGetArgumentForeign(vm, 0);
wrenReturnDouble(vm, (double)advanceState(well));
}
// TODO: The way these are wired up is pretty verbose and tedious. Also, the
// CLI has its own separate way of handling this. Figure out something cleaner.
static WrenForeignMethodFn bindForeignMethods(WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature)
{
ASSERT(strcmp(module, "random") == 0, "Should be in random module.");
ASSERT(strcmp(className, "Random") == 0, "Should be in Random class.");
if (strcmp(signature, "<allocate>") == 0) return randomAllocate;
if (strcmp(signature, "seed_()") == 0) return randomSeed0;
if (strcmp(signature, "seed_(_)") == 0) return randomSeed1;
if (strcmp(signature, "seed_(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)") == 0)
{
return randomSeed16;
}
if (strcmp(signature, "float()") == 0) return randomFloat;
if (strcmp(signature, "int()") == 0) return randomInt0;
ASSERT(false, "Unknown method.");
return NULL;
}
static WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module,
const char* className)
{
WrenForeignClassMethods methods;
methods.allocate = randomAllocate;
methods.finalize = NULL;
return methods;
}
// TODO: Lots of duplication between here and meta.
void wrenLoadRandomModule(WrenVM* vm)
{
WrenBindForeignMethodFn previousBindMethodFn = vm->config.bindForeignMethodFn;
vm->config.bindForeignMethodFn = bindForeignMethods;
WrenBindForeignClassFn previousBindClassFn = vm->config.bindForeignClassFn;
vm->config.bindForeignClassFn = bindForeignClass;
wrenInterpretInModule(vm, "random", randomModuleSource);
vm->config.bindForeignMethodFn = previousBindMethodFn;
vm->config.bindForeignClassFn = previousBindClassFn;
}
#endif
+13
View File
@@ -0,0 +1,13 @@
#ifndef wren_opt_random_h
#define wren_opt_random_h
#include "wren_common.h"
#include "wren.h"
#if WREN_OPT_RANDOM
void wrenLoadRandomModule(WrenVM* vm);
#endif
#endif
+49
View File
@@ -0,0 +1,49 @@
foreign class Random {
construct new() {
seed_()
}
construct new(seed) {
if (seed is Num) {
seed_(seed)
} else if (seed is Sequence) {
if (seed.isEmpty) Fiber.abort("Sequence cannot be empty.")
// TODO: Empty sequence.
var seeds = []
for (element in seed) {
if (!(element is Num)) Fiber.abort("Sequence elements must all be numbers.")
seeds.add(element)
if (seeds.count == 16) break
}
// Cycle the values to fill in any missing slots.
var i = 0
while (seeds.count < 16) {
seeds.add(seeds[i])
i = i + 1
}
seed_(
seeds[0], seeds[1], seeds[2], seeds[3],
seeds[4], seeds[5], seeds[6], seeds[7],
seeds[8], seeds[9], seeds[10], seeds[11],
seeds[12], seeds[13], seeds[14], seeds[15])
} else {
Fiber.abort("Seed must be a number or a sequence of numbers.")
}
}
foreign seed_()
foreign seed_(seed)
foreign seed_(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16)
foreign float()
float(max) { float() * max }
float(min, max) { float() * (max - min) + min }
foreign int()
int(max) { (float() * max).floor }
int(min, max) { (float() * (max - min)).floor + min }
}
+51
View File
@@ -0,0 +1,51 @@
// Generated automatically from src/optional/wren_opt_random.wren. Do not edit.
static const char* randomModuleSource =
"foreign class Random {\n"
" construct new() {\n"
" seed_()\n"
" }\n"
"\n"
" construct new(seed) {\n"
" if (seed is Num) {\n"
" seed_(seed)\n"
" } else if (seed is Sequence) {\n"
" if (seed.isEmpty) Fiber.abort(\"Sequence cannot be empty.\")\n"
"\n"
" // TODO: Empty sequence.\n"
" var seeds = []\n"
" for (element in seed) {\n"
" if (!(element is Num)) Fiber.abort(\"Sequence elements must all be numbers.\")\n"
"\n"
" seeds.add(element)\n"
" if (seeds.count == 16) break\n"
" }\n"
"\n"
" // Cycle the values to fill in any missing slots.\n"
" var i = 0\n"
" while (seeds.count < 16) {\n"
" seeds.add(seeds[i])\n"
" i = i + 1\n"
" }\n"
"\n"
" seed_(\n"
" seeds[0], seeds[1], seeds[2], seeds[3],\n"
" seeds[4], seeds[5], seeds[6], seeds[7],\n"
" seeds[8], seeds[9], seeds[10], seeds[11],\n"
" seeds[12], seeds[13], seeds[14], seeds[15])\n"
" } else {\n"
" Fiber.abort(\"Seed must be a number or a sequence of numbers.\")\n"
" }\n"
" }\n"
"\n"
" foreign seed_()\n"
" foreign seed_(seed)\n"
" foreign seed_(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16)\n"
"\n"
" foreign float()\n"
" float(max) { float() * max }\n"
" float(min, max) { float() * (max - min) + min }\n"
"\n"
" foreign int()\n"
" int(max) { (float() * max).floor }\n"
" int(min, max) { (float() * (max - min)).floor + min }\n"
"}\n";