diff --git a/.travis.yml b/.travis.yml index 0d6d48e2..557ca198 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,11 @@ language: c compiler: - gcc - clang -before_install: - # Travis VMs are 64-bit but we compile both for 32 and 64 bit. To enable the - # 32-bit builds to work, we need gcc-multilib. - - sudo apt-get update -qq - - sudo apt-get install -qq gcc-multilib - -script: make all && make test \ No newline at end of file +# Travis VMs are 64-bit but we compile both for 32 and 64 bit. To enable the +# 32-bit builds to work, we need gcc-multilib. +addons: + apt: + packages: + - gcc-multilib +sudo: false # Enable container-based builds. +script: make all && make test diff --git a/README.md b/README.md index e35551e3..50ac299a 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,9 @@ while (!adjectives.isDone) IO.print(adjectives.call()) and [an easy-to-use C API][embedding]. It compiles cleanly as C99, C++98 or anything later. -If you like the sound of this, [give it a try][try]! Even better, you can -[contribute to Wren itself][contribute]. +If you like the sound of this, [let's get started][started]. You can even try +it [in your browser][browser]! Excited? Well, come on and [get +involved][contribute]! [![Build Status](https://travis-ci.org/munificent/wren.svg)](https://travis-ci.org/munificent/wren) @@ -52,5 +53,6 @@ If you like the sound of this, [give it a try][try]! Even better, you can [classes]: http://munificent.github.io/wren/classes.html [fibers]: http://munificent.github.io/wren/fibers.html [embedding]: http://munificent.github.io/wren/embedding-api.html -[try]: http://munificent.github.io/wren/getting-started.html -[contribute]: http://munificent.github.io/wren/contributing.html +[started]: getting-started.html +[browser]: http://ppvk.github.io/wren-nest/ +[contribute]: contributing.html diff --git a/builtin/io.wren b/builtin/io.wren index 06146d49..6b8df735 100644 --- a/builtin/io.wren +++ b/builtin/io.wren @@ -1,101 +1,101 @@ class IO { static print { - IO.writeString_("\n") + writeString_("\n") } static print(obj) { - IO.writeObject_(obj) - IO.writeString_("\n") + writeObject_(obj) + writeString_("\n") return obj } static print(a1, a2) { - printList_([a1, a2]) + printAll([a1, a2]) } static print(a1, a2, a3) { - printList_([a1, a2, a3]) + printAll([a1, a2, a3]) } static print(a1, a2, a3, a4) { - printList_([a1, a2, a3, a4]) + printAll([a1, a2, a3, a4]) } static print(a1, a2, a3, a4, a5) { - printList_([a1, a2, a3, a4, a5]) + printAll([a1, a2, a3, a4, a5]) } static print(a1, a2, a3, a4, a5, a6) { - printList_([a1, a2, a3, a4, a5, a6]) + printAll([a1, a2, a3, a4, a5, a6]) } static print(a1, a2, a3, a4, a5, a6, a7) { - printList_([a1, a2, a3, a4, a5, a6, a7]) + printAll([a1, a2, a3, a4, a5, a6, a7]) } static print(a1, a2, a3, a4, a5, a6, a7, a8) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15]) } static print(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) { - printList_([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16]) + printAll([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16]) } - static printList_(objects) { - for (object in objects) IO.writeObject_(object) - IO.writeString_("\n") + static printAll(sequence) { + for (object in sequence) writeObject_(object) + writeString_("\n") } static write(obj) { - IO.writeObject_(obj) + writeObject_(obj) return obj } static read(prompt) { if (!(prompt is String)) Fiber.abort("Prompt must be a string.") - IO.write(prompt) - return IO.read + write(prompt) + return read() } static writeObject_(obj) { var string = obj.toString if (string is String) { - IO.writeString_(string) + writeString_(string) } else { - IO.writeString_("[invalid toString]") + writeString_("[invalid toString]") } } foreign static writeString_(string) foreign static clock foreign static time - foreign static read + foreign static read() } diff --git a/doc/site/community.markdown b/doc/site/community.markdown index 976754ec..f9ec694a 100644 --- a/doc/site/community.markdown +++ b/doc/site/community.markdown @@ -10,18 +10,21 @@ There's one Wren user group, and it's the [official Wren mailing list](https://groups.google.com/forum/#!forum/wren-lang). Please join it and say hello! There are no strangers to Wren, just friends we haven't met yet. -## Third-party libraries +## Libraries There are some third-party libraries that are written in Wren. Here's the list: -- [wren-test](https://github.com/gsmaverick/wren-test), a testing framework -- [Please](https://github.com/EvanHahn/wren-please), an assertion library -- [wren-colors](https://github.com/gsmaverick/wren-colors) for printing colored - messages to the terminal -- [3D vectors for Wren](https://github.com/EvanHahn/wren-vector3d) +- [Please](https://github.com/EvanHahn/wren-please): An assertion library. +- [wren-colors](https://github.com/gsmaverick/wren-colors): Print colored + messages to the terminal. +- [wren-test](https://github.com/gsmaverick/wren-test): A testing framework. +- [wren-vector3d](https://github.com/EvanHahn/wren-vector3d): 3D vectors. -A few people have also added Wren bindings for other languages: +## Language bindings +Want to host a Wren VM within another language. Try these: + +- [JavaScript: ppvk/wrenjs](https://github.com/ppvk/wrenjs) - [Rust: tilpner/wren-sys](https://github.com/tilpner/wren-sys) - [Rust: pwoolcoc/wren-sys](https://github.com/pwoolcoc/wren-sys) - [Rust: pwoolcoc/wren-rs](https://github.com/pwoolcoc/wren-rs) @@ -30,8 +33,16 @@ A few people have also added Wren bindings for other languages: If you want Wren syntax highlighting in your editor, look no further: -- [Vim](https://github.com/lluchs/vim-wren) - [Emacs](https://github.com/v2e4lisp/wren-mode.el) +- [Sublime Text](https://github.com/munificent/wren-sublime) +- [Vim](https://github.com/lluchs/vim-wren) + +## Tools and Utilities + +Things that make life easier: + +- [The Wren Nest](http://ppvk.github.io/wren-nest/): Run and share Wren in your + browser. Do you have anything to add here? Send a [pull request][]! diff --git a/doc/site/core/io.markdown b/doc/site/core/io.markdown index 70b313c0..054eaf4e 100644 --- a/doc/site/core/io.markdown +++ b/doc/site/core/io.markdown @@ -7,38 +7,54 @@ The IO class can be used to read and write to and from the console. ### IO.**print**(objects...) -Prints any number of things to the console and then prints a newline -character. If you don't pass it a string, it will be converted to a string for -you. When passed multiple things, Wren outputs one after another. +Prints a series of objects to the console followed by a newline. Each object is +converted to a string by calling `toString` on it. This is overloaded to +support up to 16 objects. To pass more, use `printAll()`. + > IO.print("I like bananas") + I like bananas + > IO.print("Oranges", 10) + Oranges10 - > IO.print("I like bananas") - I like bananas - > IO.print("Oranges", 10) - Oranges10 - > +### IO.**printAll**(sequence) + +Iterates over [sequence] and prints each element, then prints a single newline +at the end. Each element is converted to a string by calling `toString` on it. + + > IO.printAll([1, [2, 3], 4]) + 1[2, 3]4 ### IO.**write**(object) -Prints a single thing to the console, but does not print a newline character -afterwards. If you pass it something that isn't a string, it will convert it to -a string. +Prints a single value to the console, but does not print a newline character +afterwards. Converts the value to a string by calling `toString` on it. - > IO.write(4 + 5) - 9> + > IO.write(4 + 5) + 9> In the above example, the result of `4 + 5` is printed, and then the prompt is printed on the same line because no newline character was printed afterwards. +### IO.**read**() + +Reads in a line of text from stdin. Note that the returned text includes the +trailing newline. + + > var name = IO.read() + John + > IO.print("Hello " + name + "!") + Hello John + ! + > + ### IO.**read**(prompt) -Reads in and returns a line of text from the console. Takes a single string to -be used as a prompt. Pass an empty string for no prompt. Note that the returned -line of text includes the newline character at the end. +Displays `prompt` then reads in a line of text from stdin. Note that the +returned text includes the trailing newline. - > var name = IO.read("Enter your name: ") - Enter your name: John - > IO.print("Hello " + name + "!") - Hello John - ! - > + > var name = IO.read("Enter your name: ") + Enter your name: John + > IO.print("Hello " + name + "!") + Hello John + ! + > diff --git a/doc/site/fibers.markdown b/doc/site/fibers.markdown index 5cd71542..f87158e8 100644 --- a/doc/site/fibers.markdown +++ b/doc/site/fibers.markdown @@ -113,7 +113,7 @@ of the `yield()` call: This prints "sent". Note that the first value sent to the fiber through call is ignored. That's because the fiber isn't waiting on a `yield()` call, so there's -no where for the sent value to go. +nowhere for the sent value to go. Fibers can also pass values *back* when they yield. If you pass an argument to `yield()`, that will become the return value of the `call` that was used to diff --git a/doc/site/index.markdown b/doc/site/index.markdown index 75a40a1b..3954ad17 100644 --- a/doc/site/index.markdown +++ b/doc/site/index.markdown @@ -41,8 +41,9 @@ a familiar, modern [syntax][]. and [an easy-to-use C API][embedding]. It compiles cleanly as C99, C++98 or anything later. -If you like the sound of this, [give it a try][try]! Even better, you can -[contribute to Wren itself][contribute]. +If you like the sound of this, [let's get started][started]. You can even try +it [in your browser][browser]! Excited? Well, come on and [get +involved][contribute]! [syntax]: syntax.html [src]: https://github.com/munificent/wren/tree/master/src @@ -51,5 +52,6 @@ If you like the sound of this, [give it a try][try]! Even better, you can [classes]: classes.html [fibers]: fibers.html [embedding]: embedding-api.html -[try]: getting-started.html +[started]: getting-started.html +[browser]: http://ppvk.github.io/wren-nest/ [contribute]: contributing.html diff --git a/script/test.py b/script/test.py index 025567ae..023e9534 100755 --- a/script/test.py +++ b/script/test.py @@ -234,7 +234,7 @@ def color_text(text, color): # No ANSI escapes on Windows. if sys.platform == 'win32': - return text + return str(text) return color + str(text) + '\033[0m' diff --git a/src/vm/wren_common.h b/src/vm/wren_common.h index 4303332c..a8a82108 100644 --- a/src/vm/wren_common.h +++ b/src/vm/wren_common.h @@ -26,7 +26,7 @@ // // Defaults to on. #ifndef WREN_NAN_TAGGING -#define WREN_NAN_TAGGING 1 + #define WREN_NAN_TAGGING 1 #endif // If true, the VM's interpreter loop uses computed gotos. See this for more: @@ -48,14 +48,14 @@ // // Defaults to on. #ifndef WREN_USE_LIB_IO -#define WREN_USE_LIB_IO 1 + #define WREN_USE_LIB_IO 1 #endif // If true, loads the "Meta" class in the standard library. // // Defaults to on. #ifndef WREN_USE_LIB_META -#define WREN_USE_LIB_META 1 + #define WREN_USE_LIB_META 1 #endif // These flags are useful for debugging and hacking on Wren itself. They are not @@ -136,18 +136,18 @@ // The Microsoft compiler does not support the "inline" modifier when compiling // as plain C. #if defined( _MSC_VER ) && !defined(__cplusplus) -#define inline _inline + #define inline _inline #endif // This is used to clearly mark flexible-sized arrays that appear at the end of // some dynamically-allocated structs, known as the "struct hack". #if __STDC_VERSION__ >= 199901L -// In C99, a flexible array member is just "[]". -#define FLEXIBLE_ARRAY + // In C99, a flexible array member is just "[]". + #define FLEXIBLE_ARRAY #else -// Elsewhere, use a zero-sized array. It's technically undefined behavior, but -// works reliably in most known compilers. -#define FLEXIBLE_ARRAY 0 + // Elsewhere, use a zero-sized array. It's technically undefined behavior, + // but works reliably in most known compilers. + #define FLEXIBLE_ARRAY 0 #endif // Assertions are used to validate program invariants. They indicate things the @@ -157,34 +157,46 @@ // Assertions add significant overhead, so are only enabled in debug builds. #ifdef DEBUG -#include + #include -#define ASSERT(condition, message) \ - do \ - { \ - if (!(condition)) \ + #define ASSERT(condition, message) \ + do \ { \ - fprintf(stderr, "[%s:%d] Assert failed in %s(): %s\n", \ - __FILE__, __LINE__, __func__, message); \ + if (!(condition)) \ + { \ + fprintf(stderr, "[%s:%d] Assert failed in %s(): %s\n", \ + __FILE__, __LINE__, __func__, message); \ + abort(); \ + } \ + } \ + while(0) + + // Indicates that we know execution should never reach this point in the + // program. In debug mode, we assert this fact because it's a bug to get here. + // + // In release mode, we use compiler-specific built in functions to tell the + // compiler the code can't be reached. This avoids "missing return" warnings + // in some cases and also lets it perform some optimizations by assuming the + // code is never reached. + #define UNREACHABLE() \ + do \ + { \ + fprintf(stderr, "[%s:%d] This code should not be reached in %s()\n", \ + __FILE__, __LINE__, __func__); \ abort(); \ } \ - } \ - while(0) - -// Assertion to indicate that the given point in the code should never be -// reached. -#define UNREACHABLE() \ - do \ - { \ - fprintf(stderr, "This line should not be reached.\n"); \ - abort(); \ - } \ - while (0) + while (0) #else -#define ASSERT(condition, message) do { } while (0) -#define UNREACHABLE() do { } while (0) + #define ASSERT(condition, message) do {} while (0) + + // Tell the compiler that this part of the code will never be reached. + #if defined( _MSC_VER ) + #define UNREACHABLE() __assume(0) + #else + #define UNREACHABLE() __builtin_unreachable() + #endif #endif diff --git a/src/vm/wren_compiler.c b/src/vm/wren_compiler.c index b768641a..46d021f7 100644 --- a/src/vm/wren_compiler.c +++ b/src/vm/wren_compiler.c @@ -2673,7 +2673,6 @@ static int getNumArguments(const uint8_t* bytecode, const Value* constants, default: UNREACHABLE(); - return 0; } } diff --git a/src/vm/wren_debug.c b/src/vm/wren_debug.c index a631b5e9..cb31f4b8 100644 --- a/src/vm/wren_debug.c +++ b/src/vm/wren_debug.c @@ -9,15 +9,7 @@ void wrenDebugPrintStackTrace(ObjFiber* fiber) for (int i = fiber->numFrames - 1; i >= 0; i--) { CallFrame* frame = &fiber->frames[i]; - ObjFn* fn; - if (frame->fn->type == OBJ_FN) - { - fn = (ObjFn*)frame->fn; - } - else - { - fn = ((ObjClosure*)frame->fn)->fn; - } + ObjFn* fn = wrenGetFrameFunction(frame); // Built-in libraries and method call stubs have no source path and are // explicitly omitted from stack traces since we don't want to highlight to @@ -70,21 +62,21 @@ void wrenDumpValue(Value value) { switch (GET_TAG(value)) { - case TAG_FALSE: printf("false"); break; - case TAG_NAN: printf("NaN"); break; - case TAG_NULL: printf("null"); break; - case TAG_TRUE: printf("true"); break; + case TAG_FALSE: printf("false"); break; + case TAG_NAN: printf("NaN"); break; + case TAG_NULL: printf("null"); break; + case TAG_TRUE: printf("true"); break; case TAG_UNDEFINED: UNREACHABLE(); } } #else switch (value.type) { - case VAL_FALSE: printf("false"); break; - case VAL_NULL: printf("null"); break; - case VAL_NUM: printf("%.14g", AS_NUM(value)); break; - case VAL_TRUE: printf("true"); break; - case VAL_OBJ: printObject(AS_OBJ(value)); break; + case VAL_FALSE: printf("false"); break; + case VAL_NULL: printf("null"); break; + case VAL_NUM: printf("%.14g", AS_NUM(value)); break; + case VAL_TRUE: printf("true"); break; + case VAL_OBJ: dumpObject(AS_OBJ(value)); break; case VAL_UNDEFINED: UNREACHABLE(); } #endif diff --git a/src/vm/wren_io.c b/src/vm/wren_io.c index 8463ca8d..e8813fce 100644 --- a/src/vm/wren_io.c +++ b/src/vm/wren_io.c @@ -6,111 +6,111 @@ #include #include -// TODO: This is an arbitrary limit Do something smarter. +// 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" -" IO.writeString_(\"\n\")\n" +" writeString_(\"\n\")\n" " }\n" "\n" " static print(obj) {\n" -" IO.writeObject_(obj)\n" -" IO.writeString_(\"\n\")\n" +" writeObject_(obj)\n" +" writeString_(\"\n\")\n" " return obj\n" " }\n" "\n" " static print(a1, a2) {\n" -" printList_([a1, a2])\n" +" printAll([a1, a2])\n" " }\n" "\n" " static print(a1, a2, a3) {\n" -" printList_([a1, a2, a3])\n" +" printAll([a1, a2, a3])\n" " }\n" "\n" " static print(a1, a2, a3, a4) {\n" -" printList_([a1, a2, a3, a4])\n" +" printAll([a1, a2, a3, a4])\n" " }\n" "\n" " static print(a1, a2, a3, a4, a5) {\n" -" printList_([a1, a2, a3, a4, a5])\n" +" printAll([a1, a2, a3, a4, a5])\n" " }\n" "\n" " static print(a1, a2, a3, a4, a5, a6) {\n" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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" -" printList_([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 printList_(objects) {\n" -" for (object in objects) IO.writeObject_(object)\n" -" IO.writeString_(\"\n\")\n" +" static printAll(sequence) {\n" +" for (object in sequence) writeObject_(object)\n" +" writeString_(\"\n\")\n" " }\n" "\n" " static write(obj) {\n" -" IO.writeObject_(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" -" IO.write(prompt)\n" -" return IO.read\n" +" write(prompt)\n" +" return read()\n" " }\n" "\n" " static writeObject_(obj) {\n" " var string = obj.toString\n" " if (string is String) {\n" -" IO.writeString_(string)\n" +" writeString_(string)\n" " } else {\n" -" IO.writeString_(\"[invalid toString]\")\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" +" foreign static read()\n" "}\n"; static void ioWriteString(WrenVM* vm) @@ -125,7 +125,8 @@ static void ioRead(WrenVM* vm) char buffer[MAX_READ_LEN]; char* result = fgets(buffer, MAX_READ_LEN, stdin); - if (result != NULL) { + if (result != NULL) + { wrenReturnString(vm, buffer, (int)strlen(buffer)); } } @@ -153,7 +154,7 @@ WrenForeignMethodFn wrenBindIOForeignMethod(WrenVM* vm, const char* className, if (strcmp(signature, "writeString_(_)") == 0) return ioWriteString; if (strcmp(signature, "clock") == 0) return ioClock; if (strcmp(signature, "time") == 0) return ioTime; - if (strcmp(signature, "read") == 0) return ioRead; + if (strcmp(signature, "read()") == 0) return ioRead; return NULL; } diff --git a/src/vm/wren_value.c b/src/vm/wren_value.c index 0ee93d36..843d6589 100644 --- a/src/vm/wren_value.c +++ b/src/vm/wren_value.c @@ -359,13 +359,11 @@ static uint32_t hashValue(Value value) switch (value.type) { case VAL_FALSE: return 0; - case VAL_NULL: return 1; - case VAL_NUM: return hashNumber(AS_NUM(value)); - case VAL_TRUE: return 2; - case VAL_OBJ: return hashObject(AS_OBJ(value)); - default: - UNREACHABLE(); - return 0; + case VAL_NULL: return 1; + case VAL_NUM: return hashNumber(AS_NUM(value)); + case VAL_TRUE: return 2; + case VAL_OBJ: return hashObject(AS_OBJ(value)); + default: UNREACHABLE(); } #endif } diff --git a/src/vm/wren_value.h b/src/vm/wren_value.h index 69dac7b3..26469e05 100644 --- a/src/vm/wren_value.h +++ b/src/vm/wren_value.h @@ -586,10 +586,10 @@ typedef struct #define IS_UNDEFINED(value) ((value).type == VAL_UNDEFINED) // Singleton values. -#define FALSE_VAL ((Value){ VAL_FALSE }) -#define NULL_VAL ((Value){ VAL_NULL }) -#define TRUE_VAL ((Value){ VAL_TRUE }) -#define UNDEFINED_VAL ((Value){ VAL_UNDEFINED }) +#define FALSE_VAL ((Value){ VAL_FALSE, { 0 } }) +#define NULL_VAL ((Value){ VAL_NULL, { 0 } }) +#define TRUE_VAL ((Value){ VAL_TRUE, { 0 } }) +#define UNDEFINED_VAL ((Value){ VAL_UNDEFINED, { 0 } }) #endif @@ -628,6 +628,16 @@ ObjFiber* wrenNewFiber(WrenVM* vm, Obj* fn); // Resets [fiber] back to an initial state where it is ready to invoke [fn]. void wrenResetFiber(WrenVM* vm, ObjFiber* fiber, Obj* fn); +static inline ObjFn* wrenGetFrameFunction(CallFrame* frame) +{ + switch (frame->fn->type) + { + case OBJ_FN: return (ObjFn*)frame->fn; + case OBJ_CLOSURE: return ((ObjClosure*)frame->fn)->fn; + default: UNREACHABLE(); + } +} + // Adds a new [CallFrame] to [fiber] invoking [function] whose stack starts at // [stackStart]. static inline void wrenAppendCallFrame(WrenVM* vm, ObjFiber* fiber, @@ -639,14 +649,7 @@ static inline void wrenAppendCallFrame(WrenVM* vm, ObjFiber* fiber, CallFrame* frame = &fiber->frames[fiber->numFrames++]; frame->stackStart = stackStart; frame->fn = function; - if (function->type == OBJ_FN) - { - frame->ip = ((ObjFn*)function)->bytecode; - } - else - { - frame->ip = ((ObjClosure*)function)->fn->bytecode; - } + frame->ip = wrenGetFrameFunction(frame)->bytecode; } // TODO: The argument list here is getting a bit gratuitous. diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index 1d67f46d..38f44c52 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -613,14 +613,7 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber) frame = &fiber->frames[fiber->numFrames - 1]; \ stackStart = frame->stackStart; \ ip = frame->ip; \ - if (frame->fn->type == OBJ_FN) \ - { \ - fn = (ObjFn*)frame->fn; \ - } \ - else \ - { \ - fn = ((ObjClosure*)frame->fn)->fn; \ - } + fn = wrenGetFrameFunction(frame); // Terminates the current fiber with error string [error]. If another calling // fiber is willing to catch the error, transfers control to it, otherwise @@ -1164,7 +1157,6 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber) // We should only exit this function from an explicit return from CODE_RETURN // or a runtime error. UNREACHABLE(); - return WREN_RESULT_RUNTIME_ERROR; #undef READ_BYTE #undef READ_SHORT diff --git a/src/vm/wren_vm.h b/src/vm/wren_vm.h index 18c9c54f..89a56aca 100644 --- a/src/vm/wren_vm.h +++ b/src/vm/wren_vm.h @@ -195,26 +195,25 @@ static inline ObjClass* wrenGetClassInline(WrenVM* vm, Value value) #if WREN_NAN_TAGGING switch (GET_TAG(value)) { - case TAG_FALSE: return vm->boolClass; break; - case TAG_NAN: return vm->numClass; break; - case TAG_NULL: return vm->nullClass; break; - case TAG_TRUE: return vm->boolClass; break; + case TAG_FALSE: return vm->boolClass; break; + case TAG_NAN: return vm->numClass; break; + case TAG_NULL: return vm->nullClass; break; + case TAG_TRUE: return vm->boolClass; break; case TAG_UNDEFINED: UNREACHABLE(); } #else switch (value.type) { - case VAL_FALSE: return vm->boolClass; - case VAL_NULL: return vm->nullClass; - case VAL_NUM: return vm->numClass; - case VAL_TRUE: return vm->boolClass; - case VAL_OBJ: return AS_OBJ(value)->classObj; + case VAL_FALSE: return vm->boolClass; + case VAL_NULL: return vm->nullClass; + case VAL_NUM: return vm->numClass; + case VAL_TRUE: return vm->boolClass; + case VAL_OBJ: return AS_OBJ(value)->classObj; case VAL_UNDEFINED: UNREACHABLE(); } #endif UNREACHABLE(); - return NULL; } #endif diff --git a/test/benchmark/string_equals.py b/test/benchmark/string_equals.py new file mode 100644 index 00000000..f42947de --- /dev/null +++ b/test/benchmark/string_equals.py @@ -0,0 +1,35 @@ +from __future__ import print_function + +import time +start = time.clock() + +count = 0 +for i in range(0, 1000000): + if "abc" == "abc": + count = count + 1 + if "a slightly longer string" == \ + "a slightly longer string": + count = count + 1 + if "a significantly longer string but still not overwhelmingly long string" == \ + "a significantly longer string but still not overwhelmingly long string": + count = count + 1 + + if "" == "abc": + count = count + 1 + if "abc" == "abcd": + count = count + 1 + if "changed one character" == "changed %ne character": + count = count + 1 + if "123" == 123: count = count + 1 + if "a slightly longer string" == \ + "a slightly longer string!": + count = count + 1 + if "a slightly longer string" == \ + "a slightly longer strinh": + count = count + 1 + if "a significantly longer string but still not overwhelmingly long string" == \ + "another": + count = count + 1 + +print(count) +print("elapsed: " + str(time.clock() - start)) diff --git a/test/io/read_eof.wren b/test/io/read_eof.wren index 07fd65c1..db9045aa 100644 --- a/test/io/read_eof.wren +++ b/test/io/read_eof.wren @@ -1 +1 @@ -IO.write(IO.read) // expect: null +IO.write(IO.read()) // expect: null