mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 22:28:45 +01:00
Automatically update the string constants when a builtin module changes.
This commit is contained in:
5
Makefile
5
Makefile
@ -46,11 +46,6 @@ test: debug
|
||||
@ $(MAKE) -f script/wren.mk MODE=debug test
|
||||
@ ./script/test.py $(suite)
|
||||
|
||||
# Take the contents of the scripts under builtin/ and copy them into their
|
||||
# respective wren_<name>.c source files.
|
||||
builtin:
|
||||
@ ./script/generate_builtins.py
|
||||
|
||||
# Generate the Wren site.
|
||||
docs:
|
||||
@ ./script/generate_docs.py
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
The Wren scripts in this directory get converted to C string literals and then
|
||||
inserted into their respective .c files so that the interpreter can load them
|
||||
directly without having to do any file IO.
|
||||
The Wren scripts in this directory get converted to C string literals into files
|
||||
with a `.wren.inc` extension. Those are then `#includ`ed into their respective
|
||||
`.c` files so that the interpreter can load them directly without having to do
|
||||
any file IO.
|
||||
|
||||
The script that does this copying is `script/generate_builtins.py`.
|
||||
The script that does this translation is `script/wren_to_c_string.py`.
|
||||
|
||||
You can invoke using `make builtin`.
|
||||
When any of the ".wren" files in here are changed, the Makefile automatically
|
||||
updates the generated C headers.
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
import glob
|
||||
import os.path
|
||||
import re
|
||||
|
||||
PATTERN = re.compile(r'LibSource =\n("(.|[\n])*?);')
|
||||
|
||||
def copy_builtin(filename, out_prefix):
|
||||
name = os.path.basename(filename)
|
||||
name = name.split('.')[0]
|
||||
|
||||
with open(filename, "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
wren_source = ""
|
||||
for line in lines:
|
||||
line = line.replace('"', "\\\"")
|
||||
line = line.replace("\n", "\\n\"")
|
||||
if wren_source: wren_source += "\n"
|
||||
wren_source += '"' + line
|
||||
|
||||
# re.sub() will unescape escape sequences, but we want them to stay escapes
|
||||
# in the C string literal.
|
||||
wren_source = wren_source.replace('\\', '\\\\')
|
||||
|
||||
constant = "LibSource =\n" + wren_source + ";"
|
||||
|
||||
with open(out_prefix + name + ".c", "r") as f:
|
||||
c_source = f.read()
|
||||
|
||||
c_source = PATTERN.sub(constant, c_source)
|
||||
|
||||
with open(out_prefix + name + ".c", "w") as f:
|
||||
f.write(c_source)
|
||||
|
||||
print(filename.ljust(25) + " → " + out_prefix + name + ".c")
|
||||
|
||||
|
||||
for f in glob.iglob("builtin/*.wren"):
|
||||
copy_builtin(f, "src/vm/wren_")
|
||||
|
||||
for f in glob.iglob("src/module/*.wren"):
|
||||
copy_builtin(f, "src/module/")
|
||||
@ -22,10 +22,10 @@
|
||||
CLI_HEADERS := $(wildcard src/cli/*.h)
|
||||
CLI_SOURCES := $(wildcard src/cli/*.c)
|
||||
|
||||
MODULE_HEADERS := $(wildcard src/module/*.h)
|
||||
MODULE_HEADERS := $(wildcard src/module/*.h) $(wildcard src/module/*.wren.inc)
|
||||
MODULE_SOURCES := $(wildcard src/module/*.c)
|
||||
|
||||
VM_HEADERS := $(wildcard src/vm/*.h)
|
||||
VM_HEADERS := $(wildcard src/vm/*.h) $(wildcard src/vm/*.wren.inc)
|
||||
VM_SOURCES := $(wildcard src/vm/*.c)
|
||||
|
||||
TEST_HEADERS := $(wildcard test/api/*.h)
|
||||
@ -192,4 +192,11 @@ $(LIBUV_DIR)/build/gyp/gyp: script/libuv.py
|
||||
$(LIBUV): $(LIBUV_DIR)/build/gyp/gyp script/libuv.py
|
||||
@ ./script/libuv.py build $(LIBUV_ARCH)
|
||||
|
||||
# Wren modules that get compiled into the binary as C strings.
|
||||
src/vm/wren_%.wren.inc: builtin/%.wren script/wren_to_c_string.py
|
||||
@ ./script/wren_to_c_string.py $@ $<
|
||||
|
||||
src/module/%.wren.inc: src/module/%.wren script/wren_to_c_string.py
|
||||
@ ./script/wren_to_c_string.py $@ $<
|
||||
|
||||
.PHONY: all cli test vm
|
||||
|
||||
53
script/wren_to_c_string.py
Executable file
53
script/wren_to_c_string.py
Executable file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import os.path
|
||||
import re
|
||||
|
||||
# The source for the Wren modules that are built into the VM or CLI are turned
|
||||
# include C string literals. This way they can be compiled directly into the
|
||||
# code so that file IO is not needed to find and read them.
|
||||
#
|
||||
# These string literals are stored in files with a ".wren.inc" extension and
|
||||
# #included directly by other source files. This generates a ".wren.inc" file
|
||||
# given a ".wren" module.
|
||||
|
||||
PREAMBLE = """// Generated automatically from {0}. Do not edit.
|
||||
static const char* {1}ModuleSource =
|
||||
{2};
|
||||
"""
|
||||
|
||||
def wren_to_c_string(input_path, wren_source_lines, module):
|
||||
wren_source = ""
|
||||
for line in wren_source_lines:
|
||||
line = line.replace('"', "\\\"")
|
||||
line = line.replace("\n", "\\n\"")
|
||||
if wren_source: wren_source += "\n"
|
||||
wren_source += '"' + line
|
||||
|
||||
return PREAMBLE.format(input_path, module, wren_source)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Convert a Wren library to a C string literal.")
|
||||
parser.add_argument("output", help="The output file to write")
|
||||
parser.add_argument("input", help="The source .wren file")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.input, "r") as f:
|
||||
wren_source_lines = f.readlines()
|
||||
|
||||
module = os.path.splitext(os.path.basename(args.input))[0]
|
||||
c_source = wren_to_c_string(args.input, wren_source_lines, module)
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
f.write(c_source)
|
||||
|
||||
print(" str " + args.input)
|
||||
|
||||
|
||||
main()
|
||||
@ -7,43 +7,7 @@
|
||||
#include "wren.h"
|
||||
#include "vm.h"
|
||||
|
||||
// This is generated from builtin/module/timer.wren. Do not edit here.
|
||||
static const char* timerLibSource =
|
||||
"class Timer {\n"
|
||||
" static sleep(milliseconds) {\n"
|
||||
" if (!(milliseconds is Num)) Fiber.abort(\"Milliseconds must be a number.\")\n"
|
||||
" if (milliseconds < 0) Fiber.abort(\"Milliseconds cannot be negative.\")\n"
|
||||
" startTimer_(milliseconds, Fiber.current)\n"
|
||||
"\n"
|
||||
" runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" // TODO: Once the CLI modules are more fleshed out, find a better place to\n"
|
||||
" // put this.\n"
|
||||
" static schedule(callable) {\n"
|
||||
" if (__scheduled == null) __scheduled = []\n"
|
||||
" __scheduled.add(Fiber.new {\n"
|
||||
" callable.call()\n"
|
||||
" runNextScheduled_()\n"
|
||||
" })\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static startTimer_(milliseconds, fiber)\n"
|
||||
"\n"
|
||||
" // Called by native code.\n"
|
||||
" static resumeTimer_(fiber) {\n"
|
||||
" fiber.transfer()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static runNextScheduled_() {\n"
|
||||
" if (__scheduled == null || __scheduled.isEmpty) {\n"
|
||||
" Fiber.suspend()\n"
|
||||
" } else {\n"
|
||||
" __scheduled.removeAt(0).transfer()\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
#include "timer.wren.inc"
|
||||
|
||||
// The Wren method to call when a timer has completed.
|
||||
static WrenValue* resumeTimer;
|
||||
@ -58,7 +22,7 @@ static void timerCloseCallback(uv_handle_t* handle)
|
||||
static void timerCallback(uv_timer_t* handle)
|
||||
{
|
||||
WrenValue* fiber = (WrenValue*)handle->data;
|
||||
|
||||
|
||||
// Tell libuv that we don't need the timer anymore.
|
||||
uv_close((uv_handle_t*)handle, timerCloseCallback);
|
||||
|
||||
@ -74,24 +38,24 @@ static void startTimer(WrenVM* vm)
|
||||
{
|
||||
resumeTimer = wrenGetMethod(vm, "timer", "Timer", "resumeTimer_(_)");
|
||||
}
|
||||
|
||||
|
||||
int milliseconds = (int)wrenGetArgumentDouble(vm, 1);
|
||||
WrenValue* fiber = wrenGetArgumentValue(vm, 2);
|
||||
|
||||
|
||||
// Store the fiber to resume when the timer completes.
|
||||
uv_timer_t* handle = (uv_timer_t*)malloc(sizeof(uv_timer_t));
|
||||
handle->data = fiber;
|
||||
|
||||
|
||||
uv_timer_init(getLoop(), handle);
|
||||
uv_timer_start(handle, timerCallback, milliseconds, 0);
|
||||
}
|
||||
|
||||
char* timerGetSource()
|
||||
{
|
||||
size_t length = strlen(timerLibSource);
|
||||
size_t length = strlen(timerModuleSource);
|
||||
char* copy = (char*)malloc(length + 1);
|
||||
strncpy(copy, timerLibSource, length + 1);
|
||||
|
||||
strncpy(copy, timerModuleSource, length + 1);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ -101,7 +65,7 @@ WrenForeignMethodFn timerBindForeign(
|
||||
if (strcmp(className, "Timer") != 0) return NULL;
|
||||
|
||||
if (isStatic && strcmp(signature, "startTimer_(_,_)") == 0) return startTimer;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -32,4 +32,3 @@ class Timer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
36
src/module/timer.wren.inc
Normal file
36
src/module/timer.wren.inc
Normal file
@ -0,0 +1,36 @@
|
||||
// Generated automatically from src/module/timer.wren. Do not edit.
|
||||
static const char* timerModuleSource =
|
||||
"class Timer {\n"
|
||||
" static sleep(milliseconds) {\n"
|
||||
" if (!(milliseconds is Num)) Fiber.abort(\"Milliseconds must be a number.\")\n"
|
||||
" if (milliseconds < 0) Fiber.abort(\"Milliseconds cannot be negative.\")\n"
|
||||
" startTimer_(milliseconds, Fiber.current)\n"
|
||||
"\n"
|
||||
" runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" // TODO: Once the CLI modules are more fleshed out, find a better place to\n"
|
||||
" // put this.\n"
|
||||
" static schedule(callable) {\n"
|
||||
" if (__scheduled == null) __scheduled = []\n"
|
||||
" __scheduled.add(Fiber.new {\n"
|
||||
" callable.call()\n"
|
||||
" runNextScheduled_()\n"
|
||||
" })\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static startTimer_(milliseconds, fiber)\n"
|
||||
"\n"
|
||||
" // Called by native code.\n"
|
||||
" static resumeTimer_(fiber) {\n"
|
||||
" fiber.transfer()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static runNextScheduled_() {\n"
|
||||
" if (__scheduled == null || __scheduled.isEmpty) {\n"
|
||||
" Fiber.suspend()\n"
|
||||
" } else {\n"
|
||||
" __scheduled.removeAt(0).transfer()\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
@ -10,223 +10,7 @@
|
||||
#include "wren_primitive.h"
|
||||
#include "wren_value.h"
|
||||
|
||||
// This string literal is generated automatically from core. Do not edit.
|
||||
static const char* coreLibSource =
|
||||
"class Bool {}\n"
|
||||
"class Fiber {}\n"
|
||||
"class Fn {}\n"
|
||||
"class Null {}\n"
|
||||
"class Num {}\n"
|
||||
"\n"
|
||||
"class Sequence {\n"
|
||||
" all(f) {\n"
|
||||
" var result = true\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" if (!result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" any(f) {\n"
|
||||
" var result = false\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" if (result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" contains(element) {\n"
|
||||
" for (item in this) {\n"
|
||||
" if (element == item) return true\n"
|
||||
" }\n"
|
||||
" return false\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" count {\n"
|
||||
" var result = 0\n"
|
||||
" for (element in this) {\n"
|
||||
" result = result + 1\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" count(f) {\n"
|
||||
" var result = 0\n"
|
||||
" for (element in this) {\n"
|
||||
" if (f.call(element)) result = result + 1\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" each(f) {\n"
|
||||
" for (element in this) {\n"
|
||||
" f.call(element)\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isEmpty { iterate(null) ? false : true }\n"
|
||||
"\n"
|
||||
" map(transformation) { MapSequence.new(this, transformation) }\n"
|
||||
"\n"
|
||||
" where(predicate) { WhereSequence.new(this, predicate) }\n"
|
||||
"\n"
|
||||
" reduce(acc, f) {\n"
|
||||
" for (element in this) {\n"
|
||||
" acc = f.call(acc, element)\n"
|
||||
" }\n"
|
||||
" return acc\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" reduce(f) {\n"
|
||||
" var iter = iterate(null)\n"
|
||||
" if (!iter) Fiber.abort(\"Can't reduce an empty sequence.\")\n"
|
||||
"\n"
|
||||
" // Seed with the first element.\n"
|
||||
" var result = iteratorValue(iter)\n"
|
||||
" while (iter = iterate(iter)) {\n"
|
||||
" result = f.call(result, iteratorValue(iter))\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" join { join(\"\") }\n"
|
||||
"\n"
|
||||
" join(sep) {\n"
|
||||
" var first = true\n"
|
||||
" var result = \"\"\n"
|
||||
"\n"
|
||||
" for (element in this) {\n"
|
||||
" if (!first) result = result + sep\n"
|
||||
" first = false\n"
|
||||
" result = result + element.toString\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" toList {\n"
|
||||
" var result = List.new()\n"
|
||||
" for (element in this) {\n"
|
||||
" result.add(element)\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class MapSequence is Sequence {\n"
|
||||
" construct new(sequence, fn) {\n"
|
||||
" _sequence = sequence\n"
|
||||
" _fn = fn\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(iterator) { _sequence.iterate(iterator) }\n"
|
||||
" iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class WhereSequence is Sequence {\n"
|
||||
" construct new(sequence, fn) {\n"
|
||||
" _sequence = sequence\n"
|
||||
" _fn = fn\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(iterator) {\n"
|
||||
" while (iterator = _sequence.iterate(iterator)) {\n"
|
||||
" if (_fn.call(_sequence.iteratorValue(iterator))) break\n"
|
||||
" }\n"
|
||||
" return iterator\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iteratorValue(iterator) { _sequence.iteratorValue(iterator) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class String is Sequence {\n"
|
||||
" bytes { StringByteSequence.new(this) }\n"
|
||||
" codePoints { StringCodePointSequence.new(this) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class StringByteSequence is Sequence {\n"
|
||||
" construct new(string) {\n"
|
||||
" _string = string\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" [index] { _string.byteAt_(index) }\n"
|
||||
" iterate(iterator) { _string.iterateByte_(iterator) }\n"
|
||||
" iteratorValue(iterator) { _string.byteAt_(iterator) }\n"
|
||||
"\n"
|
||||
" count { _string.byteCount_ }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class StringCodePointSequence is Sequence {\n"
|
||||
" construct new(string) {\n"
|
||||
" _string = string\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" [index] { _string.codePointAt_(index) }\n"
|
||||
" iterate(iterator) { _string.iterate(iterator) }\n"
|
||||
" iteratorValue(iterator) { _string.codePointAt_(iterator) }\n"
|
||||
"\n"
|
||||
" count { _string.count }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class List is Sequence {\n"
|
||||
" addAll(other) {\n"
|
||||
" for (element in other) {\n"
|
||||
" add(element)\n"
|
||||
" }\n"
|
||||
" return other\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" toString { \"[\" + join(\", \") + \"]\" }\n"
|
||||
"\n"
|
||||
" +(other) {\n"
|
||||
" var result = this[0..-1]\n"
|
||||
" for (element in other) {\n"
|
||||
" result.add(element)\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Map {\n"
|
||||
" keys { MapKeySequence.new(this) }\n"
|
||||
" values { MapValueSequence.new(this) }\n"
|
||||
"\n"
|
||||
" toString {\n"
|
||||
" var first = true\n"
|
||||
" var result = \"{\"\n"
|
||||
"\n"
|
||||
" for (key in keys) {\n"
|
||||
" if (!first) result = result + \", \"\n"
|
||||
" first = false\n"
|
||||
" result = result + key.toString + \": \" + this[key].toString\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result + \"}\"\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class MapKeySequence is Sequence {\n"
|
||||
" construct new(map) {\n"
|
||||
" _map = map\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(n) { _map.iterate_(n) }\n"
|
||||
" iteratorValue(iterator) { _map.keyIteratorValue_(iterator) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class MapValueSequence is Sequence {\n"
|
||||
" construct new(map) {\n"
|
||||
" _map = map\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(n) { _map.iterate_(n) }\n"
|
||||
" iteratorValue(iterator) { _map.valueIteratorValue_(iterator) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Range is Sequence {}\n";
|
||||
#include "wren_core.wren.inc"
|
||||
|
||||
DEF_PRIMITIVE(bool_not)
|
||||
{
|
||||
@ -304,7 +88,7 @@ static PrimitiveResult runFiber(WrenVM* vm, ObjFiber* fiber, Value* args,
|
||||
if (isCall)
|
||||
{
|
||||
if (fiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
|
||||
|
||||
|
||||
// Remember who ran it.
|
||||
fiber->caller = vm->fiber;
|
||||
}
|
||||
@ -315,21 +99,21 @@ static PrimitiveResult runFiber(WrenVM* vm, ObjFiber* fiber, Value* args,
|
||||
// return below, it would overwrite the fiber being transferred to.
|
||||
if (fiber == vm->fiber) RETURN_VAL(hasValue ? args[1] : NULL_VAL);
|
||||
}
|
||||
|
||||
|
||||
if (fiber->numFrames == 0)
|
||||
{
|
||||
args[0] = wrenStringFormat(vm, "Cannot $ a finished fiber.",
|
||||
isCall ? "call" : "transfer to");
|
||||
return PRIM_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (fiber->error != NULL)
|
||||
{
|
||||
args[0] = wrenStringFormat(vm, "Cannot $ an aborted fiber.",
|
||||
isCall ? "call" : "transfer to");
|
||||
return PRIM_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
@ -340,7 +124,7 @@ static PrimitiveResult runFiber(WrenVM* vm, ObjFiber* fiber, Value* args,
|
||||
{
|
||||
*(fiber->stackTop - 1) = hasValue ? args[1] : NULL_VAL;
|
||||
}
|
||||
|
||||
|
||||
return PRIM_RUN_FIBER;
|
||||
}
|
||||
|
||||
@ -416,7 +200,7 @@ DEF_PRIMITIVE(fiber_yield)
|
||||
ObjFiber* caller = fiber->caller;
|
||||
fiber->caller = NULL;
|
||||
fiber->callerIsTrying = false;
|
||||
|
||||
|
||||
// If we don't have any other pending fibers, jump all the way out of the
|
||||
// interpreter.
|
||||
if (caller == NULL)
|
||||
@ -1274,7 +1058,7 @@ static ObjClass* defineClass(WrenVM* vm, ObjModule* module, const char* name)
|
||||
void wrenInitializeCore(WrenVM* vm)
|
||||
{
|
||||
ObjModule* coreModule = wrenGetCoreModule(vm);
|
||||
|
||||
|
||||
// Define the root Object class. This has to be done a little specially
|
||||
// because it has no superclass.
|
||||
vm->objectClass = defineClass(vm, coreModule, "Object");
|
||||
@ -1329,7 +1113,7 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
// '---------' '-------------------' -'
|
||||
|
||||
// The rest of the classes can now be defined normally.
|
||||
wrenInterpret(vm, "", coreLibSource);
|
||||
wrenInterpret(vm, "", coreModuleSource);
|
||||
|
||||
vm->boolClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Bool"));
|
||||
PRIMITIVE(vm->boolClass, "toString", bool_toString);
|
||||
|
||||
217
src/vm/wren_core.wren.inc
Normal file
217
src/vm/wren_core.wren.inc
Normal file
@ -0,0 +1,217 @@
|
||||
// Generated automatically from builtin/core.wren. Do not edit.
|
||||
static const char* coreModuleSource =
|
||||
"class Bool {}\n"
|
||||
"class Fiber {}\n"
|
||||
"class Fn {}\n"
|
||||
"class Null {}\n"
|
||||
"class Num {}\n"
|
||||
"\n"
|
||||
"class Sequence {\n"
|
||||
" all(f) {\n"
|
||||
" var result = true\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" if (!result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" any(f) {\n"
|
||||
" var result = false\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" if (result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" contains(element) {\n"
|
||||
" for (item in this) {\n"
|
||||
" if (element == item) return true\n"
|
||||
" }\n"
|
||||
" return false\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" count {\n"
|
||||
" var result = 0\n"
|
||||
" for (element in this) {\n"
|
||||
" result = result + 1\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" count(f) {\n"
|
||||
" var result = 0\n"
|
||||
" for (element in this) {\n"
|
||||
" if (f.call(element)) result = result + 1\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" each(f) {\n"
|
||||
" for (element in this) {\n"
|
||||
" f.call(element)\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isEmpty { iterate(null) ? false : true }\n"
|
||||
"\n"
|
||||
" map(transformation) { MapSequence.new(this, transformation) }\n"
|
||||
"\n"
|
||||
" where(predicate) { WhereSequence.new(this, predicate) }\n"
|
||||
"\n"
|
||||
" reduce(acc, f) {\n"
|
||||
" for (element in this) {\n"
|
||||
" acc = f.call(acc, element)\n"
|
||||
" }\n"
|
||||
" return acc\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" reduce(f) {\n"
|
||||
" var iter = iterate(null)\n"
|
||||
" if (!iter) Fiber.abort(\"Can't reduce an empty sequence.\")\n"
|
||||
"\n"
|
||||
" // Seed with the first element.\n"
|
||||
" var result = iteratorValue(iter)\n"
|
||||
" while (iter = iterate(iter)) {\n"
|
||||
" result = f.call(result, iteratorValue(iter))\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" join { join(\"\") }\n"
|
||||
"\n"
|
||||
" join(sep) {\n"
|
||||
" var first = true\n"
|
||||
" var result = \"\"\n"
|
||||
"\n"
|
||||
" for (element in this) {\n"
|
||||
" if (!first) result = result + sep\n"
|
||||
" first = false\n"
|
||||
" result = result + element.toString\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" toList {\n"
|
||||
" var result = List.new()\n"
|
||||
" for (element in this) {\n"
|
||||
" result.add(element)\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class MapSequence is Sequence {\n"
|
||||
" construct new(sequence, fn) {\n"
|
||||
" _sequence = sequence\n"
|
||||
" _fn = fn\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(iterator) { _sequence.iterate(iterator) }\n"
|
||||
" iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class WhereSequence is Sequence {\n"
|
||||
" construct new(sequence, fn) {\n"
|
||||
" _sequence = sequence\n"
|
||||
" _fn = fn\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(iterator) {\n"
|
||||
" while (iterator = _sequence.iterate(iterator)) {\n"
|
||||
" if (_fn.call(_sequence.iteratorValue(iterator))) break\n"
|
||||
" }\n"
|
||||
" return iterator\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iteratorValue(iterator) { _sequence.iteratorValue(iterator) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class String is Sequence {\n"
|
||||
" bytes { StringByteSequence.new(this) }\n"
|
||||
" codePoints { StringCodePointSequence.new(this) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class StringByteSequence is Sequence {\n"
|
||||
" construct new(string) {\n"
|
||||
" _string = string\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" [index] { _string.byteAt_(index) }\n"
|
||||
" iterate(iterator) { _string.iterateByte_(iterator) }\n"
|
||||
" iteratorValue(iterator) { _string.byteAt_(iterator) }\n"
|
||||
"\n"
|
||||
" count { _string.byteCount_ }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class StringCodePointSequence is Sequence {\n"
|
||||
" construct new(string) {\n"
|
||||
" _string = string\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" [index] { _string.codePointAt_(index) }\n"
|
||||
" iterate(iterator) { _string.iterate(iterator) }\n"
|
||||
" iteratorValue(iterator) { _string.codePointAt_(iterator) }\n"
|
||||
"\n"
|
||||
" count { _string.count }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class List is Sequence {\n"
|
||||
" addAll(other) {\n"
|
||||
" for (element in other) {\n"
|
||||
" add(element)\n"
|
||||
" }\n"
|
||||
" return other\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" toString { \"[\" + join(\", \") + \"]\" }\n"
|
||||
"\n"
|
||||
" +(other) {\n"
|
||||
" var result = this[0..-1]\n"
|
||||
" for (element in other) {\n"
|
||||
" result.add(element)\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Map {\n"
|
||||
" keys { MapKeySequence.new(this) }\n"
|
||||
" values { MapValueSequence.new(this) }\n"
|
||||
"\n"
|
||||
" toString {\n"
|
||||
" var first = true\n"
|
||||
" var result = \"{\"\n"
|
||||
"\n"
|
||||
" for (key in keys) {\n"
|
||||
" if (!first) result = result + \", \"\n"
|
||||
" first = false\n"
|
||||
" result = result + key.toString + \": \" + this[key].toString\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result + \"}\"\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class MapKeySequence is Sequence {\n"
|
||||
" construct new(map) {\n"
|
||||
" _map = map\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(n) { _map.iterate_(n) }\n"
|
||||
" iteratorValue(iterator) { _map.keyIteratorValue_(iterator) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class MapValueSequence is Sequence {\n"
|
||||
" construct new(map) {\n"
|
||||
" _map = map\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(n) { _map.iterate_(n) }\n"
|
||||
" iteratorValue(iterator) { _map.valueIteratorValue_(iterator) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Range is Sequence {}\n";
|
||||
108
src/vm/wren_io.c
108
src/vm/wren_io.c
@ -9,109 +9,7 @@
|
||||
// TODO: This is an arbitrary limit. Do something smarter.
|
||||
#define MAX_READ_LEN 1024
|
||||
|
||||
// This string literal is generated automatically from io.wren. Do not edit.
|
||||
static const char* ioLibSource =
|
||||
"class IO {\n"
|
||||
" static print {\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(obj) {\n"
|
||||
" writeObject_(obj)\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" return obj\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2) {\n"
|
||||
" printAll([a1, a2])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3) {\n"
|
||||
" printAll([a1, a2, a3])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4) {\n"
|
||||
" printAll([a1, a2, a3, a4])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static printAll(sequence) {\n"
|
||||
" for (object in sequence) writeObject_(object)\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static write(obj) {\n"
|
||||
" writeObject_(obj)\n"
|
||||
" return obj\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static read(prompt) {\n"
|
||||
" if (!(prompt is String)) Fiber.abort(\"Prompt must be a string.\")\n"
|
||||
" write(prompt)\n"
|
||||
" return read()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static writeObject_(obj) {\n"
|
||||
" var string = obj.toString\n"
|
||||
" if (string is String) {\n"
|
||||
" writeString_(string)\n"
|
||||
" } else {\n"
|
||||
" writeString_(\"[invalid toString]\")\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static writeString_(string)\n"
|
||||
" foreign static clock\n"
|
||||
" foreign static time\n"
|
||||
" foreign static read()\n"
|
||||
"}\n";
|
||||
#include "wren_io.wren.inc"
|
||||
|
||||
static void ioWriteString(WrenVM* vm)
|
||||
{
|
||||
@ -143,14 +41,14 @@ static void ioTime(WrenVM* vm)
|
||||
|
||||
void wrenLoadIOLibrary(WrenVM* vm)
|
||||
{
|
||||
wrenInterpret(vm, "", ioLibSource);
|
||||
wrenInterpret(vm, "", ioModuleSource);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn wrenBindIOForeignMethod(WrenVM* vm, const char* className,
|
||||
const char* signature)
|
||||
{
|
||||
if (strcmp(className, "IO") != 0) return NULL;
|
||||
|
||||
|
||||
if (strcmp(signature, "writeString_(_)") == 0) return ioWriteString;
|
||||
if (strcmp(signature, "clock") == 0) return ioClock;
|
||||
if (strcmp(signature, "time") == 0) return ioTime;
|
||||
|
||||
103
src/vm/wren_io.wren.inc
Normal file
103
src/vm/wren_io.wren.inc
Normal file
@ -0,0 +1,103 @@
|
||||
// Generated automatically from builtin/io.wren. Do not edit.
|
||||
static const char* ioModuleSource =
|
||||
"class IO {\n"
|
||||
" static print {\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(obj) {\n"
|
||||
" writeObject_(obj)\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" return obj\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2) {\n"
|
||||
" printAll([a1, a2])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3) {\n"
|
||||
" printAll([a1, a2, a3])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4) {\n"
|
||||
" printAll([a1, a2, a3, a4])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) {\n"
|
||||
" printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16])\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static printAll(sequence) {\n"
|
||||
" for (object in sequence) writeObject_(object)\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static write(obj) {\n"
|
||||
" writeObject_(obj)\n"
|
||||
" return obj\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static read(prompt) {\n"
|
||||
" if (!(prompt is String)) Fiber.abort(\"Prompt must be a string.\")\n"
|
||||
" write(prompt)\n"
|
||||
" return read()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static writeObject_(obj) {\n"
|
||||
" var string = obj.toString\n"
|
||||
" if (string is String) {\n"
|
||||
" writeString_(string)\n"
|
||||
" } else {\n"
|
||||
" writeString_(\"[invalid toString]\")\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static writeString_(string)\n"
|
||||
" foreign static clock\n"
|
||||
" foreign static time\n"
|
||||
" foreign static read()\n"
|
||||
"}\n";
|
||||
@ -6,9 +6,7 @@
|
||||
|
||||
#include "wren_primitive.h"
|
||||
|
||||
// This string literal is generated automatically from meta.wren. Do not edit.
|
||||
static const char* metaLibSource =
|
||||
"class Meta {}\n";
|
||||
#include "wren_meta.wren.inc"
|
||||
|
||||
DEF_PRIMITIVE(meta_eval)
|
||||
{
|
||||
@ -43,10 +41,10 @@ DEF_PRIMITIVE(meta_eval)
|
||||
|
||||
void wrenLoadMetaLibrary(WrenVM* vm)
|
||||
{
|
||||
wrenInterpret(vm, "", metaLibSource);
|
||||
wrenInterpret(vm, "", metaModuleSource);
|
||||
|
||||
ObjModule* coreModule = wrenGetCoreModule(vm);
|
||||
|
||||
|
||||
// The methods on "Meta" are static, so get the metaclass for the Meta class.
|
||||
ObjClass* meta = AS_CLASS(wrenFindVariable(vm, coreModule, "Meta"));
|
||||
PRIMITIVE(meta->obj.classObj, "eval(_)", meta_eval);
|
||||
|
||||
3
src/vm/wren_meta.wren.inc
Normal file
3
src/vm/wren_meta.wren.inc
Normal file
@ -0,0 +1,3 @@
|
||||
// Generated automatically from builtin/meta.wren. Do not edit.
|
||||
static const char* metaModuleSource =
|
||||
"class Meta {}\n";
|
||||
@ -634,7 +634,7 @@ static void bindForeignClass(WrenVM* vm, ObjClass* classObj, ObjModule* module)
|
||||
// occurred.
|
||||
//
|
||||
// Returns false if the result is an error.
|
||||
static bool defineClass(WrenVM* vm, ObjFiber* fiber, int numFields,
|
||||
static bool createClass(WrenVM* vm, ObjFiber* fiber, int numFields,
|
||||
ObjModule* module)
|
||||
{
|
||||
// Pull the name and superclass off the stack.
|
||||
@ -1195,13 +1195,13 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber)
|
||||
|
||||
CASE_CODE(CLASS):
|
||||
{
|
||||
if (!defineClass(vm, fiber, READ_BYTE(), NULL)) RUNTIME_ERROR(PEEK());
|
||||
if (!createClass(vm, fiber, READ_BYTE(), NULL)) RUNTIME_ERROR(PEEK());
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
CASE_CODE(FOREIGN_CLASS):
|
||||
{
|
||||
if (!defineClass(vm, fiber, -1, fn->module)) RUNTIME_ERROR(PEEK());
|
||||
if (!createClass(vm, fiber, -1, fn->module)) RUNTIME_ERROR(PEEK());
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user