From 09f266c23fb22f391f04903272a8a8e9e1add383 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Mon, 16 Mar 2015 07:05:40 -0700 Subject: [PATCH 1/3] Fix typo in wrenDumpObject(). Thanks, Michel! --- src/vm/wren_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm/wren_debug.c b/src/vm/wren_debug.c index 90356cf6..84846fed 100644 --- a/src/vm/wren_debug.c +++ b/src/vm/wren_debug.c @@ -48,7 +48,7 @@ static void dumpObject(Obj* obj) case OBJ_LIST: printf("[list %p]", obj); break; case OBJ_MAP: printf("[map %p]", obj); break; case OBJ_MODULE: printf("[module %p]", obj); break; - case OBJ_RANGE: printf("[fn %p]", obj); break; + case OBJ_RANGE: printf("[range %p]", obj); break; case OBJ_STRING: printf("%s", ((ObjString*)obj)->value); break; case OBJ_UPVALUE: printf("[upvalue %p]", obj); break; default: printf("[unknown object]"); break; From aedf9a85715aae9cf188108fd3339a248dbdb7f3 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Mon, 16 Mar 2015 07:22:52 -0700 Subject: [PATCH 2/3] Move CLI file loading code to separate file. --- project/xcode/wren.xcodeproj/project.pbxproj | 6 ++ src/cli/io.c | 77 ++++++++++++++++++++ src/cli/io.h | 25 +++++++ src/cli/main.c | 73 ++----------------- 4 files changed, 113 insertions(+), 68 deletions(-) create mode 100644 src/cli/io.c create mode 100644 src/cli/io.h diff --git a/project/xcode/wren.xcodeproj/project.pbxproj b/project/xcode/wren.xcodeproj/project.pbxproj index cde735e3..2fb780c9 100644 --- a/project/xcode/wren.xcodeproj/project.pbxproj +++ b/project/xcode/wren.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 29205C9D1AB4E6430073018D /* wren_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 29205C961AB4E6430073018D /* wren_utils.c */; }; 29205C9E1AB4E6430073018D /* wren_value.c in Sources */ = {isa = PBXBuildFile; fileRef = 29205C971AB4E6430073018D /* wren_value.c */; }; 29205C9F1AB4E6430073018D /* wren_vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29205C981AB4E6430073018D /* wren_vm.c */; }; + 29C8A92F1AB71C1C00DEC81D /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = 29C8A92E1AB71C1C00DEC81D /* io.c */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -48,6 +49,8 @@ 29205CA71AB4E65E0073018D /* wren_value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_value.h; path = ../../src/vm/wren_value.h; sourceTree = ""; }; 29205CA81AB4E65E0073018D /* wren_vm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_vm.h; path = ../../src/vm/wren_vm.h; sourceTree = ""; }; 29AB1F061816E3AD004B501E /* wren */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wren; sourceTree = BUILT_PRODUCTS_DIR; }; + 29C8A92E1AB71C1C00DEC81D /* io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = io.c; path = ../../src/cli/io.c; sourceTree = ""; }; + 29C8A9301AB71C3300DEC81D /* io.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = io.h; path = ../../src/cli/io.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -86,6 +89,8 @@ 29205CA91AB4E67B0073018D /* cli */ = { isa = PBXGroup; children = ( + 29C8A9301AB71C3300DEC81D /* io.h */, + 29C8A92E1AB71C1C00DEC81D /* io.c */, 29205C8E1AB4E5C90073018D /* main.c */, ); name = cli; @@ -175,6 +180,7 @@ 29205C9D1AB4E6430073018D /* wren_utils.c in Sources */, 29205C9E1AB4E6430073018D /* wren_value.c in Sources */, 29205C9F1AB4E6430073018D /* wren_vm.c in Sources */, + 29C8A92F1AB71C1C00DEC81D /* io.c in Sources */, 29205C8F1AB4E5C90073018D /* main.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/src/cli/io.c b/src/cli/io.c new file mode 100644 index 00000000..bf41bdfc --- /dev/null +++ b/src/cli/io.c @@ -0,0 +1,77 @@ +#include +#include +#include + +#include "io.h" + +char const* rootDirectory = NULL; + +// Reads the contents of the file at [path] and returns it as a heap allocated +// string. +// +// Returns `NULL` if the path could not be found. Exits if it was found but +// could not be read. +char* readFile(const char* path) +{ + FILE* file = fopen(path, "rb"); + if (file == NULL) return NULL; + + // Find out how big the file is. + fseek(file, 0L, SEEK_END); + size_t fileSize = ftell(file); + rewind(file); + + // Allocate a buffer for it. + char* buffer = (char*)malloc(fileSize + 1); + if (buffer == NULL) + { + fprintf(stderr, "Could not read file \"%s\".\n", path); + exit(74); + } + + // Read the entire file. + size_t bytesRead = fread(buffer, sizeof(char), fileSize, file); + if (bytesRead < fileSize) + { + fprintf(stderr, "Could not read file \"%s\".\n", path); + exit(74); + } + + // Terminate the string. + buffer[bytesRead] = '\0'; + + fclose(file); + return buffer; +} + +void setRootDirectory(const char* path) +{ + rootDirectory = path; +} + +char* readModule(WrenVM* vm, const char* module) +{ + // The module path is relative to the root directory and with ".wren". + size_t rootLength = rootDirectory == NULL ? 0 : strlen(rootDirectory); + size_t moduleLength = strlen(module); + size_t pathLength = rootLength + moduleLength + 5; + char* path = (char*)malloc(pathLength + 1); + + if (rootDirectory != NULL) + { + memcpy(path, rootDirectory, rootLength); + } + + memcpy(path + rootLength, module, moduleLength); + memcpy(path + rootLength + moduleLength, ".wren", 5); + path[pathLength] = '\0'; + + char* file = readFile(path); + if (file == NULL) + { + free(path); + return NULL; + } + + return file; +} diff --git a/src/cli/io.h b/src/cli/io.h new file mode 100644 index 00000000..d60d6021 --- /dev/null +++ b/src/cli/io.h @@ -0,0 +1,25 @@ +#ifndef io_h +#define io_h + +#include "wren.h" + +// Simple IO functions. + +// Reads the contents of the file at [path] and returns it as a heap allocated +// string. +// +// Returns `NULL` if the path could not be found. Exits if it was found but +// could not be read. +char* readFile(const char* path); + +// Sets the root directory that modules are resolved relative to. +void setRootDirectory(const char* path); + +// Attempts to read the source for [module] relative to the current root +// directory. +// +// Returns it if found, or NULL if the module could not be found. Exits if the +// module was found but could not be read. +char* readModule(WrenVM* vm, const char* module); + +#endif diff --git a/src/cli/main.c b/src/cli/main.c index 1b60a250..e03e64ea 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -4,72 +4,10 @@ #include #include +#include "io.h" #include "wren.h" #define MAX_LINE_LENGTH 1024 // TODO: Something less arbitrary. -#define MAX_PATH_LENGTH 2024 // TODO: Something less arbitrary. - -char rootDirectory[MAX_PATH_LENGTH]; - -// Reads the contents of the file at [path] and returns it as a heap allocated -// string. -// -// Returns `NULL` if the path could not be found. Exits if it was found but -// could not be read. -static char* readFile(const char* path) -{ - FILE* file = fopen(path, "rb"); - if (file == NULL) return NULL; - - // Find out how big the file is. - fseek(file, 0L, SEEK_END); - size_t fileSize = ftell(file); - rewind(file); - - // Allocate a buffer for it. - char* buffer = (char*)malloc(fileSize + 1); - if (buffer == NULL) - { - fprintf(stderr, "Could not read file \"%s\".\n", path); - exit(74); - } - - // Read the entire file. - size_t bytesRead = fread(buffer, sizeof(char), fileSize, file); - if (bytesRead < fileSize) - { - fprintf(stderr, "Could not read file \"%s\".\n", path); - exit(74); - } - - // Terminate the string. - buffer[bytesRead] = '\0'; - - fclose(file); - return buffer; -} - -static char* readModule(WrenVM* vm, const char* module) -{ - // The module path is relative to the root directory and with ".wren". - size_t rootLength = strlen(rootDirectory); - size_t moduleLength = strlen(module); - size_t pathLength = rootLength + moduleLength + 5; - char* path = (char*)malloc(pathLength + 1); - memcpy(path, rootDirectory, rootLength); - memcpy(path + rootLength, module, moduleLength); - memcpy(path + rootLength + moduleLength, ".wren", 5); - path[pathLength] = '\0'; - - char* file = readFile(path); - if (file == NULL) - { - free(path); - return NULL; - } - - return file; -} static int runFile(WrenVM* vm, const char* path) { @@ -78,8 +16,10 @@ static int runFile(WrenVM* vm, const char* path) const char* lastSlash = strrchr(path, '/'); if (lastSlash != NULL) { - memcpy(rootDirectory, path, lastSlash - path + 1); - rootDirectory[lastSlash - path + 1] = '\0'; + char* root = (char*)malloc(lastSlash - path + 2); + memcpy(root, path, lastSlash - path + 1); + root[lastSlash - path + 1] = '\0'; + setRootDirectory(root); } char* source = readFile(path); @@ -112,9 +52,6 @@ static int runRepl(WrenVM* vm) printf("\\\\/\"-\n"); printf(" \\_/ wren v0.0.0\n"); - // Import relative to the current directory. - rootDirectory[0] = '\0'; - char line[MAX_LINE_LENGTH]; for (;;) From 91a23da5b0d6e38578c895cafccf9518fb698459 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Mon, 16 Mar 2015 07:42:45 -0700 Subject: [PATCH 3/3] Move CLI script running to a separate file. (This is set up to reuse this code for API tests.) --- project/xcode/wren.xcodeproj/project.pbxproj | 6 ++ src/cli/main.c | 68 ++++---------------- src/cli/vm.c | 54 ++++++++++++++++ src/cli/vm.h | 14 ++++ 4 files changed, 86 insertions(+), 56 deletions(-) create mode 100644 src/cli/vm.c create mode 100644 src/cli/vm.h diff --git a/project/xcode/wren.xcodeproj/project.pbxproj b/project/xcode/wren.xcodeproj/project.pbxproj index 2fb780c9..406f5dc3 100644 --- a/project/xcode/wren.xcodeproj/project.pbxproj +++ b/project/xcode/wren.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 29205C9E1AB4E6430073018D /* wren_value.c in Sources */ = {isa = PBXBuildFile; fileRef = 29205C971AB4E6430073018D /* wren_value.c */; }; 29205C9F1AB4E6430073018D /* wren_vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29205C981AB4E6430073018D /* wren_vm.c */; }; 29C8A92F1AB71C1C00DEC81D /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = 29C8A92E1AB71C1C00DEC81D /* io.c */; }; + 29C8A9331AB71FFF00DEC81D /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29C8A9311AB71FFF00DEC81D /* vm.c */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -51,6 +52,8 @@ 29AB1F061816E3AD004B501E /* wren */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wren; sourceTree = BUILT_PRODUCTS_DIR; }; 29C8A92E1AB71C1C00DEC81D /* io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = io.c; path = ../../src/cli/io.c; sourceTree = ""; }; 29C8A9301AB71C3300DEC81D /* io.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = io.h; path = ../../src/cli/io.h; sourceTree = ""; }; + 29C8A9311AB71FFF00DEC81D /* vm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vm.c; path = ../../src/cli/vm.c; sourceTree = ""; }; + 29C8A9321AB71FFF00DEC81D /* vm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vm.h; path = ../../src/cli/vm.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -92,6 +95,8 @@ 29C8A9301AB71C3300DEC81D /* io.h */, 29C8A92E1AB71C1C00DEC81D /* io.c */, 29205C8E1AB4E5C90073018D /* main.c */, + 29C8A9321AB71FFF00DEC81D /* vm.h */, + 29C8A9311AB71FFF00DEC81D /* vm.c */, ); name = cli; sourceTree = ""; @@ -175,6 +180,7 @@ files = ( 29205C991AB4E6430073018D /* wren_compiler.c in Sources */, 29205C9A1AB4E6430073018D /* wren_core.c in Sources */, + 29C8A9331AB71FFF00DEC81D /* vm.c in Sources */, 29205C9B1AB4E6430073018D /* wren_debug.c in Sources */, 29205C9C1AB4E6430073018D /* wren_io.c in Sources */, 29205C9D1AB4E6430073018D /* wren_utils.c in Sources */, diff --git a/src/cli/main.c b/src/cli/main.c index e03e64ea..d4deeb47 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -1,54 +1,16 @@ -#include -#include #include -#include #include #include "io.h" +#include "vm.h" #include "wren.h" #define MAX_LINE_LENGTH 1024 // TODO: Something less arbitrary. -static int runFile(WrenVM* vm, const char* path) +static int runRepl() { - // Use the directory where the file is as the root to resolve imports - // relative to. - const char* lastSlash = strrchr(path, '/'); - if (lastSlash != NULL) - { - char* root = (char*)malloc(lastSlash - path + 2); - memcpy(root, path, lastSlash - path + 1); - root[lastSlash - path + 1] = '\0'; - setRootDirectory(root); - } + WrenVM* vm = createVM(); - char* source = readFile(path); - if (source == NULL) - { - fprintf(stderr, "Could not find file \"%s\".\n", path); - exit(66); - } - - int result; - switch (wrenInterpret(vm, path, source)) - { - case WREN_RESULT_SUCCESS: result = 0; break; - case WREN_RESULT_COMPILE_ERROR: result = 65; break; // EX_DATAERR. - case WREN_RESULT_RUNTIME_ERROR: result = 70; break; // EX_SOFTWARE. - default: - // Unreachable. - result = 255; - break; - } - - wrenFreeVM(vm); - free(source); - - return result; -} - -static int runRepl(WrenVM* vm) -{ printf("\\\\/\"-\n"); printf(" \\_/ wren v0.0.0\n"); @@ -84,20 +46,14 @@ int main(int argc, const char* argv[]) return 64; // EX_USAGE. } - WrenConfiguration config; + if (argc == 1) + { + runRepl(); + } + else if (argc == 2) + { + runFile(argv[1]); + } - config.loadModuleFn = readModule; - - // Since we're running in a standalone process, be generous with memory. - config.initialHeapSize = 1024 * 1024 * 100; - - // Use defaults for these. - config.reallocateFn = NULL; - config.minHeapSize = 0; - config.heapGrowthPercent = 0; - - WrenVM* vm = wrenNewVM(&config); - - if (argc == 1) return runRepl(vm); - if (argc == 2) return runFile(vm, argv[1]); + return 0; } diff --git a/src/cli/vm.c b/src/cli/vm.c new file mode 100644 index 00000000..7bce1bcd --- /dev/null +++ b/src/cli/vm.c @@ -0,0 +1,54 @@ +#include +#include + +#include "io.h" +#include "vm.h" + +WrenVM* createVM() +{ + WrenConfiguration config; + + config.loadModuleFn = readModule; + + // Since we're running in a standalone process, be generous with memory. + config.initialHeapSize = 1024 * 1024 * 100; + + // Use defaults for these. + config.reallocateFn = NULL; + config.minHeapSize = 0; + config.heapGrowthPercent = 0; + + return wrenNewVM(&config); +} + +void runFile(const char* path) +{ + // Use the directory where the file is as the root to resolve imports + // relative to. + const char* lastSlash = strrchr(path, '/'); + if (lastSlash != NULL) + { + char* root = (char*)malloc(lastSlash - path + 2); + memcpy(root, path, lastSlash - path + 1); + root[lastSlash - path + 1] = '\0'; + setRootDirectory(root); + } + + char* source = readFile(path); + if (source == NULL) + { + fprintf(stderr, "Could not find file \"%s\".\n", path); + exit(66); + } + + WrenVM* vm = createVM(); + + WrenInterpretResult result = wrenInterpret(vm, path, source); + + wrenFreeVM(vm); + free(source); + + // Exit with an error code if the script failed. + if (result == WREN_RESULT_COMPILE_ERROR) exit(65); // EX_DATAERR. + if (result == WREN_RESULT_RUNTIME_ERROR) exit(70); // EX_SOFTWARE. +} diff --git a/src/cli/vm.h b/src/cli/vm.h new file mode 100644 index 00000000..32520ded --- /dev/null +++ b/src/cli/vm.h @@ -0,0 +1,14 @@ +#ifndef vm_h +#define vm_h + +#include "wren.h" + +// Creates a new Wren VM with the CLI's module loader and other configuration. +WrenVM* createVM(); + +// Executes the Wren script at [path] in a new VM. +// +// Exits if the script failed or could not be loaded. +void runFile(const char* path); + +#endif