mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 22:28:45 +01:00
Move IO into a separate module.
This commit is contained in:
8
Makefile
8
Makefile
@ -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
7
builtin/README.md
Normal 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
11
builtin/core.wren
Normal 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
12
builtin/io.wren
Normal 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
|
||||
}
|
||||
}
|
||||
26
corelib.wren
26
corelib.wren
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
40
script/generate_builtins.py
Executable 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)
|
||||
@ -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)
|
||||
@ -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
31
src/wren_io.c
Normal 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
11
src/wren_io.h
Normal 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
|
||||
@ -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)
|
||||
|
||||
@ -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 */,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user