1
0
forked from Mirror/wren

Move IO into a separate module.

This commit is contained in:
Bob Nystrom
2014-02-04 08:44:59 -08:00
parent ba06a4fd8a
commit 36df70dba1
13 changed files with 182 additions and 96 deletions

View File

@ -52,6 +52,8 @@ docs:
watchdocs:
@./script/generate_docs.py --watch
# Take the contents of corelib.wren and copy them into src/wren_core.c.
corelib:
@./script/generate_corelib.py
# Take the contents of the scripts under builtin/ and copy them into their
# respective wren_<name>.c source files.
# TODO: Needs dependencies so it knows when to run.
builtin:
@./script/generate_builtins.py

7
builtin/README.md Normal file
View File

@ -0,0 +1,7 @@
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 script that does this copying is `script/generate_builtins.py`.
You can invoke using `make builtin`.

11
builtin/core.wren Normal file
View File

@ -0,0 +1,11 @@
class List {
toString {
var result = "["
for (i in 0...this.count) {
if (i > 0) result = result + ", "
result = result + this[i].toString
}
result = result + "]"
return result
}
}

12
builtin/io.wren Normal file
View File

@ -0,0 +1,12 @@
class IO {
static print(obj) {
IO.writeString_(obj.toString)
IO.writeString_("\n")
return obj
}
static write(obj) {
IO.writeString_(obj.toString)
return obj
}
}

View File

@ -1,26 +0,0 @@
// Note: This is converted to a C string literal and inserted into
// src/wren_core.c using make_corelib.
class IO {
static print(obj) {
IO.writeString_(obj.toString)
IO.writeString_("\n")
return obj
}
static write(obj) {
IO.writeString_(obj.toString)
return obj
}
}
class List {
toString {
var result = "["
for (i in 0...this.count) {
if (i > 0) result = result + ", "
result = result + this[i].toString
}
result = result + "]"
return result
}
}

View File

@ -100,11 +100,31 @@ void wrenDefineMethod(WrenVM* vm, const char* className,
const char* methodName, int numParams,
WrenForeignMethodFn method);
// Defines a static foreign method implemented by the host application. Looks
// for a global class named [className] to bind the method to. If not found, it
// will be created automatically.
//
// Defines a static method on that class named [methodName] accepting
// [numParams] parameters. If a method already exists with that name and arity,
// it will be replaced. When invoked, the method will call [method].
void wrenDefineStaticMethod(WrenVM* vm, const char* className,
const char* methodName, int numParams,
WrenForeignMethodFn method);
// Reads an numeric argument for a foreign call. This must only be called within
// a function provided to [wrenDefineMethod]. Retrieves the argument at [index]
// which ranges from 0 to the number of parameters the method expects - 1.
double wrenGetArgumentDouble(WrenVM* vm, int index);
// Reads an string argument for a foreign call. This must only be called within
// a function provided to [wrenDefineMethod]. Retrieves the argument at [index]
// which ranges from 0 to the number of parameters the method expects - 1.
//
// The memory for the returned string is owned by Wren. You can inspect it
// while in your foreign function, but cannot keep a pointer to it after the
// function returns, since the garbage collector may reclaim it.
const char* wrenGetArgumentString(WrenVM* vm, int index);
// Provides a numeric return value for a foreign call. This must only be called
// within a function provided to [wrenDefineMethod]. Once this is called, the
// foreign call is done, and no more arguments can be read or return calls made.

40
script/generate_builtins.py Executable file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env python
import glob
import os.path
import re
PATTERN = re.compile(r'libSource =\n("(.|[\n])*?);')
def copy_builtin(filename):
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("src/wren_" + name + ".c", "r") as f:
c_source = f.read()
c_source = PATTERN.sub(constant, c_source)
with open("src/wren_" + name + ".c", "w") as f:
f.write(c_source)
print name
for f in glob.iglob("builtin/*.wren"):
copy_builtin(f)

View File

@ -1,31 +0,0 @@
#!/usr/bin/env python
import re
with open("corelib.wren", "r") as f:
lines = f.readlines()
# Remove the comment from the top.
lines.pop(0)
lines.pop(0)
corelib = ""
for line in lines:
line = line.replace('"', "\\\"")
line = line.replace("\n", "\\n\"")
if corelib: corelib += "\n"
corelib += '"' + line
with open("src/wren_core.c", "r") as f:
wren_core = f.read()
# re.sub() will unescape escape sequences, but we want them to stay as escapes
# in the C string literal.
corelib = corelib.replace('\\', '\\\\')
corelib = "coreLibSource =\n" + corelib + ";"
PATTERN = re.compile(r'coreLibSource =\n("(.|[\n])*?);')
wren_core = PATTERN.sub(corelib, wren_core)
with open("src/wren_core.c", "w") as f:
f.write(wren_core)

View File

@ -40,22 +40,8 @@
return PRIM_ERROR; \
} while (0);
// This string literal is generated automatically from corelib.wren using
// make_corelib. Do not edit here.
const char* coreLibSource =
"class IO {\n"
" static print(obj) {\n"
" IO.writeString_(obj.toString)\n"
" IO.writeString_(\"\n\")\n"
" return obj\n"
" }\n"
"\n"
" static write(obj) {\n"
" IO.writeString_(obj.toString)\n"
" return obj\n"
" }\n"
"}\n"
"\n"
// This string literal is generated automatically from core. Do not edit.
static const char* libSource =
"class List {\n"
" toString {\n"
" var result = \"[\"\n"
@ -68,7 +54,6 @@ const char* coreLibSource =
" }\n"
"}\n";
// Validates that the given argument in [args] is a Num. Returns true if it is.
// If not, reports an error and returns false.
static bool validateNum(WrenVM* vm, Value* args, int index, const char* argName)
@ -746,13 +731,6 @@ DEF_NATIVE(string_subscript)
RETURN_VAL(value);
}
DEF_NATIVE(io_writeString)
{
if (!validateString(vm, args, 1, "Argument")) return PRIM_ERROR;
wrenPrintValue(args[1]);
RETURN_NULL;
}
DEF_NATIVE(os_clock)
{
double time = (double)clock() / CLOCKS_PER_SEC;
@ -924,7 +902,7 @@ void wrenInitializeCore(WrenVM* vm)
ObjClass* osClass = defineClass(vm, "OS");
NATIVE(osClass->metaclass, "clock", os_clock);
wrenInterpret(vm, "Wren core library", coreLibSource);
wrenInterpret(vm, "Wren core library", libSource);
vm->listClass = AS_CLASS(findGlobal(vm, "List"));
NATIVE(vm->listClass, "add ", list_add);
@ -941,7 +919,4 @@ void wrenInitializeCore(WrenVM* vm)
// IEEE 754 even though they have different bit representations.
NATIVE(vm->numClass, "== ", num_eqeq);
NATIVE(vm->numClass, "!= ", num_bangeq);
ObjClass* ioClass = AS_CLASS(findGlobal(vm, "IO"));
NATIVE(ioClass->metaclass, "writeString_ ", io_writeString);
}

31
src/wren_io.c Normal file
View File

@ -0,0 +1,31 @@
#include <stdio.h>
#include "wren_io.h"
// This string literal is generated automatically from io.wren. Do not edit.
static const char* libSource =
"class IO {\n"
" static print(obj) {\n"
" IO.writeString_(obj.toString)\n"
" IO.writeString_(\"\n\")\n"
" return obj\n"
" }\n"
"\n"
" static write(obj) {\n"
" IO.writeString_(obj.toString)\n"
" return obj\n"
" }\n"
"}\n";
static void writeString(WrenVM* vm)
{
const char* s = wrenGetArgumentString(vm, 1);
// TODO: Check for null.
printf("%s", s);
}
void wrenLoadIOLibrary(WrenVM* vm)
{
wrenInterpret(vm, "Wren IO library", libSource);
wrenDefineStaticMethod(vm, "IO", "writeString_", 1, writeString);
}

11
src/wren_io.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef wren_io_h
#define wren_io_h
#include "wren.h"
// This module defines the IO class and its associated methods. They are
// implemented using the C standard library.
void wrenLoadIOLibrary(WrenVM* vm);
#endif

View File

@ -9,6 +9,8 @@
// TODO: This is used for printing the stack trace on an error. This should be
// behind a flag so that you can use Wren with all debugging info stripped out.
#include "wren_debug.h"
// TODO: Put this behind a flag so users can disable the IO library.
#include "wren_io.h"
#include "wren_vm.h"
#if WREN_TRACE_MEMORY || WREN_TRACE_GC
@ -76,6 +78,8 @@ WrenVM* wrenNewVM(WrenConfiguration* configuration)
vm->foreignCallNumArgs = 0;
wrenInitializeCore(vm);
wrenLoadIOLibrary(vm);
return vm;
}
@ -288,9 +292,7 @@ static void callForeign(WrenVM* vm, ObjFiber* fiber,
WrenForeignMethodFn foreign, int numArgs)
{
vm->foreignCallSlot = &fiber->stack[fiber->stackSize - numArgs];
// Don't include the receiver.
vm->foreignCallNumArgs = numArgs - 1;
vm->foreignCallNumArgs = numArgs;
foreign(vm);
@ -1061,9 +1063,9 @@ void wrenUnpinObj(WrenVM* vm)
vm->pinned = vm->pinned->previous;
}
void wrenDefineMethod(WrenVM* vm, const char* className,
const char* methodName, int numParams,
WrenForeignMethodFn methodFn)
static void defineMethod(WrenVM* vm, const char* className,
const char* methodName, int numParams,
WrenForeignMethodFn methodFn, bool isStatic)
{
ASSERT(className != NULL, "Must provide class name.");
@ -1119,18 +1121,44 @@ void wrenDefineMethod(WrenVM* vm, const char* className,
Method method;
method.type = METHOD_FOREIGN;
method.foreign = methodFn;
if (isStatic) classObj = classObj->metaclass;
wrenBindMethod(vm, classObj, methodSymbol, method);
}
void wrenDefineMethod(WrenVM* vm, const char* className,
const char* methodName, int numParams,
WrenForeignMethodFn methodFn)
{
defineMethod(vm, className, methodName, numParams, methodFn, false);
}
void wrenDefineStaticMethod(WrenVM* vm, const char* className,
const char* methodName, int numParams,
WrenForeignMethodFn methodFn)
{
defineMethod(vm, className, methodName, numParams, methodFn, true);
}
double wrenGetArgumentDouble(WrenVM* vm, int index)
{
ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call.");
ASSERT(index >= 0, "index cannot be negative.");
ASSERT(index < vm->foreignCallNumArgs, "Not that many arguments.");
// + 1 to shift past the receiver.
// TODO: Check actual value type first.
return AS_NUM(*(vm->foreignCallSlot + index + 1));
return AS_NUM(*(vm->foreignCallSlot + index));
}
const char* wrenGetArgumentString(WrenVM* vm, int index)
{
ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call.");
ASSERT(index >= 0, "index cannot be negative.");
ASSERT(index < vm->foreignCallNumArgs, "Not that many arguments.");
// TODO: Check actual value type first.
return AS_CSTRING(*(vm->foreignCallSlot + index));
}
void wrenReturnDouble(WrenVM* vm, double value)

View File

@ -13,6 +13,7 @@
29AB1F3218170104004B501E /* wren_compiler.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F3018170104004B501E /* wren_compiler.c */; };
29B0C61C187524A500354372 /* wren_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 29B0C61B187524A500354372 /* wren_utils.c */; };
29CEDD5718495A630074C8B7 /* wren_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 29CEDD5618495A630074C8B7 /* wren_debug.c */; };
29EC5BBA18A024DA00BA4D1C /* wren_io.c in Sources */ = {isa = PBXBuildFile; fileRef = 29EC5BB918A024DA00BA4D1C /* wren_io.c */; };
29FA7298181D91020089013C /* wren_core.c in Sources */ = {isa = PBXBuildFile; fileRef = 29FA7297181D91020089013C /* wren_core.c */; };
/* End PBXBuildFile section */
@ -43,6 +44,8 @@
29B0C61D187524BC00354372 /* wren_utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = wren_utils.h; path = src/wren_utils.h; sourceTree = SOURCE_ROOT; };
29BD8159184CCEE700FA45E9 /* wren_debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = wren_debug.h; path = src/wren_debug.h; sourceTree = SOURCE_ROOT; };
29CEDD5618495A630074C8B7 /* wren_debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wren_debug.c; path = src/wren_debug.c; sourceTree = SOURCE_ROOT; };
29EC5BB818A024A400BA4D1C /* wren_io.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = wren_io.h; path = src/wren_io.h; sourceTree = SOURCE_ROOT; };
29EC5BB918A024DA00BA4D1C /* wren_io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wren_io.c; path = src/wren_io.c; sourceTree = SOURCE_ROOT; };
29FA7296181D90F30089013C /* wren_core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = wren_core.h; path = src/wren_core.h; sourceTree = SOURCE_ROOT; };
29FA7297181D91020089013C /* wren_core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wren_core.c; path = src/wren_core.c; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
@ -100,6 +103,8 @@
292A45D41838566F00C34813 /* wren_value.c */,
29AB1F2D1816FA5B004B501E /* wren_vm.h */,
29AB1F2E1816FA66004B501E /* wren_vm.c */,
29EC5BB818A024A400BA4D1C /* wren_io.h */,
29EC5BB918A024DA00BA4D1C /* wren_io.c */,
);
name = src;
path = wren;
@ -161,6 +166,7 @@
29AB1F291816E49C004B501E /* main.c in Sources */,
29FA7298181D91020089013C /* wren_core.c in Sources */,
29AB1F3218170104004B501E /* wren_compiler.c in Sources */,
29EC5BBA18A024DA00BA4D1C /* wren_io.c in Sources */,
29AB1F2F1816FA66004B501E /* wren_vm.c in Sources */,
29B0C61C187524A500354372 /* wren_utils.c in Sources */,
);