740 Commits

Author SHA1 Message Date
ce8d89d18c Merge branch 'master' into templates 2015-10-08 08:06:40 -07:00
8980d34ee5 Only close an upvalue for a local if there actually is one for it. 2015-10-08 08:06:29 -07:00
fbdf504c76 Include the source text for each interpolated expression.
Since we don't have custom interpolaters yet, this isn't exposed to the
user in any way, but that will come next.

Also added some more tests and explicitly limit the amount of
interpolation nesting.
2015-10-07 07:27:03 -07:00
3dfba7c67a Merge branch 'master' into templates 2015-10-05 07:45:47 -07:00
24cbb7f399 Fix closures in methods.
A local name inside a method should always resolve to a self send even
if there is a local variable with that name outside of the method.
2015-10-05 07:44:51 -07:00
24be23a37d "Template" -> "interpolation".
- Rename the method called on string to "interpolate".
- Make the argument passed to that a first-class StringInterpolation
  object.
- Make that contain a list of strings and InterpolatedField objects.

These first-class objects will make it easier to add things like format
strings and the raw uninterpolated text while still having a pleasant
API.
2015-10-04 15:03:25 -07:00
5aa0a5ee41 Merge branch 'master' into templates 2015-10-04 09:19:51 -07:00
e968b4bf98 Fix two typos in the docs. 2015-10-03 21:45:59 -07:00
76d188e018 Get rid of PrimitiveResult.
Primitives still have a return value to indicate normal value returning
versus runtime errors or fiber switching since it minimizes branches
in the common case of a normal value result.
2015-10-03 20:43:12 -07:00
812bc15380 Get rid of the special "call" primitive result type.
Instead, Fn.call(...) is a special *method* type that has the same
special sauce. The goal is eventually to get rid of the primitive
result type entirely.
2015-10-03 19:04:11 -07:00
e41d9eac7c Tweak the embedding docs a bit. 2015-10-02 21:25:55 -07:00
d61d7fd5b4 Don't pass fiber explicitly to primitives.
Thanks, Michel!
2015-10-02 07:51:12 -07:00
b7ed774da3 Reading files!
- File.close()
- File.open()
- File.read()
- file.readBytes()

And a few other little methods. Still lots more work to do, but it's a
start.
2015-09-30 21:13:36 -07:00
bacbd85543 Add .isInfinity and .isInteger to Num. 2015-09-30 08:41:43 -07:00
5129597c63 Unify PRIM_ERROR and PRIM_RUN_FIBER. 2015-09-30 07:32:39 -07:00
b05a74da19 Revamp how runtime errors and fiber switching is handled.
- Add Fiber.transferError(_).
- Primitives place runtime errors directly in the fiber instead of on
  the stack.
- Primitives that change fibers set it directly in the VM.
- Allow a fiber's error to be any object (except null).
2015-09-29 22:57:03 -07:00
79354f5a97 Do some work on wrenCall().
- Add an explicit va_list version. That lets variadic functions
  forward to it.
- Fix a GC bug in wrenCall() with return values.
- Make the call API test not re-enter the VM.
2015-09-29 19:29:10 -07:00
f757c9efac Better embedding API support (and tests!) for strings with null bytes.
- Test that a foreign method can return strings.
- Test that a foreign method can return a string with null bytes.
- Test wrenCall().
- Allow passing NULL for "v" to wrenCall().
- Allow "a" for passing an explicit length byte array to wrenCall().
2015-09-24 08:02:31 -07:00
a944ead5b4 Give the docs some love. 2015-09-22 21:19:38 -07:00
505b48fdac Add a real Pygments lexer for Wren (finally!). 2015-09-22 07:59:54 -07:00
36f7d74183 Unify "script" and "project" under "util". 2015-09-22 07:45:58 -07:00
2f9ba2beaa Merge branch 'buildfix' of https://github.com/krypt-n/wren into krypt-n-buildfix 2015-09-21 19:48:08 -07:00
f6083b1756 Simplify how built-in foreign methods and classes are wired up. 2015-09-21 07:58:39 -07:00
9c92d90374 Use python2 executable for libuv buildscripts
Fixes build for systems with python == python3, as long as a python2
executable exists
2015-09-20 00:49:29 +02:00
8ef4ea6186 Allow super calls in static methods. 2015-09-19 15:19:41 -07:00
b08cadefc0 Fix renamed token type. 2015-09-19 10:09:40 -07:00
46a33a412d String templates (i.e. interpolation).
Still need to do:

- Tagged templates so users can control interpolation.
- Optional format strings.

But basic string interpolation is working now:

System.print("Hi, %(name)! You are %(birth - today) years old.")
2015-09-19 10:07:41 -07:00
19f70b4035 Simplify and optimize how keywords are lexed. 2015-09-17 20:51:24 -07:00
dc527c8d86 Add "io" module with beginnings of a File class. 2015-09-16 07:34:49 -07:00
251752fcfb Make join() require parentheses without a separator. 2015-09-16 07:15:48 -07:00
efceee4320 Let the host application control how System prints text. 2015-09-15 23:01:43 -07:00
58e4d26648 "IO" -> "System".
Get rid of the separate opt-in IO class and replace it with a core
System class.

- Remove wren_io.c, wren_io.h, and io.wren.
- Remove the flags that disable it.
- Remove the overloads for print() with different arity. (It was an
  experiment, but I don't think it's that useful.)
- Remove IO.read(). That will reappear using libuv in the CLI at some
  point.
- Remove IO.time. Doesn't seem to have been used.
- Update all of the tests, docs, etc.

I'm sorry for all the breakage this causes, but I think "System" is a
better name for this class (it makes it natural to add things like
"System.gc()") and frees up "IO" for referring to the CLI's IO module.
2015-09-15 07:46:09 -07:00
66b89a493f Combine io.c and vm.c.
(This is mainly to free up io.c as a built in module.)
2015-09-13 22:29:47 -07:00
ea5c3b01eb Add module for Scheduler.
Also reorganizes some code to make it easier to add more modules.
2015-09-13 11:32:39 -07:00
f36a795534 Automatically update the string constants when a builtin module changes. 2015-09-13 10:03:02 -07:00
e1cf8e22c3 Merge pull request #300 from jesskay/patch-1
Correct platform.system() call
2015-09-12 10:45:18 -07:00
1a27593993 Error if a class tries to inherit from null.
Fix #246.
2015-09-12 10:14:04 -07:00
e1f979e78a Don't use string length in map benchmark (since it's slow now). 2015-09-12 09:59:30 -07:00
92c2b2d5e0 Copy edit the string docs. 2015-09-12 09:42:31 -07:00
fe143644b3 Rationalize string lengths.
The .count getter on string returns the number of code points. That's
O(n), but it's consistent with the rest of the main string API.

If you want the number of bytes, it's "string".bytes.count.

Updated the docs.

Fixes 68. Woo!
2015-09-11 21:33:26 -07:00
c0b5ec9f15 Move codePointAt() to separate CodePointSequence class. 2015-09-11 07:56:01 -07:00
bda9ad880a Flesh out string byte handling a bit:
- Get rid of public byteAt(_) method on strings. It's redundant and
  longer than .bytes[_].
- Implement bytes.count natively so it's O(1).
2015-09-10 23:52:18 -07:00
adcb5bccba Simplify emitConstant().
Thanks, Michel!
2015-09-09 06:44:26 -07:00
1df7565bb9 Fix bug in passing a range as the string subscript. 2015-09-08 20:59:47 -07:00
6330aae20c Correct platform.system() call
An "arch" somehow ended up in the platform.system() call, which takes no arguments.
2015-09-06 02:11:08 +01:00
783a5b750a Get ranges working in string subscripts (again).
Now with UTF-8 hotness!
2015-09-01 22:14:55 -07:00
2e83f056c1 No more default constructors.
Fixes #296.
2015-09-01 08:16:04 -07:00
36f3059e48 Get finalizers working. 2015-08-31 21:56:21 -07:00
1e0a2e6036 Get rid of WrenMethod and just use WrenValue for both.
Thanks, Michel!
2015-08-31 07:57:48 -07:00
1cea3ca3bc Remove redundant ignoreNewlines(). 2015-08-31 07:46:17 -07:00
2b044666ee Reorganize trailing comma code a bit.
- Split out syntax error tests.
- Avoid redundant handling of empty literals.
2015-08-31 07:23:36 -07:00
d7eed08774 Add some tests with invalid trailing commas 2015-08-31 06:41:09 -07:00
b20c9a1b38 Allow trailing comma in list literal 2015-08-31 06:41:09 -07:00
e1d3596643 Allow trailing comma in map literal 2015-08-31 06:41:09 -07:00
6559edbc56 Update docs to mention libuv. 2015-08-30 22:38:40 -07:00
556af50f83 Revise low level fiber semantics to play nicer with schedulers.
Now that I'm starting to write a real async scheduler on top of Wren's
basic fiber API, I have a better feel for what it needs. It turns out
run() is not it.

- Remove run() methods.
- Add transfer() which leaves the caller of the invoked fiber alone.
- Add suspend() to return control to the host application.
- Add Timer.schedule() to start a new independently scheduled fiber.
- Change Timer.sleep() so that it only transfers control to explicitly
  scheduled fibers, not any one.
2015-08-30 22:15:37 -07:00
91af02ac81 Merge branch 'master' into libuv
# Conflicts:
#	project/xcode/wren.xcodeproj/project.pbxproj
#	script/wren.mk
#	src/cli/main.c
#	src/cli/vm.c
#	src/cli/vm.h
#	test/api/main.c
2015-08-28 23:13:56 -07:00
a11450e722 Install g++-multilib for 32-bit std C++ libs on Travis. 2015-08-28 20:25:26 -07:00
647e70a8be Print output when a command fails in libuv.py. 2015-08-28 20:14:55 -07:00
52f7f96813 Get libuv building for all architectures on Linux. 2015-08-28 19:49:19 -07:00
b4deb30a02 Reorganize build scripts for libuv.
- Create separate libs for each architecture. OS X doesn't need this
  (we just build a universal binary), but it will help Linux.
- Move the libuv build stuff into wren.mk where the actual dependency
  on the lib is.
- Download libuv to deps/ instead of build/. That way "make clean"
  doesn't blow it away.
- Don't redownload libuv unless needed.
2015-08-28 19:31:03 -07:00
0ae59be11a Use the same libuv output directory on Mac and Linux. 2015-08-27 07:55:12 -07:00
f33b362cc0 Clean up delta_blue benchmark. 2015-08-27 06:25:24 -07:00
fa4a8148c9 A little bit of code clean-up. 2015-08-22 07:56:38 -07:00
881824227d Don't count "{" or "}" in the line count. 2015-08-22 07:27:32 -07:00
1c941c0258 Make a helper function for matching and consuming a character. 2015-08-21 23:08:11 -07:00
470d2347ff Store number and string literals directly as a Value in the parser.
Thanks, Michel!
2015-08-21 22:54:30 -07:00
eda3f89266 Merge branch 'master' of https://github.com/munificent/wren 2015-08-20 22:34:42 -07:00
610952f727 Update line count in docs. 2015-08-20 22:34:33 -07:00
f433237ff2 Merge pull request #297 from Fedjmike/patch-1
readme: Updated line count
2015-08-20 22:34:08 -07:00
40fbf6112b Use "init " as the prefix for initializers. 2015-08-20 22:30:44 -07:00
ab3c57d518 Merge branch 'still-seeing-this' of https://github.com/minirop/wren into ctor 2015-08-20 22:23:53 -07:00
4d613fc394 Merge branch 'fix-timer-libuv' of https://github.com/Rohansi/wren into timer 2015-08-20 22:09:52 -07:00
147a0815f2 Tweak style. 2015-08-20 22:08:39 -07:00
95ef53e758 Merge branch 'fix-windows-libuv' of https://github.com/Rohansi/wren into win 2015-08-20 22:07:34 -07:00
7be1fb543b Fix test name. 2015-08-20 22:04:42 -07:00
4ab9c06e2c Merge branch 'exponant-notation' of https://github.com/minirop/wren into science 2015-08-20 22:03:19 -07:00
69b0d34065 Start working on docs for the embedding API. 2015-08-20 22:02:13 -07:00
af5b654f4b updated comments where "this" was still used for constructors 2015-08-19 19:33:54 +02:00
ff7ebdc381 Updated line count
The line count is actually around 7,000 (or 11,000 including blanks and comments):

```
~/wren $ cloc src/*/*.{c,h}
      26 text files.
      26 unique files.                              
       0 files ignored.

http://cloc.sourceforge.net v 1.60  T=0.08 s (344.3 files/s, 146330.5 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C                               12           1471           1279           6102
C/C++ Header                    14            380            967            850
-------------------------------------------------------------------------------
SUM:                            26           1851           2246           6952
-------------------------------------------------------------------------------
```
2015-08-18 17:03:11 +01:00
513f272244 Copy the null terminator with the string instead of setting it 2015-08-16 14:00:50 -04:00
cb603f44c2 Properly dispose of libuv timers when we finish using them 2015-08-16 13:58:24 -04:00
0efb943173 Fix timerGetSource() returning a string without a null terminator 2015-08-16 13:58:23 -04:00
cd5087d222 Get 32-bit and C++ Mac builds happy with libuv. 2015-08-16 10:28:55 -07:00
6be1dce49c Link to rtlib too. 2015-08-16 09:59:53 -07:00
214f72ccf1 Put the libs last? 2015-08-16 09:57:47 -07:00
e6b0a89046 Try allowing gnu C99 extensions. 2015-08-16 09:55:50 -07:00
bd3a9ad7c6 Try including libuv as an object instead of linking to it. 2015-08-16 09:40:02 -07:00
1f13416724 Remove libuv.a from the objects list. 2015-08-16 09:36:17 -07:00
572ba7c7da Maybe the order of libraries matters... 2015-08-16 09:16:26 -07:00
9608002d65 Try to get pthreads working on Linux (again...). 2015-08-16 09:07:41 -07:00
c46519eeda Don't use rmtree on Windows if it's going to cause problems 2015-08-16 09:32:38 -04:00
0c539af6ac added scientific notation 2015-08-16 11:50:45 +02:00
9b18d38546 Merge pull request #291 from Rohansi/fix-broken-links
Fixed some broken links in the readme
2015-08-15 19:58:42 -07:00
48bdbc7745 First pass at implementing foreign classes.
Most of the pieces are there:

- You can declare a foreign class.
- It will call your C function to provide an allocator function.
- Whenever a foreign object is created, it calls the allocator.
- Foreign methods can access the foreign bytes of an object.
- Most of the runtime checking is in place for things like subclassing
  foreign classes.

There is still some loose ends to tie up:

- Finalizers are not called.
- Some of the error-handling could be better.
- The GC doesn't track how much memory a marked foreign object uses.
2015-08-15 12:07:53 -07:00
7a79b8fac6 Simplify the API tests.
Use fewer test suites with more tests in each one since there's so much
boilerplate for defining an API test.
2015-08-13 09:09:27 -07:00
ad60a7e46e Update project files to build with libuv and the timer module 2015-08-13 01:39:34 -04:00
607b91d023 Fixed some broken links in the readme 2015-08-12 22:40:55 -04:00
8e791c70c0 Getting farther... 2015-08-08 09:14:52 -07:00
0c5c291d85 Try to make Linux and libuv love each other. 2015-08-08 09:06:40 -07:00
eaaaca7cd2 Enable POSIX extensions when compiling stuff that uses libuv. 2015-08-08 08:57:57 -07:00
8d90e093ea Try to get libuv working on Linux (again).
It seems to want to build to a different output directory on Mac and
Linux. I can't fix that, so just make our Makefile accommodate.
2015-08-08 07:40:27 -07:00
bb7485d46b Use the same libuv build directory on Linux. 2015-08-08 07:20:07 -07:00
9845ed5126 Tests for Timer.sleep(). 2015-08-08 07:17:30 -07:00
d4acbe8a70 A vertical slice of real libuv integration.
This adds a "timer" module to the CLI that provides a Timer class with
a static sleep() method. Not the most exciting functionality in the
world, but it requires the full hunk of libuv integration:

- The CLI sets up libuv and runs the event loop.
- Added a new directory src/module for CLI modules.
- Updated all the make scripts to handle it.
- Reorganized some other CLI code.
2015-08-07 08:10:55 -07:00
254729d067 Merge branch 'master' into libuv 2015-08-07 07:57:32 -07:00
56d4d3e671 Allow passing WrenValues to wrenCall(). 2015-08-07 07:57:23 -07:00
07615ed1f2 Merge branch 'master' into libuv 2015-08-06 23:15:55 -07:00
0b97b27cf4 Add an API for storing handles to values outside of the VM.
It's pretty bare bones now, but it lets you get a reference to an object
from a foreign call and then return it later.
2015-08-06 22:24:15 -07:00
59ff15d26a Merge branch 'master' into libuv 2015-08-06 21:37:13 -07:00
a1424f8371 Be more explicit about fulling initializing Signature structs.
Thanks, Michel!
2015-08-06 07:34:19 -07:00
d18ee3068a Make wrenFindVariable() also take a module.
Thanks, Michel!
2015-08-06 07:13:11 -07:00
0631f3b109 Fix deadlock bug in map insertion. 2015-08-06 06:55:30 -07:00
d995dc894c Set working directory for Linux libuv compile. 2015-08-02 10:58:27 -07:00
30752b26be First pass at compiling libuv on Linux. 2015-08-02 10:56:44 -07:00
4a6d7e0428 Integrate libuv into Wren.
- Add a script that downloads and compiles libuv.
- Hook that up to the Makefile so it pulls down libuv on build.
- Add a separate "vm" target that just builds the VM library and skips
  libuv.
- Link to libuv when compiling the CLI.
- Update the XCode project to link to libuv too.

Linux and Windows support isn't done yet, but it should be pretty
straightforward to add to the Python script.
2015-08-02 10:43:38 -07:00
71ab3ca887 Use "construct" instead of "this" to define constructors. 2015-07-21 07:24:53 -07:00
ed8ec262e4 Fix example in README. 2015-07-20 07:34:30 -07:00
bc822cd4c7 Merge branch 'master' into constructor-methods 2015-07-19 12:49:23 -07:00
6ece2c173b More test runner fixes. 2015-07-19 10:31:55 -07:00
71eda0e427 Make an inline function for getting the fn for a call frame.
Thanks, Michel!
2015-07-19 10:16:54 -07:00
e42893fe4c Clean up macros and fix non-nan-tagged and non-computed-goto modes. 2015-07-19 10:16:27 -07:00
1b27d556e0 Fix bug in test runner. 2015-07-19 09:33:00 -07:00
214794db67 Fix a tiny typo. 2015-07-19 09:10:42 -07:00
fd637e46bc Fix a couple of style nits. 2015-07-18 14:17:39 -07:00
d91c06d18b Tweak IO library a bit:
- Reword some docs.
- Make IO.printAll() public.
- Require () on read.
2015-07-18 14:09:00 -07:00
ea2bad3272 Merge pull request #286 from BarabasGitHub/string_equals-py
Added string_equals.py to benchmarks
2015-07-18 11:21:49 -07:00
c095b72976 Reorganize community docs a bit. 2015-07-18 11:19:52 -07:00
f7d3c85329 added links on the community page to 'wrenjs' and 'wren-nest' 2015-07-15 17:40:12 -05:00
df6b5cfde1 Added string_equals.py 2015-07-10 19:40:10 +02:00
18165db204 Update Travis config to allow container-based builds. 2015-07-10 10:35:25 -07:00
861d906fc2 Ensure signature type is correctly initialized. 2015-07-10 10:27:32 -07:00
a389fdea67 Fix implicit conversion. 2015-07-10 09:22:04 -07:00
5fb6186d7d Make constructors just methods.
* Eliminate "new" reserved word.
* Allow "this" before a method definition to define a constructor.
* Only create a default constructor for classes that don't define one.
2015-07-10 09:18:22 -07:00
0ddaa2517c Merge branch 'fix-tests' 2015-07-09 08:09:19 -07:00
fa8ac84a8b Fix broken test runner (!).
If a test expected an error and found at least one, it would not fail
on any other expected errors that didn't occur.

Also, some tests were expecting a compile time error message even though
the test script doesn't validate those (yet).

The test function was getting monolithic, so I went ahead and split it
into a separate little class.
2015-07-09 08:06:33 -07:00
8b445447e4 Merge pull request #281 from sbrl/master
Add myself to the AUTHORS and correct a small typo
2015-07-01 16:07:51 -07:00
31c761ecbd Add myself to the AUTHORS and correct a small typo 2015-07-01 18:48:04 +01:00
a44e07deba Some minor doc cleanups and tweaks. 2015-07-01 08:11:10 -07:00
70cc371379 Merge pull request #275 from sbrl/master
Document the IO class
2015-07-01 06:44:27 -07:00
2387d4dc31 Grow the call frame array dynamically.
Previously, fibers had a hard-coded limit to how big their stack size
is. This limit exists in two forms: the number of distinct call frames
(basically the maximum call depth), and the number of unique stack
slots.

This fixes the first half of this by dynamically allocating the call
frame array and growing it as needed. This makes new fibers smallers
since they can start with a very small array. Checking and growing as
needed doesn't noticeably regress the perf on the other benchmarks, and
it makes a new fiber benchmark about 45% faster.

The stack array is still hardcoded, but that will be in another commit.
2015-07-01 00:00:25 -07:00
18dcd3ce3d Reuse primitive for returning this.
Thanks, Michel!
2015-06-30 07:39:43 -07:00
4a15653c66 Add isEmpty to Sequence.
Thanks, Michel and Thorbjørn!
2015-06-30 06:52:29 -07:00
ed6d7c5084 Implement toString directly on Class.
Thanks, Michel!
2015-06-28 15:33:37 -07:00
70d6753374 Renamed temporary filename to actual filename 2015-06-28 19:45:55 +01:00
ffddc579fd Fixed IO title and renamed file to temporary name 2015-06-28 19:45:08 +01:00
1a87f52e9d Eliminate duplication between CODE_CALL and CODE_SUPER handling.
Also improves perf:

binary_trees - wren            106.96% relative to baseline
delta_blue - wren               99.84% relative to baseline
fib - wren                     114.97% relative to baseline
for - wren                     123.32% relative to baseline
method_call - wren             112.80% relative to baseline
map_numeric - wren             111.36% relative to baseline
map_string - wren               93.73% relative to baseline
string_equals - wren           106.15% relative to baseline
2015-06-28 10:58:48 -07:00
080514cffb Tweak arguments to runInterpreter().
Thanks, Michel!
2015-06-27 08:56:52 -07:00
aa37bdc780 Include method name in block argument debug name. 2015-06-27 08:36:20 -07:00
bf730bb953 More tests for invalid code points. 2015-06-27 08:11:58 -07:00
88e209132e Updated to match standard style conventions. 2015-06-27 12:50:29 +01:00
7baef81a4e Clean up a bit. 2015-06-26 23:01:07 -07:00
8c538e4048 Merge branch 'leaks' of https://github.com/NomAnor/wren into NomAnor-leaks 2015-06-26 22:49:24 -07:00
3196735f39 Add block arguments and operators to syntax example. 2015-06-26 22:14:32 -07:00
8ce4879de5 Clean up getting modules.
Thanks, Michel!
2015-06-23 07:15:22 -07:00
2c95ae2d2e Make "is" just another infix operator.
Thanks, Michel!
2015-06-19 07:58:07 -07:00
327b40bba7 Remove unnecessary null checks before calling wrenMarkObject().
Thanks, Michel!
2015-06-18 07:52:05 -07:00
291ddf3961 Merge pull request #271 from BarabasGitHub/vs-proj
Fixed project files for visual studio.
2015-06-18 07:37:58 -07:00
01fe9c3976 Fix memory leak for rootDirectory variable
The memory for the root directory path is not freed.
2015-06-03 21:48:26 +02:00
33151c64d2 Fix memory leak for compiler constants
The ownership for constants is not transfered to the new function so the
constant buffer must be cleared when the compiler is finished.
2015-06-03 21:47:16 +02:00
0add2195f3 realloc is not a valid implementation for the wren reallocation function
The behavior of realloc for size == 0 is implementation defined.
It can return a non NULL pointer which must not be dereferenced but nether
the less must be freed. When calling the wren reallocation function with
size == 0 the memory pointed to ptr must be freed and NULL returned.
2015-06-02 20:57:41 +02:00
73a2101505 Merge branch 'fix-super' 2015-06-02 07:33:48 -07:00
3cdfaea797 Statically dispatch super() calls. Fix #250. 2015-06-02 07:33:39 -07:00
08f0937f89 Fix NaN tagging diagrams. 2015-06-02 07:14:19 -07:00
01ef6e4198 Added link to IO class to core template 2015-05-30 16:12:13 +01:00
0dab2f4be4 Added link to IO class documentation to core index 2015-05-30 16:11:26 +01:00
d3e12980d4 Attempted to document the IO class 2015-05-30 16:10:14 +01:00
3fd63eb2a5 Create IO.markdown 2015-05-29 10:40:16 +01:00
06feba4861 Merge branch 'master' into fix-super 2015-05-27 06:57:20 -07:00
d66556b713 Add API tests for returning null or numbers. 2015-05-24 10:04:24 -07:00
6c135e9941 Show number of expectations in test output. 2015-05-24 09:45:52 -07:00
bbbc85cb66 Merge pull request #273 from munificent/api-test
Add infrastructure to test embedding API.
2015-05-24 09:29:25 -07:00
7084d6bfd5 Add infrastructure to test embedding API. 2015-05-24 09:23:30 -07:00
ac69ae4bb8 Fixed project files for visual studio. 2015-05-23 19:15:58 +02:00
852c837435 Merge pull request #268 from zeckalpha/test-example
Run examples as tests. Would have prevented #266
2015-05-23 08:32:33 -07:00
5ad94fb4da Add ignored to walk() in test.py to clean up list of test dirs. 2015-05-21 09:17:40 -05:00
fc7612c843 Run examples as tests. Would have prevented #266 2015-05-20 10:10:40 -05:00
a114f34a2a Remove outdated set example. Fix #266. 2015-05-20 07:07:47 -07:00
16d5c4441c Merge branch 'master' of https://github.com/munificent/wren 2015-05-19 07:00:57 -07:00
3be0a396c4 Remove unneeded line from Makefile. 2015-05-19 07:00:44 -07:00
9ccefc6af3 Merge pull request #262 from lluchs/syntax-example
Add syntax example file
2015-05-19 06:58:12 -07:00
e861b86563 Revert 40897f3348.
It leaks memory in the case of runtime errors.
2015-05-19 06:50:17 -07:00
8834dcfe1d Add (failing) tests. 2015-05-19 06:47:42 -07:00
be5a42dc22 Add function to grow a buffer by more than one element. 2015-05-05 06:54:13 -07:00
40897f3348 Don't stackoverflow on recursive lists and maps. Fix #3. 2015-05-03 11:13:05 -07:00
3f06553f7f Allow fibers as map keys. 2015-05-03 11:12:17 -07:00
fcf4197139 Add Object.same(_,_) to access built-in equality even for classes that may override ==.
Had to add a new metaclass for Object since it now has its own static method so we
can't just use Class as its metaclass. (We don't want *every* class to have a same(_,_)
static method.)
2015-05-01 07:55:28 -07:00
a907c143c8 Test referring to lowercase class name inside class.
Fix #251.
2015-04-25 10:47:55 -07:00
47d0ba951f Merge pull request #261 from EvanHahn/patch-1
Add Evan Hahn to AUTHORS
2015-04-25 09:34:57 -07:00
abdb2727e9 Add Evan Hahn to AUTHORS 2015-04-25 11:19:55 -05:00
f132f59649 Add syntax example file 2015-04-25 18:10:17 +02:00
1c5a2b03c1 Copy edit a bit. 2015-04-25 08:48:06 -07:00
e0ceb87975 Merge branch '257-community' of git://github.com/EvanHahn/wren into EvanHahn-257-community 2015-04-25 08:39:43 -07:00
30ccadd896 Merge branch 'master' of https://github.com/munificent/wren 2015-04-25 08:39:04 -07:00
bead9a3406 Output amalgamation into build/. 2015-04-25 08:38:45 -07:00
f0d1b73fa3 Add a Community page
Closes #257.
2015-04-23 17:46:18 -05:00
f07e38f40a Merge branch 'amalgamation' of git://github.com/lluchs/wren into lluchs-amalgamation 2015-04-23 07:27:32 -07:00
4147ef2500 Merge pull request #259 from minirop/import-keyword
added missing "import" keyword
2015-04-22 07:46:13 -07:00
7c1ede0a3d Merge branch 'master' of https://github.com/munificent/wren 2015-04-22 07:45:39 -07:00
bfce24151e Tweak docs. 2015-04-22 07:45:20 -07:00
fea844382f Merge branch 'doc-todos' of git://github.com/gsmaverick/wren into gsmaverick-doc-todos 2015-04-22 07:22:42 -07:00
9f30400b7d Merge pull request #258 from patriciomacadden/fix-typo
fix typo: orde => order
2015-04-22 07:21:13 -07:00
732dd18019 Merge pull request #256 from bjorn/toList_docs
Some documentation updates
2015-04-22 07:19:00 -07:00
701e97510a added missing "import" keyword 2015-04-19 23:13:40 +02:00
c3497ee840 Code review changes. 2015-04-19 13:32:15 -07:00
512500be17 fix typo: orde => order 2015-04-17 23:13:36 -03:00
796639e371 Fix amalgamation to work with X Macro files 2015-04-16 14:45:22 +02:00
bc7bf2a09f Print LICENSE on top of the amalgamation 2015-04-16 14:45:22 +02:00
c44be6418b Add comments for file start/end 2015-04-16 14:45:22 +02:00
9bcf31e14d Add amalgamation generation script 2015-04-16 14:45:22 +02:00
4dad9cd688 Make builtin statics unambigous 2015-04-16 14:45:22 +02:00
8d90333ebc #undef some macros which are redefined elsewhere 2015-04-16 14:44:41 +02:00
fdf459b1a5 Make callFunction() unique 2015-04-16 13:01:54 +02:00
d59031d614 Some documentation updates
Some Sequence.list references remained after it was renamed to
Sequence.toList.
2015-04-06 17:21:32 +02:00
e4f3072460 Merge branch 'master' of https://github.com/munificent/wren 2015-04-06 06:53:59 -07:00
ef06eed680 Minor clean-ups. 2015-04-06 06:53:53 -07:00
94f7993bd2 Merge pull request #255 from patriciomacadden/add-myself-to-authors
Add myself to AUTHORS
2015-04-06 06:45:11 -07:00
6d2cbcf3b6 Add myself to AUTHORS 2015-04-05 19:52:12 -03:00
d0bebbd380 Add docs for fiber.call. 2015-04-04 16:50:40 -07:00
1cd83eccbc Add docs for fn.call. 2015-04-04 15:29:10 -07:00
e754fcc49f Add docs for list.insert. 2015-04-04 15:23:16 -07:00
bb3de9eeba Don't confuse the GC if a collection occurs after a compile error. 2015-04-03 23:12:14 -07:00
82ce1d8be9 Fix up Meta.eval(_).
- Made it use primitives instead of foreign functions.
- This fixed an issue where the interpreter loop was running re-entrantly.
- Which in turn fixed a GC bug.
- Report a runtime error if the argument isn't a string.
- Report a runtime error if the source doesn't compile.
2015-04-03 21:22:58 -07:00
9ffdc09672 Merge pull request #252 from lluchs/broken-link
Fix broken link to wren.h
2015-04-03 18:51:21 -07:00
455196db81 Merge pull request #249 from lluchs/clang-absolute-value
Fix warning in clang 3.5 (-Wabsolute-value)
2015-04-03 18:38:10 -07:00
62e76a5780 Fix broken link to wren.h 2015-04-04 00:51:42 +02:00
75a3051fae .list -> .toList
Fix #248.
2015-04-03 11:22:34 -07:00
563a090865 Push more core class creation into the core library itself. 2015-04-03 08:00:55 -07:00
278f1c063b Merge branch 'refactoring' of git://github.com/patriciomacadden/wren into patriciomacadden-refactoring 2015-04-03 07:19:17 -07:00
45fc872214 Fix warning in clang 3.5 (-Wabsolute-value) 2015-04-01 17:42:20 +02:00
b46828e93e Update docs for map(_) and where(_). 2015-04-01 07:31:15 -07:00
f4a836c66e Merge branch 'deferred_execution' of git://github.com/bjorn/wren into bjorn-deferred_execution
Conflicts:
	builtin/core.wren
	src/vm/wren_core.c
2015-04-01 07:22:02 -07:00
561d46ef1d Merge pull request #241 from bjorn/sequence_each
Added Sequence.each
2015-04-01 07:10:21 -07:00
92a054f76a Don't make locals in scope in their own initializer. 2015-04-01 07:05:40 -07:00
2256448017 Fix whitespace. 2015-04-01 06:43:44 -07:00
c826348c2b Merge pull request #247 from ComFreek/patch-2
Fixed char-subscripts warning
2015-04-01 06:42:38 -07:00
fca4e3d9e2 refactor defineSingleClass and defineClass 2015-03-31 22:58:55 -03:00
a8ea2a91a6 Use deferred execution for Sequence.map and Sequence.where
The methods Sequence.map and Sequence.where are now implemented using
deferred execution. They return an instance of a new Sequence-derived
class that performs the operation while iterating. This has three main
advantages:

* It can be computationally cheaper when not the whole sequence is
  iterated.

* It consumes less memory since it does not store the result in a newly
  allocated list.

* They can work on infinite sequences.

Some disadvantages are:

* Iterating the returned iterator will be slightly slower due to
  the added indirection.

* You should be aware that modifications made to the original sequence
  will affect the returned sequence.

* If you need the result in a list, you now need to call Sequence.list
  on the result.
2015-03-31 22:25:07 +02:00
c00d6ad694 Added Sequence.each
This is a bit of a style preference since of course you can always write
the same thing with a for loop. However, I think sometimes the code
looks better when using this method.

It also provides an alternative to Sequence.map for cases where you
don't need the resulting list, and one that becomes especially necessary
when Sequence.map is changed to return a new sequence. The example in
the README.md file was using Sequence.map in a way that required this
alternative in that case.
2015-03-31 21:53:29 +02:00
2a26ceeea7 Fixed char-subscripts warning 2015-03-31 18:27:44 +02:00
13c519d0be Merge branch 'master' of https://github.com/munificent/wren 2015-03-30 07:39:37 -07:00
9bdbc05be1 Flush benchmark output after each ".".
Thanks, Michel!
2015-03-30 07:39:21 -07:00
54ee4987d1 Merge pull request #242 from patriciomacadden/fix-function-call
Fix wrong function call
2015-03-28 18:08:51 -07:00
515b9317c7 Fix wrong function call 2015-03-28 17:01:21 -03:00
37e1e8fe77 Remove outdated comment. 2015-03-28 10:19:38 -07:00
07f9d4d2be Tweak Sequence.all() and Sequence.any().
When possible, they return the actual value from the predicate
instead of always just "true" and "false". This matches && and ||
which evaluate to the RHS or LHS when appropriate.
2015-03-28 10:18:45 -07:00
a7fafce265 Pull out opcode definitions into an X-macro file. 2015-03-28 09:56:07 -07:00
6254a2e15e Invert the return value for finishBloc().
Thanks, Michel!
2015-03-28 09:15:19 -07:00
53ee453f0f Merge pull request #239 from bjorn/sequence_list
Added Sequence.list
2015-03-28 09:06:49 -07:00
5bb3154e83 Copy editing. 2015-03-27 20:59:15 -07:00
72c38a59ce More stuff for working with strings and bytes!
- "\x" escape sequence to put byte values in strings: "\x34"
- String.byteAt(index) gets value of byte in string.
- String.bytes returns a raw sequence of bytes for a string.
- String.codePointAt(index) gets the code point at an offset as a raw number.
2015-03-27 20:44:07 -07:00
b409569b6f Added Sequence.list
This helper method turns any sequence into a List.
2015-03-27 22:59:58 +01:00
7d45dda383 String.fromCodePoint(). Fix #219. 2015-03-27 07:43:36 -07:00
373770a8d5 Fields are private, not protected. Fix #237. 2015-03-27 06:46:12 -07:00
322eea1af5 Generate a runtime error if a foreign method was not found. 2015-03-26 07:17:09 -07:00
9c414b5da5 Get Meta working with foreign methods. 2015-03-25 20:20:26 -07:00
8dcd336638 Merge branch 'master' into foreign-methods 2015-03-25 20:06:55 -07:00
35d0da92b9 Merge branch 'master' of https://github.com/munificent/wren 2015-03-25 19:25:37 -07:00
c707135b9a Add wren_meta to XCode project. 2015-03-25 19:25:18 -07:00
d99a82e6d8 Merge branch 'meta-library' of git://github.com/gsmaverick/wren into gsmaverick-meta-library 2015-03-25 19:21:58 -07:00
1776c329db Merge pull request #235 from bjorn/master
Added myself to the AUTHORS file
2015-03-25 19:15:58 -07:00
6b9c162fe9 Added myself to the AUTHORS file 2015-03-26 00:01:39 +01:00
e4a785a071 Remove oldSize from allocate API.
binary_trees - wren            .......... 0.29s 0.0048 107.79% relative to baseline
delta_blue - wren              .......... 0.12s 0.0017 106.95% relative to baseline
fib - wren                     .......... 0.30s 0.0042 119.95% relative to baseline
for - wren                     .......... 0.12s 0.0020 107.57% relative to baseline
method_call - wren             .......... 0.15s 0.0256 106.09% relative to baseline
map_numeric - wren             .......... 0.44s 0.0199 105.27% relative to baseline
map_string - wren              .......... 0.14s 0.0049 100.18% relative to baseline
string_equals - wren           .......... 0.30s 0.0032 100.57% relative to baseline

Thanks, Michel!
2015-03-25 07:45:29 -07:00
8c4e5eeea8 Show standard deviation and other tweaks in benchmark script. 2015-03-25 07:26:45 -07:00
31d2989565 Remove unnecessary headers. 2015-03-24 23:30:53 -07:00
0bd19da392 Bind C methods to Wren using foreign declarations. 2015-03-24 07:58:15 -07:00
82fceb8361 Give makefile prettier output. Pretty! 2015-03-24 07:51:48 -07:00
c9226256ff Merge pull request #220 from bjorn/count_predicate
Added Sequence.count(predicate)
2015-03-23 07:35:17 -07:00
89ebffb582 Rearrange a bit. 2015-03-23 06:48:08 -07:00
0484accb2d Merge branch 'module-index' of git://github.com/gsmaverick/wren into gsmaverick-module-index 2015-03-23 06:42:03 -07:00
d8770b9a6a Clean up the .gitignore a bit. 2015-03-23 06:33:29 -07:00
2624d08a79 Merge branch 'master' of git://github.com/bncastle/wren into bncastle-master 2015-03-23 06:32:29 -07:00
d168eafeb6 Upvalue -> ObjUpvalue.
This is consistent with ObjModule which also is an Obj
even though it isn't first class in the language.
2015-03-22 22:31:03 -07:00
a4df577903 Get rid of some unused parameters. 2015-03-22 22:17:40 -07:00
d438edc8d0 Remove some redundant warnings settings. 2015-03-22 22:17:29 -07:00
efa6f32d25 Merge branch 'w-extra' of git://github.com/verpeteren/wren into verpeteren-w-extra 2015-03-22 21:49:31 -07:00
a937bd1cf9 Adds a Meta library with an eval function for interpreting code inline. 2015-03-22 14:17:02 -07:00
dd4691649a Convert Compiler and ObjList to both use ValueBuffer for their arrays. 2015-03-22 12:22:47 -07:00
2dfec85506 Enable clang warning on suspicious implicit conversions. 2015-03-22 10:36:08 -07:00
f732ada5ea Fix unreachable code in REPL. 2015-03-22 10:27:38 -07:00
1e493c9061 Hoist instance testing out of the main interpreter loop.
Thanks, Michel!
2015-03-21 16:50:27 -07:00
91c69ccbf0 If module name does not specify a file try to load it as a module package instead. 2015-03-21 16:05:02 -07:00
f2c5c804a4 Refactor out a lot of boilerplate in core. 2015-03-21 14:57:43 -07:00
1301410142 Merge branch 'num_methods' of git://github.com/bjorn/wren into bjorn-num_methods 2015-03-21 12:54:08 -07:00
b522f35b0a Ensure step is always initialized. 2015-03-21 12:32:31 -07:00
3445c6a2cb Finish making code for working with lists use unsigned ints. 2015-03-21 12:22:04 -07:00
98dbde5b1b Merge branch 'int-types' of git://github.com/verpeteren/wren into verpeteren-int-types 2015-03-21 08:46:01 -07:00
f6cf78c175 Assert instead of silently handling freed VM. 2015-03-20 08:00:52 -07:00
1883ae81cd Merge branch 'free-vm' of git://github.com/verpeteren/wren into verpeteren-free-vm 2015-03-20 07:56:32 -07:00
07951bbeae Added Num.pi and some tests 2015-03-19 21:12:50 +01:00
94804fe1a0 Added Sequence.count(predicate)
Returns the number of elements in the sequence that pass the
`predicate`.

It could also have been implemented as:

  count(f) { reduce(0) {|a, b| f.call(b) ? a + 1 : a } }

But I considered the simple version more readable.

Also documented Sequence.count.
2015-03-19 21:10:05 +01:00
da112dd136 Changed Visual Studio solution to output into build/vs
Changed Visual Studio solution to output into build/vs
2015-03-19 10:52:48 -04:00
5e1ddb7db5 Hash entire string. 2015-03-19 07:38:05 -07:00
30367fcdd2 Merge branch 'master' of https://github.com/munificent/wren 2015-03-19 07:29:07 -07:00
1b6a2684e2 Do a little clean-up/reorganization on wren_value.h. 2015-03-19 07:28:53 -07:00
3974d8101d Merge pull request #223 from bjorn/master
Fixed the source locations used by script/generate_builtins.py
2015-03-18 07:55:18 -07:00
a3abf31da0 Merge pull request #222 from bjorn/sequence_contains
Moved List.contains to Sequence.contains, added tests and docs
2015-03-18 07:54:55 -07:00
3383d06ca3 Merge pull request #213 from RickGlimmer/master
Fix unreachable links for IE11 (edge mode)
2015-03-18 07:52:31 -07:00
be11d09bd8 Store hash code in strings.
Makes string equality and string map keys much faster.
Also did some other general string clean-up.
2015-03-18 07:09:03 -07:00
b80ba29b0e Merge branch 'master' of https://github.com/munificent/wren 2015-03-17 07:01:09 -07:00
b4fa4acce1 Handle empty string map keys. 2015-03-17 07:00:54 -07:00
bc52292b6d Changed int-fields in ObjList to match the uint32_t-types in ObjMap
Both ObjList and ObjMap have the same fields (capacity and count). Therefor it makes sense to make them the same type.
2015-03-17 07:29:19 +01:00
9f32de7047 Added -Wextra to compile flags
-Wextra does several extra checks during the compiling. Unfortunately one of the extra check is for unused parameters.
Several functions have unused parameters (mostly the WrenVM* vm).
2015-03-17 07:29:09 +01:00
26586bfa11 Added a check for allready freed in wrenFreeVm.
If wrenFreeVm was called twice, this would lead to an error, because the memory was allready freed.
The used check is rather naive, suggesting that a valid vm does have at least one methodName set.
2015-03-17 07:28:50 +01:00
7514bb9dd3 Visual Studio Project Modifications
- Visual Studio: Fixed project to work with changes made to separate
Wren's cli and file loading code
- Visual Studio: Added another project to the solution that builds Wren
as a static library, and modified the original VS project to use it.
2015-03-16 14:52:33 -04:00
b9f034b398 Merge pull request #224 from bjorn/list_insert_args
Reverse the argument order of List.insert
2015-03-16 09:18:59 -07:00
c3f43e3f70 Merge pull request #226 from bncastle/master
Fix Visual Studio project so it builds
2015-03-16 09:16:54 -07:00
eed7d406da Merge remote-tracking branch 'munificent/master' 2015-03-16 10:56:14 -04:00
91a23da5b0 Move CLI script running to a separate file.
(This is set up to reuse this code for API tests.)
2015-03-16 07:42:45 -07:00
aedf9a8571 Move CLI file loading code to separate file. 2015-03-16 07:22:52 -07:00
09f266c23f Fix typo in wrenDumpObject().
Thanks, Michel!
2015-03-16 07:05:40 -07:00
75d0ce271f Fixed Visual Studio include path 2015-03-16 09:41:51 -04:00
e315ed9265 Fixed file locations for Visual Studio project
- Fixed source file locations for Visual Studio Solution
- Modified .gitignore to ignore Visual Studio cache files
2015-03-16 09:30:16 -04:00
cd0a0da36f Add some missing arguments. 2015-03-15 23:17:08 -07:00
9764b165b4 Try different expansion for CONST_STRING macro. 2015-03-15 23:07:20 -07:00
034ab3c2af Clean up code for creating strings in the VM. 2015-03-15 22:32:20 -07:00
b7081c36b4 Update metrics script to new file layout. 2015-03-15 22:07:06 -07:00
d7a91117ac Reverse the argument order of List.insert
The previous order, insert(element, index), was counter-intuitive.
I'm not aware of any list API that uses this order. I've checked:

* Ruby Array.insert(index, obj...)
* JavaScript array.splice(start, deleteCount[, item1[, item2[, ...]]])
* C++ / QList::insert(int i, const T & value)
* C++ / std::vector::insert
* Lua table.insert (list, [pos,] value)
* C# List<T>.Insert(int index, T item)
* Java Interface List<E>.add(int index, E element)
* Python list.insert(i, x)

So it seemed to me more like an oversight in Wren.
2015-03-15 22:51:24 +01:00
287c611260 Clean up debug dump code. 2015-03-15 10:09:43 -07:00
1616df63d2 Clean up file loading code. 2015-03-15 10:09:22 -07:00
1099c75c77 Added Num.atan(x)
Maps to the C function atan2.
2015-03-15 16:43:02 +01:00
42dd7cdad4 Added more goniometry Num methods
Num.acos
Num.asin
Num.atan
2015-03-15 16:29:56 +01:00
09bcf5ad98 Added Num.tan
Strange omission with Num.sin and Num.cos already available.
2015-03-15 16:29:56 +01:00
fc1dc4c54b Moved List.contains to Sequence.contains, added tests and docs 2015-03-15 15:59:42 +01:00
aebc7c08b0 Fixed the source locations used by script/generate_builtins.py 2015-03-15 15:55:51 +01:00
92c17e81f6 Reorganize source files.
This makes it clear which files are part of the VM (i.e. the Wren library)
and which are part of the CLI. Makes a directory for the latter so it has
some room to grow.

This probably totally broke the VS project. If you can fix that, send me
a PR!
2015-03-14 15:00:50 -07:00
64eccdd9be Reorganize tests and benchmark scripts.
Mainly to get rid of one top level directory. But this will
also be useful when there are tests of the embedding API.
2015-03-14 12:45:56 -07:00
e2a72282a1 Move gh-pages directory under build/. 2015-03-14 12:19:03 -07:00
d1b48a7213 Ugh, fix test script. 2015-03-14 09:49:55 -07:00
5459993857 Add Class.supertype.
Thanks, Michel!
2015-03-14 09:48:45 -07:00
26fb5eb525 Simplify WrenVM initialization. 2015-03-14 09:36:27 -07:00
34213ddc8a Clean up debug trace macros.
Thanks, Michel!
2015-03-14 09:29:17 -07:00
db9e5737f6 Handle malformed UTF-8 output in test runner.
Thanks, Michel!
2015-03-14 08:47:31 -07:00
f7849244a8 Tighten up operator table a bit. 2015-03-13 07:56:47 -07:00
69567c5eb5 Control string representation of infinity. 2015-03-13 07:35:10 -07:00
3ac7d80af5 Cast size_t arguments to printf(). 2015-03-13 07:27:11 -07:00
46aaff03bc Clean up debug header preamble. 2015-03-13 07:26:42 -07:00
3ff56d48ee Normalize path handling on Windows in test script. 2015-03-13 07:26:23 -07:00
e6f3ee9191 Merge branch 'master' of https://github.com/munificent/wren 2015-03-13 07:25:12 -07:00
860616244e Tweak precedence table styles a bit. 2015-03-13 07:24:45 -07:00
06cea4f275 Merge branch 'ops-doc' of git://github.com/hachibu/wren into hachibu-ops-doc 2015-03-12 07:27:31 -07:00
48163087de Merge pull request #215 from gsmaverick/spelling-fix
Fix spelling on error.
2015-03-12 07:26:29 -07:00
b4e029fbf3 Pass char* to error(). 2015-03-11 07:31:18 -07:00
337ef467ed Add operator precedence table to documentation 2015-03-09 11:36:15 -04:00
4895c78f9d Fix incorrect comment. 2015-03-08 18:22:17 -07:00
28268f19ba Fix spelling on error. 2015-03-08 17:44:24 -07:00
958a85fc31 Fix unreachable links for IE11 (edge mode)
This corrects the flow of content. As main did not have a float style it
overlapped the nav tag making the links unreachable in IE11.
2015-03-08 15:59:59 +00:00
72baefe497 Clean up some outdated TODOs. 2015-03-07 14:10:34 -08:00
b36b71d3c6 Merge pull request #212 from soveran/io-read-eof
Change IO.read to return null on EOF
2015-03-07 13:47:07 -08:00
98c5e04f9a Clean up internal Map API.
Thanks, Michel!
2015-03-07 12:41:18 -08:00
05ba7d9fbf Add fiber features needed for to write an external scheduler:
- Allow yielding the main fiber. This exits the interpreter. The
  host can resume it by calling a method.
- Allow getting a reference to the current fiber.
2015-03-07 12:32:11 -08:00
542a783cb4 Change IO.read to return null on EOF 2015-03-07 09:10:18 +00:00
7aacf02a00 Tweak num methods a bit. 2015-03-06 22:52:42 -08:00
632a01d584 Merge branch 'num_methods' of git://github.com/MarcoLizza/wren into MarcoLizza-num_methods 2015-03-06 22:43:02 -08:00
d35e3c917c Add count to Sequence. 2015-03-06 07:01:02 -08:00
d56e2d6398 Removing old tests. 2015-03-05 11:27:56 +01:00
130d0df957 Fixing the test a bit. 2015-03-05 11:24:54 +01:00
f0fec695bb Removing redundant 'div' method. 2015-03-05 09:48:52 +01:00
28cc520e55 Style combing for 'sign' method. 2015-03-05 00:47:54 +01:00
919950bc33 Fixing 'truncate', too. 2015-03-05 00:46:45 +01:00
15f73b43f0 Renaming 'decimal' as 'fraction'. 2015-03-05 00:45:30 +01:00
d722adddff Use more idiomatic loops in delta_blue. 2015-03-04 07:16:56 -08:00
fde6f74d15 Adding tests. 2015-03-04 16:12:08 +01:00
f33d89bd0b Adding integer division method ('div'). 2015-03-04 16:10:37 +01:00
2b66880bb3 Simplify marking. 2015-03-04 07:08:48 -08:00
52ebb2b5d7 Consistency in variable names. :) 2015-03-04 14:46:24 +01:00
fc866f896f Extending 'sign' method to handle also "equal to zero" case. 2015-03-04 14:45:51 +01:00
86e63dd597 Adding number 'sign' method. 2015-03-04 14:42:50 +01:00
f494b526c7 Inverting 'decimal' and 'truncate'... opps! :D 2015-03-04 14:42:34 +01:00
d6e9a49813 Adding 'decimal' and 'truncate' number methods. 2015-03-04 00:29:19 +01:00
5007e1ff33 Adding deg<->rad number conversion methods. 2015-03-04 00:28:44 +01:00
90aa43450b Merge branch 'master' of git://github.com/bjorn/wren into bjorn-master 2015-03-03 07:23:47 -08:00
87739e8730 Merge branch 'master' into mingw-fix 2015-03-03 07:20:43 -08:00
28005ed47a Refactor number parsing a bit. 2015-03-03 07:17:56 -08:00
0ec31433c8 Generate an error if a number literal is too large to be represented with the Num class. 2015-03-03 00:07:55 -08:00
794d09ef15 Fix typo. 2015-03-02 07:32:09 -08:00
de80f1fd65 Add DEALLOCATE() macro. 2015-03-02 07:31:46 -08:00
4cf23218f9 "Native" -> "primitive". Yay consistency! 2015-03-02 07:24:04 -08:00
f10e0121b6 Two small doc fixes
* Fixed inconsistency in Lua vs. Wren example
* Fixed broken sentence
2015-03-01 23:14:32 +01:00
8f985847d4 Added Sequence.any as complement to Sequence.all 2015-03-01 23:14:32 +01:00
208ae9f7f2 Handle cc not being defined by MSYS for MinGW. 2015-03-01 09:25:48 -08:00
20b0188125 Merge branch 'master' of https://github.com/munificent/wren 2015-03-01 08:40:17 -08:00
ff9091cf63 Tweak static field docs a bit. 2015-03-01 08:39:53 -08:00
b2a7c5737c Merge branch 'static-fields-doc' of git://github.com/hachibu/wren into hachibu-static-fields-doc 2015-03-01 08:34:11 -08:00
3168d240a6 Merge pull request #203 from hachibu/authors
authors: add myself to authors
2015-03-01 08:33:06 -08:00
537cce1caa Merge branch 'master' of https://github.com/munificent/wren 2015-03-01 08:20:55 -08:00
12f725f2ef authors: add myself to authors 2015-03-01 07:50:30 -05:00
e72eedc6f5 Merge pull request #202 from bjorn/fib
Made the fib benchmark a bit faster
2015-02-28 16:51:41 -08:00
a025e01971 Clean up some dumb mistakes. 2015-02-28 13:51:19 -08:00
876c2d9208 Add API to call Wren method from C code.
This gives you a simple, efficient way to invoke a method on
some Wren object from C code, passing in arguments.

The basic API is in place and works, but there's still lots to do:

- Lots of error handling.
- Documentation.
- Tests!
2015-02-28 13:31:15 -08:00
d5377faf11 Made the fib benchmark a bit faster
This way fib.wren was consistently about 6% faster for me.
2015-02-28 21:15:18 +01:00
6b05610c6a Correctly count range size in GC. 2015-02-28 09:09:57 -08:00
7bed58ecf3 doc/site/classes.markdown: add static fields example 2015-02-28 11:26:18 -05:00
f472a301a2 Don't trigger GC on deallocation. 2015-02-27 21:41:59 -08:00
59796bcf5d Document benchmark runner. 2015-02-27 21:34:07 -08:00
c27a094882 Reorganize superclass validation a bit. 2015-02-27 08:08:27 -08:00
46713a5bb3 Merge branch 'issue-70' of git://github.com/verpeteren/wren into verpeteren-issue-70 2015-02-27 07:41:25 -08:00
effa69f64e Tweak docs a bit. 2015-02-27 07:37:58 -08:00
7cb5de388d Merge branch 'doc-site-core-num' of git://github.com/hachibu/wren into hachibu-doc-site-core-num 2015-02-27 07:30:58 -08:00
8408e862a3 Clean up the test script a bit. 2015-02-27 07:22:27 -08:00
07c7b49681 Use full signature in method debug name. 2015-02-27 07:10:44 -08:00
5d116153dd Simplify parameterList(). 2015-02-27 06:51:37 -08:00
ac70088e6b doc: add documentation for ceil, floor, .., and ... in num.markdown 2015-02-27 08:49:42 -05:00
96ceaa528b Allow empty argument list methods.
- Compile them as calls and definitions.
- Use them for call(), clear(), run(), try(), and yield().
- Update the docs.
2015-02-26 23:08:36 -08:00
1aaa8cff52 Use more comprehensive signature strings for methods. 2015-02-26 21:56:15 -08:00
e007bb7f11 Make embedding API provide full method signature. 2015-02-26 07:44:45 -08:00
22edfd7e7f Add note to comment. 2015-02-26 07:37:10 -08:00
f05d6143f5 Generating a runtime error on subclassing of builtins
As discussed in https://github.com/munificent/wren/issues/70, it is not allowed to subclass built-in types.
2015-02-25 20:13:37 +01:00
6a10d9740c Merge pull request #187 from MarcoLizza/bitwise_precedence
Bitwise precedence
2015-02-25 07:14:31 -08:00
fc2ed6f6e1 Don't allow trailing non-number characters when parsing a string to a number. 2015-02-25 07:07:54 -08:00
88e7f778aa Raising '&&' precedence above '||' one's. 2015-02-25 16:04:02 +01:00
21734b169a Bitwise operators precedence is now between 'PREC_COMPARISON' and 'PREC_RANGE'. 2015-02-25 16:02:29 +01:00
cec1f9160a Moving bitwise precedence-test to the correct folder. 2015-02-25 16:00:53 +01:00
4b88292ec1 Merge branch 'num-from-string' of git://github.com/gsmaverick/wren into gsmaverick-num-from-string 2015-02-25 06:53:12 -08:00
516808f6d2 Fix typo in docs. 2015-02-25 06:49:42 -08:00
f4a39bc943 Code review changes. 2015-02-25 01:20:53 -08:00
6e680f89bf Merge branch 'master' of https://github.com/munificent/wren 2015-02-24 22:08:57 -08:00
b5e5f80d8c Fix some signed-unsigned mismatches. 2015-02-24 21:56:33 -08:00
0242e43ed5 Make sure UINT32_MAX is available even in gcc C++ builds. 2015-02-24 21:09:04 -08:00
d0923f8fe1 Make sure UINT32_MAX is defined. 2015-02-24 20:26:39 -08:00
963ebb237d Install gcc-multilib so 32-bit C libraries are available on 64-bit Travis VMs. 2015-02-24 20:26:24 -08:00
03595703e2 Merge pull request #185 from MarcoLizza/baseline_in_benchmark_dir
Fixed benchmark baseline-file creation path.
2015-02-24 19:49:29 -08:00
5f0a2ba21c Just use a normal relative path to import relative to the cwd. 2015-02-24 19:47:17 -08:00
dc0dda3993 Merge branch 'wren_cpp_warnings' of git://github.com/MarcoLizza/wren into MarcoLizza-wren_cpp_warnings 2015-02-24 19:43:12 -08:00
f296850242 Build all configurations on Travis. 2015-02-24 19:32:46 -08:00
dfa1b51663 Add bitwise operators precedence test. 2015-02-23 17:29:31 +01:00
f280789758 Fix bitwise operators precedence. 2015-02-23 17:28:43 +01:00
422801a64a Allow executing multiple chunks of code in the same module.
This means successive calls to wrenInterpret() will run in
the same context. Allows variables to span calls in the REPL.
2015-02-23 07:02:27 -08:00
0577bf3784 Use current working directory as a module root for REPL. 2015-02-23 13:57:56 +01:00
940135c03b Remove C++ warnings on GCC and (minor) memory leak when allocating root-directory. 2015-02-23 13:57:20 +01:00
512baa2aff Fixed benchmark baseline-file creation path. 2015-02-23 10:01:57 +01:00
03a5b96040 Add a fromString static method on Num that converts strings to numbers. 2015-02-22 20:06:17 -08:00
a9d9362e29 Fix some typos in fn docs. 2015-02-22 12:34:32 -08:00
0dda174855 A bit more compiler clean up. 2015-02-22 11:04:43 -08:00
0f9e15833f Unify argument parsing. Fix #24. 2015-02-22 10:42:49 -08:00
a8a5805895 Fix test script. 2015-02-22 10:42:21 -08:00
bd97c244a5 Document removeAt() return value. Fix #176. 2015-02-22 10:26:31 -08:00
d6ec8c114e Don't crash if script path has no path separator. Fix #181. 2015-02-22 10:22:21 -08:00
037a2bdb66 Massive Makefile clean up!
- "make all" builds all combinations of configurations
- Binaries are built to "bin"
- (For convenience, the release interpreter also goes in the top level dir)
- Libraries are built to "lib"

This will also make it easier to support building and testing other
configurations like Nan tagging versus union, computed goto, etc.
2015-02-22 10:19:23 -08:00
3802609644 Store benchmark baseline file in benchmark/. 2015-02-21 13:49:02 -08:00
b45d3689de Clean up some comments. 2015-02-21 00:09:55 -08:00
44c547176b Fix quotes in module docs. 2015-02-20 06:54:03 -08:00
a4fa3027c0 Fix cyclic import docs. 2015-02-19 06:38:13 -08:00
bdb8634743 Tweak style. 2015-02-19 06:32:46 -08:00
4260a10983 add simple example for importing a module 2015-02-18 11:39:31 -05:00
ae88ee539d Merge branch 'master' of https://github.com/munificent/wren 2015-02-18 07:55:38 -08:00
ca14dffab4 First pass at docs for modules. 2015-02-18 07:55:09 -08:00
8ec89740c5 Merge pull request #172 from MarcoLizza/more_bitwise
More bitwise operands
2015-02-18 06:51:13 -08:00
b2ca4c0381 Allow zero or multiple imported names. 2015-02-17 07:32:33 -08:00
31304ac2bb Merge branch 'master' into modules 2015-02-17 07:22:21 -08:00
c6043d3c81 Use bytecode to import variable, instead of builtin function. 2015-02-17 07:21:51 -08:00
314c39e430 Use a native bytecode to load a module, instead of a weird builtin function on String. 2015-02-16 22:45:58 -08:00
269bf90ec8 More explicit naming bitwise operand implementations. 2015-02-16 22:29:30 +01:00
c45d70ac4e Fixed token name for '<<' and '>>'. 2015-02-16 22:26:54 +01:00
c2c576b27c Get rid of builtin function for importing. 2015-02-16 10:21:29 -08:00
5b1447882b Move running the module fiber into C. 2015-02-16 10:16:42 -08:00
36d100b8e4 Move module load failure into C. 2015-02-16 10:12:41 -08:00
cbd0217072 Merge pull request #174 from MarcoLizza/IO_time
IO.time
2015-02-16 10:01:56 -08:00
032c650e1f Get rid of hash constants for singleton values. 2015-02-16 09:33:07 -08:00
c9400a2c81 Adding 'IO.time' static method. 2015-02-16 12:04:56 +01:00
00cdef303c Adding new bitwise operands tests. 2015-02-16 11:30:15 +01:00
5280bf6c28 Adding '^', '<<', and '>>' operands implementation for numbers. 2015-02-16 11:29:14 +01:00
71fb636c94 Compiler now recognizes '^', '<<', and '>>' operands. 2015-02-16 11:28:34 +01:00
a44d479643 Basic import syntax. 2015-02-14 16:46:00 -08:00
ffc770b4a7 Also clean Mac .dylibs. 2015-02-12 09:07:41 -08:00
6ada5e0b24 Merge branch 'patch-1' of git://github.com/Phyllostachys/wren into Phyllostachys-patch-1 2015-02-12 09:06:37 -08:00
e4caeb2a7c made ``make clean`` more explicit 2015-02-12 10:23:13 -05:00
b7cd8c755f Make map deletion not soul-crushingly slow.
In cases where the hashtable had a large cluster (which can happen with lots of sequential numeric keys),
deletion would regress to near O(n).

Instead, this deletes by leaving a tombstone entry, similar to what Python, Lua, et. al. do.
2015-02-11 22:43:39 -08:00
911d5e374f Add benchmark for string map keys. 2015-02-11 22:41:59 -08:00
2bad33fbc8 Rename a couple of things in the benchmark script. 2015-02-11 19:48:39 -08:00
bc5a793c41 Split out the core and main modules.
- Implicitly import everything in core into every imported module.
- Test cyclic imports.
2015-02-11 10:06:45 -08:00
0d9095baf9 Adding map benchmark scripts. 2015-02-09 11:51:09 +01:00
b11f6e24e6 Moving the "run_bench" script to the "script" folder. 2015-02-09 11:49:06 +01:00
5b348e61d7 ``make clean`` now removes the libraries
```make clean``` now removes ```libwren.a``` and ```libwren.so``` where it only removed ```build```` and ```wren```
2015-02-06 15:15:41 -05:00
2005e1e0a2 Add ".wren" to modules in the embedder. 2015-02-06 11:52:05 -08:00
bb647d4247 Start getting module loading working.
Right now, it uses a weird "import_" method on String which
should either be replaced or at least hidden behind some syntax.

But it does roughly the right thing. Still lots of corner cases to
clean up and stuff to fix. In particular:

- Need to handle compilation errors in imported modules.
- Need to implicitly import all core and IO types into imported module.
- Need to handle circular imports.
  (Just need to give entry module the right name for this to work.)
2015-02-06 07:01:15 -08:00
30a5284338 Merge branch 'master' into modules
Conflicts:
	src/wren_debug.c
	src/wren_value.c
	src/wren_value.h
2015-02-05 12:07:25 -08:00
02600e2cb1 Get rid of main module field in WrenVM.
Instead, the main module is stored in the module map.
2015-02-05 12:03:19 -08:00
4a19050416 Merge branch 'uint32_string' of git://github.com/MarcoLizza/wren into MarcoLizza-uint32_string 2015-02-04 20:28:27 -08:00
55caae343b Add "." to comments. :) 2015-02-04 20:26:29 -08:00
ddd20c687e Merge branch 'master' into MarcoLizza-8_bit_strings_tests 2015-02-04 20:25:12 -08:00
878be6fb6b Clean up wrenStringFind() a bit. 2015-02-04 20:23:50 -08:00
ba4760331e Merge branch 'replacing_strstr' of git://github.com/MarcoLizza/wren into MarcoLizza-replacing_strstr 2015-02-04 17:56:29 -08:00
aa9cfffb34 Keep code within 80 columns. 2015-02-04 08:15:35 -08:00
8f313bf4ec Merge branch 'fixing_string_concatenation' of git://github.com/MarcoLizza/wren into MarcoLizza-fixing_string_concatenation 2015-02-04 08:12:50 -08:00
ef84995598 Merge branch '8_bit_strings_tests' of git://github.com/MarcoLizza/wren into MarcoLizza-8_bit_strings_tests 2015-02-04 06:59:57 -08:00
ed534b8165 Merge pull request #159 from MarcoLizza/null_char_escape
Adding '\0' escape sequence for null characters.
2015-02-04 06:57:42 -08:00
6f26f542ea Merge pull request #163 from MarcoLizza/memcpy_for_strings
Getting rid of "strcpy()/strncpy()" in favour of "memcpy()".
2015-02-04 06:57:17 -08:00
74289d8e7f Merge pull request #165 from MarcoLizza/gcc_constant_warning
Getting rid of constant unsigned error when compiling for C++ on GCC.
2015-02-04 06:55:44 -08:00
8af1a787e2 Getting rid of constant unsigned error when compiling for C++ on GCC. 2015-02-04 13:59:53 +01:00
d73b19967d Adding 8-bit strings test cases. 2015-02-04 13:58:16 +01:00
096e5cf33c Fixing empty search string corner case. 2015-02-04 13:53:59 +01:00
4d1e0833fb Getting rid of "strcpy()/strncpy()" in favour of "memcpy()". 2015-02-04 13:51:54 +01:00
4c58830684 Fixing minor string length comparison warning. 2015-02-04 13:47:09 +01:00
d3ca27fb9a Changing 'wrenStringConcat()' to support null-containing strings. 2015-02-04 13:44:39 +01:00
875ee9e55a Replacing 'strstr()' with 'wrenStringFind()' to support 8-bit strings. Internally the Boyer-Moore-Horspool algorithm is used. 2015-02-04 13:38:15 +01:00
866aeb7a3a Changing string size type to 'uint32_t'. 2015-02-04 13:29:15 +01:00
6997b9475d Adding '\0' escape sequence for null characters. 2015-02-04 13:25:25 +01:00
abc43f18bc Merge branch 'master' into shared-lib-makefile 2015-02-01 21:47:43 -08:00
9917c16876 Fix un-Nan-tagging mode. Thanks, Michel Hermier! 2015-02-01 15:26:33 -08:00
593e5c8b35 Clean up how flex arrays are allocated. 2015-02-01 15:12:37 -08:00
98df1b2bd1 Add cast. 2015-01-31 10:54:27 -08:00
970093299a Merge branch 'symbol_table_optimization' of git://github.com/MarcoLizza/wren into MarcoLizza-symbol_table_optimization 2015-01-31 10:49:41 -08:00
2ba8da7418 Merge branch 'master' into modules 2015-01-30 07:21:41 -08:00
87b9fdd620 Using 'memcmp' in place of 'strncmp'. 2015-01-30 09:24:10 +01:00
a54bde7294 Fixing style typo. 2015-01-30 09:23:30 +01:00
8e25aa646e Remove unneeded conversion. Fix #148. 2015-01-29 20:44:46 -08:00
23cc8a5384 Fixed debug symbols dump. 2015-01-29 17:08:05 +01:00
5143b0707d Keeping trace of symbols length in the symbol table. 2015-01-29 16:54:21 +01:00
3bed04e0b9 Support clang/OS X shared libraries in the Makefile. 2015-01-28 19:50:53 -08:00
f10058a704 Merge branch 'master' of https://github.com/munificent/wren 2015-01-28 19:19:19 -08:00
0aa4d7c2bd Fix crash when doing a lookup on an empty map. 2015-01-28 19:19:04 -08:00
1101823666 Turn Module into an Obj. 2015-01-27 07:11:45 -08:00
81dd7a7412 Merge pull request #143 from MarcoLizza/dropped_bitfields_usage
Bitfields usage
2015-01-27 07:06:18 -08:00
2f97ef57d3 Change Makefile to differentiate between static and shared library
Previously, just the static libraries (libwren*.a) were created. In the Makefile documentation these were mentioned in the comments as shared.
Now both variants will be created.
2015-01-27 15:05:53 +01:00
a2c1ee5c25 Using a single boolean in place of a bitwise masking. 2015-01-27 14:13:26 +01:00
6f9b10cde8 Removing bitfields usage from 'Obj' struct. 2015-01-27 14:09:32 +01:00
83ad9abd73 Merge branch 'master' into modules
Conflicts:
	src/wren_core.c
2015-01-26 21:55:41 -08:00
699b453805 Fix ambiguous sequence point in dup. 2015-01-26 21:23:54 -08:00
b3f556adba Move globals out of VM and into a Module struct.
Functions store a reference to the module where they were
defined and load "module" variables from there.

Right now there's only one "main" module, but this is a step
in the right direction. Perf is down, though. :(

binary_trees - wren            ..........  3026  0.33s   88.28% relative to baseline
delta_blue - wren              ..........  7248  0.14s   94.32% relative to baseline
fib - wren                     ..........  2414  0.41s   88.08% relative to baseline
for - wren                     ..........  6753  0.15s   78.79% relative to baseline
method_call - wren             ..........  6624  0.15s  100.03% relative to baseline
2015-01-26 07:45:21 -08:00
b93ad5fae4 Merge branch 'range-equality' of git://github.com/gsmaverick/wren into gsmaverick-range-equality 2015-01-26 07:01:15 -08:00
8b7c16eebd Strings and ranges should rely on the object definition of equality. 2015-01-25 23:28:37 -08:00
ed8e595f54 Get rid of bytecodes for list literals.
Just compile them to:

new List
.add(...)
.add(...)
...

Gets rid of some code in the interpreter loop, which is always good.
Also addresses the old limitation where a list literal could only have
255 elements.
2015-01-25 22:49:30 -08:00
a9bd864c6b More docs for maps. 2015-01-25 21:39:22 -08:00
f482a53d0e Define equality on ranges. 2015-01-25 19:50:54 -08:00
44db50e7ef Don't rely on fallthrough. 2015-01-25 17:51:50 -08:00
41d9ba9b3d Merge branch 'hex-literals' of git://github.com/gsmaverick/wren into gsmaverick-hex-literals 2015-01-25 17:49:05 -08:00
4579171afa Add remove() to Map. 2015-01-25 17:42:36 -08:00
0ad7a7d9ff Code review changes. 2015-01-25 13:02:44 -08:00
0e6a90443e Add containsKey() to Map, and validate key types. 2015-01-25 12:39:19 -08:00
3061bdde7f Start documenting maps and work on some other docs a bit. 2015-01-25 11:08:13 -08:00
492c730e6f Key and value iteration for maps. Also toString. 2015-01-25 10:27:38 -08:00
251b623c65 Map "clear" method. 2015-01-25 08:39:44 -08:00
e740a4c95a Map literals! 2015-01-24 23:21:50 -08:00
abe80e6d4b Initial map implementation.
Still lots of methods missing and clean up and tests to do.
Also still no literal syntax.

But the core hash table code is there and working. The supported
key types are all, uh, supported.
2015-01-24 22:27:35 -08:00
12102b19ef Adds support for hexadecimal literals. 2015-01-24 22:07:46 -08:00
cff08f989b Rename a couple of tests. 2015-01-24 14:42:25 -08:00
438e7bae3f Merge branch 'list-join' of git://github.com/gsmaverick/wren into gsmaverick-list-join 2015-01-24 14:39:45 -08:00
4977083904 Abstract List's toString method to a more general join method on Sequence. 2015-01-24 14:01:16 -08:00
efd161cea2 Add "arity" getter to Fn. 2015-01-23 20:33:05 -08:00
c3a858a2c7 Update doc on VS project. 2015-01-23 10:41:11 -08:00
94080a0e96 Be a bit more explicit about uses of the struct hack. 2015-01-23 10:38:12 -08:00
cda727a18d Merge branch 'msvc-project-and-compatibility' of git://github.com/MarcoLizza/wren into MarcoLizza-msvc-project-and-compatibility 2015-01-23 10:12:12 -08:00
2f12ad879d Pulling the "Math" library out. 2015-01-23 10:08:34 +01:00
1464280933 Restoring original header files order and using MSVC project setting to disable non-secure CRT warnings. 2015-01-23 10:05:10 +01:00
eb424f5c1a Make strings iterable over their code points.
I'm not sure why, but this also regresses perf:

binary_trees - wren            ..........  3290  0.30s   96.68% relative to baseline
delta_blue - wren              ..........  7948  0.13s   99.06% relative to baseline
fib - wren                     ..........  3165  0.32s   95.90% relative to baseline
for - wren                     ..........  8242  0.12s   96.00% relative to baseline
method_call - wren             ..........  5417  0.18s   78.74% relative to baseline

Need to investigate.
2015-01-22 20:58:22 -08:00
a5b00cebe7 Clarify how string subscripting handles UTF-8. 2015-01-22 16:38:03 -08:00
a92e58c804 Add tests for string methods that support UTF-8 already. 2015-01-22 15:28:54 -08:00
c5e67953b8 Allow non-ASCII UTF-8 characters in string literals. 2015-01-22 15:18:30 -08:00
c88e61d018 Adding "Math" lib into Wren. 2015-01-22 17:46:09 +01:00
5f267ee822 Merge branch 'math_lib' into msvc-project-and-compatibility 2015-01-22 16:42:40 +01:00
6df15f209a Added simple "Math" library. 2015-01-22 16:41:19 +01:00
2cee4c83bd Clean up and improve docs in embedder API. Fix #133. 2015-01-22 07:05:55 -08:00
8ce58ec3c4 Reorganize files in XCode project. 2015-01-22 07:05:32 -08:00
f628de1201 Merge remote-tracking branch 'munificent/master' into 'msvc-project-and-compatibility' branch for fix #128. 2015-01-22 10:13:16 +01:00
b05e5f9c73 Merge pull request #132 from edsrzf/fix-mod-precedence
Fix precedence of % operator
2015-01-21 13:50:09 -08:00
513af6df65 Fix precedence of % operator
It previously had the same precedence as + and -.
2015-01-22 09:49:53 +13:00
bdc3439a71 Remove old "pinned" terminology. 2015-01-21 08:02:18 -08:00
1d0f6a5033 Get rid of totally broken WREN_PIN. Fix #128. 2015-01-21 07:56:06 -08:00
244218286e Updating AUTHORS file. =) 2015-01-21 11:06:22 +01:00
61674112c9 Addressing odd Microsoft Visual Studio 2013 optimizer bug. 2015-01-21 11:01:09 +01:00
222c2d5bbb Adding Microsoft Visual Studio 2013 project and solution files. 2015-01-21 11:00:35 +01:00
73ce2b0b7e Revised headers include order. The "wren_common.h" should be included first, being a sort of "configuration" header. Then the "wren-XYZ.h" header should follow for "XYZ.c" source file. Then the other "wren_*.h" headers (in lexicographical order if possible). Al last, the standard include files. 2015-01-21 10:30:37 +01:00
991ada8919 Microsoft compiler seems not to support the computed-goto approach. 2015-01-21 10:27:27 +01:00
67da0c42f0 Fixed returning a "void" function return value (!). 2015-01-21 10:23:46 +01:00
bc74c28904 Using a "char" could cause odd sign extension results. 2015-01-21 10:22:56 +01:00
a45ec69f9f In MSVC the "inline" modifier is not available when compiling in plain-C. 2015-01-21 10:22:18 +01:00
bb9708a7e3 Resolving (non-standard) zero-sized array usage warning. 2015-01-21 10:21:04 +01:00
9453acf1e6 User-defined subscript operators. 2015-01-20 18:25:54 -08:00
311bec5b03 Mention authors on the footer! 2015-01-20 17:47:17 -08:00
879d9d725e Add links to mailing list. 2015-01-20 17:46:52 -08:00
b6443f0301 Move XCode project under project/. 2015-01-20 17:14:30 -08:00
c63b027210 More explicit casting between Value and Obj* to satisfy 32-bit MinGW.
Fix #111.
2015-01-20 17:06:39 -08:00
d7ae2bbc4c Turn CalculatedRange into output params. 2015-01-20 15:33:21 -08:00
b55eb7de7a Merge branch 'string-range-subscript' of git://github.com/gsmaverick/wren into gsmaverick-string-range-subscript 2015-01-20 15:01:14 -08:00
d894fc3dec Tighten numeric types in intepreter:
binary_trees - wren            ..........  3563  0.28s  101.26% relative to baseline
delta_blue - wren              ..........  8162  0.12s  106.05% relative to baseline
fib - wren                     ..........  3310  0.30s  103.39% relative to baseline
for - wren                     ..........  8576  0.12s  102.16% relative to baseline
method_call - wren             ..........  6946  0.14s  107.08% relative to baseline
2015-01-20 14:41:09 -08:00
721db7564b Remove unused return value from consume() and consumeLine(). 2015-01-20 14:40:34 -08:00
363dff2ffd Reorganize a bit. 2015-01-20 14:00:03 -08:00
8c3759a457 Merge branch 'feature-wrenGetArgumentBool' of git://github.com/hazbo/wren into hazbo-feature-wrenGetArgumentBool 2015-01-20 13:58:36 -08:00
eb4e50a500 Don't use -fPIC on Windows (cygwin, mingw32). 2015-01-20 13:42:46 -08:00
a65e11b9f7 Added comment for wrenGetArgumentBool 2015-01-19 14:52:30 +00:00
2763ab3176 Implemented wrenGetArgumentBool 2015-01-19 14:40:37 +00:00
bfc2f9c0ee Adds range subscripting for strings. 2015-01-18 22:55:30 -08:00
2a4804bbc9 Reorganize core library docs. 2015-01-18 15:36:36 -08:00
50c0cbe8c3 Merge branch 'master' of https://github.com/munificent/wren 2015-01-18 10:20:29 -08:00
d8b678356e Raise precedence of "is". Fix #119. 2015-01-18 10:20:13 -08:00
8a292fac9e Merge pull request #121 from zeckalpha/phony-prep
Make prep Phony
2015-01-18 10:03:13 -08:00
9fcaddaa07 Make prep Phony 2015-01-17 20:20:05 -06:00
ea32ba5f55 Merge pull request #118 from hazbo/feature-wrenReturnBool
Feature wren return bool
2015-01-17 08:45:45 -08:00
b7d03971c6 Added comment for wrenReturnBool 2015-01-17 12:02:23 +00:00
dec4f0d1e7 Implemented wrenReturnBool in vm 2015-01-17 11:48:27 +00:00
ae97e9c3a4 Remove Linux-specific libc stuff. 2015-01-16 23:32:20 -08:00
f79f1d2b63 Show benchmarks are time, not scores. 2015-01-16 17:51:10 -08:00
fe71ddd520 Update benchmark table. 2015-01-16 07:52:51 -08:00
eece4ee926 Inline callFunction():
binary_trees - wren            ..........  3400  0.29s   97.79% relative to baseline
delta_blue - wren              ..........  7565  0.13s  102.23% relative to baseline
fib - wren                     ..........  3039  0.33s   98.93% relative to baseline
for - wren                     ..........  8265  0.12s   92.49% relative to baseline
method_call - wren             ..........  6759  0.15s  131.21% relative to baseline
2015-01-16 07:45:42 -08:00
2a37110bd1 Don't use designated initializer. 2015-01-16 07:10:33 -08:00
096578cc92 Reorganize docs a bit. 2015-01-16 07:04:01 -08:00
16d2f62a24 Update reduce documentation 2015-01-16 09:53:20 +01:00
ae3045bd8d Add myself to AUTHORS 2015-01-16 09:53:14 +01:00
82740d2668 Add a test demonstrating folding order 2015-01-16 09:48:59 +01:00
4bc06a3acc Add reduce test for ranges 2015-01-16 09:33:23 +01:00
d764581a3d Add test for empty reduce 2015-01-16 09:29:45 +01:00
5cfb638fd1 Use @munificent's single-argument reduce 2015-01-16 09:26:19 +01:00
5a7b70d45c Add documentation for reduce 2015-01-16 09:24:59 +01:00
4c6b819ed1 Add reduce function on Sequence 2015-01-16 09:24:59 +01:00
64c2bd7633 Make all types support "!" so "if (!foo)" works reliably for all objects. 2015-01-15 21:50:01 -08:00
94259fac8a Merge branch 'master' of https://github.com/munificent/wren 2015-01-15 21:17:45 -08:00
8651d9c12a Merge branch 'cpp'
Conflicts:
	src/wren_vm.c
2015-01-15 21:17:08 -08:00
93a4dd1b64 Update docs to mention compiling as C++. 2015-01-15 21:15:21 -08:00
6e369fc639 Finish making Wren compile as C++98.
- Get Value, the hard part, compiling as C++.
- Add some rudimentary C++ support to the makefile, mainly for testing.
2015-01-15 21:12:51 -08:00
4bd2c949e1 Merge pull request #113 from gsmaverick/fix-all-docs
Fix all docs
2015-01-15 20:38:00 -08:00
d3e4ac1745 Add myself to AUTHORS. 2015-01-15 19:06:24 -08:00
2ddf0a9586 Fix some overlooked references to forall. 2015-01-15 19:05:58 -08:00
0dec887a2f Fix interpreter loop when computed gotos are disabled. 2015-01-15 16:22:55 -08:00
3a2432eef7 Get value compiling as C++. 2015-01-15 16:21:14 -08:00
89a6ed9687 Get vm compiling as C++. 2015-01-15 16:02:38 -08:00
08263e3676 Get debug and utils compiling as C++. 2015-01-15 16:00:51 -08:00
e3ccb68c79 Get main.c and compiler compiling as C++. 2015-01-15 15:59:14 -08:00
4249f92571 Rename tests. 2015-01-15 06:54:16 -08:00
78e99c6c99 Merge branch 'list-forall' of git://github.com/gsmaverick/wren into gsmaverick-list-forall 2015-01-15 06:52:43 -08:00
b829ce67af Rename forall to all. 2015-01-14 23:19:31 -08:00
7ce4f20533 Merge branch 'nonlocal-names' 2015-01-14 23:08:34 -08:00
c50e46725f Implicitly define nonlocal names.
If a capitalized name cannot be resolved, a new top-level
variable with its name is implicitly declared. If a real
definition is not found later, a compile time error is raised.

Mutual recursion at the top level works now!

Fix #101. Fix #106.
2015-01-14 23:08:25 -08:00
74a7ac6b95 Update DeltaBlue to use nonlocal name. 2015-01-14 23:03:17 -08:00
f2b334d7d2 Add more forall test cases. 2015-01-14 22:51:34 -08:00
15561be89b Don't check against other keywords once we find a match. Fix #110. 2015-01-14 06:46:02 -08:00
7716ad6263 Adds forall method on Sequences. 2015-01-13 23:47:01 -08:00
a8e2ba233c Add support for "nonlocal" (capitalized) names, and change how variable lookup works.
Inside a method, all local variable lookup stops at the method boundary. In other
words, methods, do not close over outer local variables.

If a name is not found inside a method and is lowercase, it's a method on this.
If it's capitalized, it's a global variable.
2015-01-13 21:36:42 -08:00
9cb414d63b Merge branch 'master' of https://github.com/munificent/wren 2015-01-13 06:42:35 -08:00
b4495736ed Don't have a semicolon at the end of the template 2015-01-12 20:16:06 -06:00
39e5aea77c Merge pull request #104 from zeckalpha/typos
Typos
2015-01-12 16:58:05 -08:00
0c6d192ace bretheren > brethren 2015-01-12 17:39:41 -06:00
1c9520020e unvalid > invalid 2015-01-12 17:27:35 -06:00
ca93578696 Missing semicolons.
I'm unsure about the one inside the macro, but the other ones were making my syntax highlighting break.
2015-01-12 17:24:05 -06:00
12b8168b94 Merge pull request #103 from pwoolcoc/add-debugging-symbols
Allow better debugging
2015-01-12 07:32:21 -08:00
d74e11b80e Allow better debugging
This will ensure that we have better output when running `wren` under
{g,ll}db.
2015-01-12 10:01:34 -05:00
1d9445d9bc Tests for IO.read(). 2015-01-11 21:47:29 -08:00
7a7c7a8fad Merge branch 'add-read-string' of git://github.com/pwoolcoc/wren into pwoolcoc-add-read-string
Conflicts:
	builtin/io.wren
	src/wren_io.c
2015-01-11 20:05:52 -08:00
73b041a78a Merge branch 'master' of git://github.com/Alek900/wren into Alek900-master
Conflicts:
	src/wren_compiler.c
2015-01-11 20:01:30 -08:00
21e740d5c3 Test that carriage returns are treated like whitespace. 2015-01-11 19:58:30 -08:00
ad6d350140 Merge branch 'master' of https://github.com/munificent/wren 2015-01-11 19:53:17 -08:00
3feb72041e Tweak style a bit. 2015-01-11 19:52:59 -08:00
ab1c5aca0c Merge branch 'Fix-CRLF-bug' of git://github.com/elder-george/wren into elder-george-Fix-CRLF-bug 2015-01-11 19:52:08 -08:00
e07156d9e2 Merge pull request #74 from tamc/document-inheritance-from-builtins
Added documentation about issue #70 - can't inherit from built-ins
2015-01-11 19:50:39 -08:00
650a70b9a3 Merge pull request #96 from zeckalpha/feature/set-example_updated_syntax
Set example updated syntax
2015-01-11 19:50:07 -08:00
6bd245b4b2 Tweak comment. 2015-01-11 19:44:35 -08:00
be0032cc40 Merge branch 'segfault_on_top_level_super_with_no_args' of git://github.com/zeckalpha/wren into zeckalpha-segfault_on_top_level_super_with_no_args 2015-01-11 19:42:26 -08:00
bc29e0929e Rename a couple of files and tweak some docs. 2015-01-11 19:13:15 -08:00
7557c91b3c Adds some common methods to strings. 2015-01-11 16:06:56 -08:00
c376d88e61 super at top level: Allow the compiler to continue compilation after erroring. Added two more tests. 2015-01-11 17:44:10 -06:00
c0b0920d67 Update set example to new Syntax. Replaces #30 2015-01-09 16:02:40 -06:00
fa85bb1eef Remove spaces from after method definitions 2015-01-09 15:15:34 -06:00
c2e6181b01 Newline at end of file 2015-01-09 15:15:34 -06:00
2253d9269f Fix for iterate handling null 2015-01-09 15:15:34 -06:00
a67cde69bb Update set example to use bitwise operators 2015-01-09 15:15:34 -06:00
18af6514f0 Add Set example 2015-01-09 15:15:34 -06:00
3490c8d2f3 Segfault when calling super at top-level with no arguments.
If enclosingClass is null, we can't proceed with compilation since we don't have its name.
2015-01-09 15:14:06 -06:00
aa48223361 Merge pull request #92 from zeckalpha/https_for_fonts
Fonts weren't working in Firefox due to Mixed Content errors.
2015-01-09 09:34:35 -08:00
d9527dc4dc Use protocol-relative URL 2015-01-09 09:25:06 -06:00
3116bf97de Use correct buffer size in string subscript operator. 2015-01-09 07:12:25 -08:00
bcf052436f Merge pull request #94 from edsrzf/fix-neg-number
Don't treat negative numbers as literals
2015-01-09 07:00:12 -08:00
75d28c083c Don't treat negative numbers as literals
Fixes #93.

Previously, "1 -1" was lexed as two number tokens: a positive literal and
a negative literal. This caused problems when it came to parsing.

Now the '-' and the second number are separate tokens.

Note this is a breaking change, since `-16.sqrt` is now parsed as `-(16.sqrt)`,
as opposed to `(-16).sqrt`.

There is a small bit of overhead to doing it this way, but it might be possible
to optimize that out in the compiler at some point in the future.
2015-01-09 20:17:40 +13:00
efabf20fee Make a few changes to methodNotFound():
- Move closer to other runtime error code.
- Make it static since it's private to wren_vm.h.
- Allocate a managed ObjString* for the message so the GC can handle it.
  That's how it ends up anyway, so this cuts out the middle man.
- Use a width specifier in sprintf() to print the canonical method name.
2015-01-08 22:29:37 -08:00
a9f1d52ef7 Merge branch 'improve-debugging' of git://github.com/gsmaverick/wren into gsmaverick-improve-debugging 2015-01-08 21:49:20 -08:00
15da548f48 Code review changes. 2015-01-08 21:30:47 -08:00
7f1b5bfe51 Add stack vs register-based question to FAQ. 2015-01-08 21:06:10 -08:00
28203e3df5 Fonts weren't working in Firefox due to Mixed Content errors.
https://developer.mozilla.org/en-US/docs/Security/MixedContent
2015-01-08 19:57:15 -06:00
15b0d8777c Handle toString not returning a string in IO.print and IO.write.
Fix #67.
2015-01-08 07:53:37 -08:00
92fcfc1b00 Merge pull request #83 from zeckalpha/benchmark_missing_interpreters
Benchmark: Alert that an interpreter was not found rather than halting.
2015-01-08 07:44:29 -08:00
cb0bb6a375 Merge pull request #84 from zeckalpha/operator_they_their_typo
Docs: Expressions: Operators: they->their typo
2015-01-08 07:43:00 -08:00
a9a676d706 Merge branch 'master' of https://github.com/munificent/wren 2015-01-08 07:41:49 -08:00
1a7f849c42 Store string length as an int instead of size_t.
Saves a few bits, and avoids some signed/unsigned conversions.
It's also consistent with other places string lengths are stored in the VM.
2015-01-08 07:41:30 -08:00
817f37bbf0 Docs: Expressions: Operators: they->their typo 2015-01-08 09:32:50 -06:00
5e07c10374 Benchmark: Alert that an interpreter was not found rather than halting. 2015-01-08 09:16:32 -06:00
1e6241a7df Merge pull request #81 from edsrzf/sprintf-return
Use the return value of sprintf to avoid strlen calls
2015-01-08 07:01:21 -08:00
49575fc1a5 Merge pull request #80 from edsrzf/string-store-length
Store string length
2015-01-08 06:59:41 -08:00
648ee727a1 Fix style nits 2015-01-08 19:34:58 +13:00
68adc3f511 Use the return value of sprintf to avoid strlen calls 2015-01-08 13:46:33 +13:00
5261ef498f Optimize string methods for stored length
wrenStringConcat could still make use of this info, but that's a more involved
change.
2015-01-08 11:09:11 +13:00
3fd348e6c1 Store string length
Strings are still null-terminated so that they can be treated as C strings.
2015-01-08 10:05:51 +13:00
0d099933d6 Add myself to AUTHORS 2015-01-08 09:51:13 +13:00
8540e58b61 Typo fix 2015-01-07 16:41:30 +00:00
437eddc126 Merge pull request #77 from zeckalpha/benchmark_metrics
Add metrics for benchmarks
2015-01-07 07:30:59 -08:00
d53da95664 Merge pull request #76 from zeckalpha/run_bench_python3
Make run_bench compatible with Python 3
2015-01-07 07:25:46 -08:00
71fbc32c42 Merge branch 'master' into edsrzf-string-flexible-array 2015-01-07 07:23:03 -08:00
fd859ec70a Merge pull request #75 from edsrzf/fix-benchmark
Remove semi-colons from delta_blue.wren
2015-01-07 07:22:05 -08:00
b30f8446f8 Merge branch 'string-flexible-array' of git://github.com/edsrzf/wren into edsrzf-string-flexible-array 2015-01-07 07:20:12 -08:00
ed548aa659 Keep same whitespace as previous version 2015-01-06 17:57:57 -06:00
5e1469fc36 Add metrics for benchmarks 2015-01-06 16:20:52 -06:00
e83d01855c Make run_bench compatible with Python 3 2015-01-06 16:20:21 -06:00
cb91bea6e7 Remove semi-colons from delta_blue.wren 2015-01-07 08:06:44 +13:00
4a9b3f3e49 Fixed typo in classes.markdown 2015-01-06 16:47:54 +00:00
af6be5d346 Update README.md
Add Travis build status image.
2015-01-06 07:21:22 -08:00
6adf8c40e1 Don't use printf() to format NaNs since the output isn't fully specified. Fix #65. 2015-01-06 07:09:45 -08:00
92222fe7c6 Added documentation about issue #70 - can't inherit from built-ins 2015-01-06 08:37:57 +00:00
e3b5206ca8 Use a flexible array for strings 2015-01-06 19:08:42 +13:00
a8507ca17a Merge branch 'master' of https://github.com/munificent/wren
Conflicts:
	AUTHORS
2015-01-05 21:58:23 -08:00
2abf70f8d6 Merge pull request #69 from pwoolcoc/add-pwoolcoc-to-authors
Add myself to the AUTHORS file
2015-01-05 20:52:01 -08:00
7fb18d7843 Made \r treated as a whitespace character. 2015-01-05 18:33:49 -08:00
ca9b399d56 Make Python scripts Python 2 and 3 compatible. An alternative to #71. 2015-01-05 20:09:23 -06:00
6aed3ec64c Add myself to the AUTHORS file 2015-01-05 11:02:52 -05:00
84b2dbf48e Merge pull request #66 from txgruppi/master
Updated description of logical or
2015-01-05 07:46:26 -08:00
59c2024384 Updated description of logical or 2015-01-05 09:42:34 +00:00
7ecff2d79f Implement IO.read 2015-01-04 19:54:28 -05:00
6912eec6a7 Adding support for '\r' char to lexer. 2015-01-04 14:25:17 -08:00
84ead3bb18 Start sketching out an actual contributor's guide.
- Add AUTHORS file
- Update README to match site docs
2015-01-04 13:36:23 -08:00
52bd38f3bd Don't double report lexer errors. 2015-01-04 13:10:46 -08:00
09bb28735c Merge branch 'feature-shebang-support' of git://github.com/mauvm/wren into mauvm-feature-shebang-support 2015-01-04 13:02:42 -08:00
a9bb2387a1 Handle empty (or comment-only) files. Fix #57. 2015-01-04 13:00:53 -08:00
7f90485cff Let the user know the arity of a missing method in the error message. 2015-01-04 14:42:11 -05:00
4200f18f83 Rename test for invalid shebang. 2015-01-04 20:09:33 +01:00
6c549e0cc5 Use lexError() and add test for invalid shebang. 2015-01-04 19:56:16 +01:00
005688da96 Merge branch 'master' of https://github.com/munificent/wren 2015-01-04 10:03:16 -08:00
728cb2cbca Gitignore shared libraries and comment makefile a bit. 2015-01-04 10:02:50 -08:00
f466763d54 Merge branch 'build-shared-lib-and-interpreter' of git://github.com/pwoolcoc/wren into pwoolcoc-build-shared-lib-and-interpreter 2015-01-04 09:57:05 -08:00
dfb381e43b Remove duplicate comment. Oops. 2015-01-04 08:52:40 +01:00
e46d2e479b Merge pull request #55 from gsmaverick/repl-newline
Don't try to run an empty line in the REPL.
2015-01-03 23:40:20 -08:00
a8726e6c00 SO MUCH NEW DOCS OH WOW. 2015-01-03 23:27:02 -08:00
8a54ef9919 Add tests. 2015-01-03 20:53:17 +01:00
fa96fb0a8e Let compiler ignore shebang on first line. 2015-01-03 20:53:12 +01:00
e3e358fb61 Don't try to run an empty line in the REPL. 2015-01-03 14:25:10 -05:00
c25cfca18b Eliminate semicolons entirely. 2015-01-03 10:02:45 -08:00
d1ac8c314f Added test for whitespace in code 2015-01-03 15:10:04 +01:00
150ea237e9 Added test and fixed skipping whitespace 2015-01-03 14:57:34 +01:00
c0043e78d4 Merge branch 'master' of https://github.com/munificent/wren 2015-01-02 20:17:36 -08:00
b33dcf0da5 Name the anonymous union since strict C99 doesn't allow it. 2015-01-02 20:17:10 -08:00
d190254f4a Merge pull request #49 from skybrian/patch-1
Fix example of catching and printing an error
2015-01-02 20:09:43 -08:00
2abeb9ad2e Make first example correct (!). Fix #47. 2015-01-02 20:07:43 -08:00
dd686a808d Make tab(\t) a valid whitespace character. 2015-01-02 23:22:09 +01:00
46867d3540 Fix example of catching and printing an error
The output didn't match the source code.
(Tested.)
2015-01-02 14:12:53 -08:00
7cb77b7729 First try at building separate lib + binary 2015-01-02 15:24:07 -05:00
6b510da872 Get Travis set up. 2015-01-02 08:13:51 -08:00
526a84c4d6 Remove pointless newline. 2015-01-02 07:59:31 -08:00
99f0bf09c3 Add README and move metrics script. 2015-01-02 07:42:08 -08:00
a1b02a04bb Clarify license. 2015-01-02 07:38:00 -08:00
f028544b53 CamelCase. 2015-01-02 07:31:02 -08:00
23ba46a9f9 Move the -lm after the list of object files
Fixes linking through `gcc`, doesn't affect `clang`.

Closes #43
2015-01-02 09:32:30 -05:00
25b31a206a Check the return value of getline
Otherwise, `gcc` warns, which causes the build to fail
2015-01-02 09:32:29 -05:00
50be5971a4 Fix link to embedding API. 2015-01-01 22:59:38 -08:00
3640c66bfb Fix range in docs. 2015-01-01 22:48:43 -08:00
944 changed files with 232367 additions and 16991 deletions

39
.gitignore vendored
View File

@ -1,23 +1,34 @@
# Intermediate files directory.
build/
build_xcode/
.sass-cache/
# Built applications.
# Build outputs.
bin/
lib/
wren
wrend
# XCode user-specific stuff.
xcuserdata/
*.xccheckout
# Intermediate files.
build/
deps/
.sass-cache/
# I leave a temporary Wren script at the top level so that I can quickly test
# stuff.
scratch.wren
# The baseline file is machine-specific, so doesn't get checked in.
benchmark/baseline.txt
test/benchmark/baseline.txt
# built docs get copied here, which is presumed to be a separate checkout of
# the repo so they can be pushed to GitHub Pages.
gh-pages/
# XCode user-specific stuff.
xcuserdata/
*.xccheckout
# Visual Studio cache files.
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio User-specific files.
*.suo
*.user
*.userosscache
*.sln.docstates

13
.travis.yml Normal file
View File

@ -0,0 +1,13 @@
language: c
compiler:
- gcc
- clang
# 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
- g++-multilib
sudo: false # Enable container-based builds.
script: make all && make test

17
AUTHORS Normal file
View File

@ -0,0 +1,17 @@
This is the (likely incomplete) list of people who have made Wren what it is.
If you submit a patch to Wren, please add your name and email address to the
end of this list.
Robert Nystrom <robert@stuffwithstuff.com>
Kyle Marek-Spartz <kyle.marek.spartz@gmail.com>
Paul Woolcock <paul@woolcock.us>
Evan Shaw <edsrzf@gmail.com>
Gavin Schulz <gavin.schulz@gmail.com>
Lukas Werling <lukas.werling@gmail.com>
Marco Lizza <marco.lizza@gmail.com>
Raymond Sohn <raymondsohn@gmail.com>
Thorbjørn Lindeijer <bjorn@lindeijer.nl>
Patricio Mac Adden <patriciomacadden@gmail.com>
Evan Hahn <me@evanhahn.com>
Starbeamrainbowlabs <contact@starbeamrainbowlabs.com>
Alexander Roper <minirop@gmail.com>

1
CNAME
View File

@ -1 +0,0 @@
wren.io

23
LICENSE Normal file
View File

@ -0,0 +1,23 @@
Wren uses the MIT License:
Copyright (c) 2013-2015 Robert Nystrom
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. (As clarification, there is no
requirement that the copyright notice and permission be included in binary
distributions of the Software.)
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

65
Makefile Normal file
View File

@ -0,0 +1,65 @@
# Top-level Makefile. This has targets for various utility things. To actually
# compile Wren itself, it invokes util/wren.mk for the various configurations
# that Wren can be built with.
# Executables are built to bin/. Libraries are built to lib/.
# A normal, optimized release build for the current CPU architecture.
release:
@ $(MAKE) -f util/wren.mk
@ cp bin/wren wren # For convenience, copy the interpreter to the top level.
# A debug build for the current architecture.
debug:
@ $(MAKE) -f util/wren.mk MODE=debug
# A release build of just the VM.
vm:
@ $(MAKE) -f util/wren.mk vm
# Build all configurations.
all: debug release
@ $(MAKE) -f util/wren.mk LANG=cpp
@ $(MAKE) -f util/wren.mk MODE=debug LANG=cpp
@ $(MAKE) -f util/wren.mk ARCH=32
@ $(MAKE) -f util/wren.mk LANG=cpp ARCH=32
@ $(MAKE) -f util/wren.mk MODE=debug ARCH=32
@ $(MAKE) -f util/wren.mk MODE=debug LANG=cpp ARCH=32
@ $(MAKE) -f util/wren.mk ARCH=64
@ $(MAKE) -f util/wren.mk LANG=cpp ARCH=64
@ $(MAKE) -f util/wren.mk MODE=debug ARCH=64
@ $(MAKE) -f util/wren.mk MODE=debug LANG=cpp ARCH=64
# Remove all build outputs and intermediate files. Does not remove downloaded
# dependencies. Use cleanall for that.
clean:
@ rm -rf bin
@ rm -rf build
@ rm -rf lib
# Remove all build outputs, intermediate files, and downloaded dependencies.
cleanall: clean
@ rm -rf deps
# Run the tests against the debug build of Wren.
test: debug
@ $(MAKE) -f util/wren.mk MODE=debug test
@ ./util/test.py $(suite)
# Generate the Wren site.
docs:
@ ./util/generate_docs.py
# Continuously generate the Wren site.
watchdocs:
@ ./util/generate_docs.py --watch
# Build the docs and copy them to a local "gh-pages" directory.
gh-pages: docs
@ cp -r build/docs/. build/gh-pages
# Build amalgamation of all Wren library files.
amalgamation: src/include/wren.h src/vm/*.h src/vm/*.c
./util/generate_amalgamation.py > build/wren.c
.PHONY: all amalgamation builtin clean debug docs gh-pages release test vm watchdocs

58
README.md Normal file
View File

@ -0,0 +1,58 @@
## Wren is a small, fast, class-based concurrent scripting language
Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in
a familiar, modern [syntax][].
```dart
System.print("Hello, world!")
class Wren {
flyTo(city) {
System.print("Flying to ", city)
}
}
var adjectives = Fiber.new {
["small", "clean", "fast"].each {|word| Fiber.yield(word) }
}
while (!adjectives.isDone) System.print(adjectives.call())
```
* **Wren is small.** The VM implementation is under [4,000 semicolons][src].
You can skim the whole thing in an afternoon. It's *small*, but not
*dense*. It is readable and [lovingly-commented][nan].
* **Wren is fast.** A fast single-pass compiler to tight bytecode, and a
compact object representation help Wren [compete with other dynamic
languages][perf].
* **Wren is class-based.** There are lots of scripting languages out there,
but many have unusual or non-existent object models. Wren places
[classes][] front and center.
* **Wren is concurrent.** Lightweight [fibers][] are core to the execution
model and let you organize your program into an army of communicating
coroutines.
* **Wren is a scripting language.** Wren is intended for embedding in
applications. It has no dependencies, a small standard library,
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, [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)
[syntax]: http://munificent.github.io/wren/syntax.html
[src]: https://github.com/munificent/wren/tree/master/src
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
[perf]: http://munificent.github.io/wren/performance.html
[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
[started]: http://munificent.github.io/wren/getting-started.html
[browser]: http://ppvk.github.io/wren-nest/
[contribute]: http://munificent.github.io/wren/contributing.html

View File

@ -1,105 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Hello Wren &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</nav>
<nav class="small">
<table>
<tr>
<td>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Hello Wren</h2>
<p>4 Feb 2019</p>
<hr />
<p>Welcome to the new Wren development blog!</p>
<p>Around November 2018 on the Wren mailing list, munificent announced that a new maintainer is taking over the development and maintainence of the Wren language. <a href="https://groups.google.com/forum/#!topic/wren-lang/cMUwij-NIn0">The original post is here, with all the details.</a></p>
<p>In short, <a href="https://github.com/ruby0x1">I&rsquo;m (ruby0x1)</a> taking over from <a href="https://github.com/munificent">Bob (munificent)</a> as maintainer, but Bob is sticking around as a contributor!</p>
<h3>The Wren blog <a href="#the-wren-blog" name="the-wren-blog" class="header-anchor">#</a></h3>
<p>One of the first things I felt Wren needed going forward is a consistent and centralized place to talk about the language. The existing design choices and goals, and especially the future and evolution of Wren are something a lot of people want to read about, in detail. Now we have a place to do exactly that!</p>
<p>The blog will be keeping in the spirit of Wren by remaining simple. Posts are just regular markdown files in the repository alongside the rest of the site, and are considered part of the documentation.</p>
<p>Since Wren as a project aims to help others learn, having the in depth thought processes, development details and technical intricacy be documented in the same place, over a timeline, is valuable.</p>
<h3>What&rsquo;s next for Wren? <a href="#what's-next-for-wren" name="what's-next-for-wren" class="header-anchor">#</a></h3>
<p>First and foremost, I wanted to state explicitly that <strong>Wren is going to be changing</strong> but it is <strong>not going to become something else</strong>. </p>
<p>Wren attracted me as a language because of what it <em>is</em>, not because it isn&rsquo;t {<em>other language</em>}. If I wanted to use {<em>other language</em>} I would have, but I chose Wren because I wanted what it was. </p>
<p>So, Wren is going to be changing in ways that align with it&rsquo;s existing design intentions. Staying small, simple, learnable and hackable is all vital to what makes Wren valuable, and will remain. </p>
<p>We&rsquo;re just as excited as you are to get to longer term changes and fun tweaks (we have lots of work done already in local projects like <a href="https://i.imgur.com/dazexnY.gifv">the debugger</a>). There&rsquo;s plenty of ideas we&rsquo;ve tried since we&rsquo;ve been <a href="https://luxeengine.com">using Wren full time</a> the last 2.5+ years, and can&rsquo;t wait to get started with bring those into the main branch (and optional modules). There&rsquo;s a lot to do!</p>
<p>In the next blog I want to try talk a bit more about the short to medium term goals and roadmap (rather than mixing it here with the meta/hello world post). Be sure to keep an eye out for that one, as it has more juicy details on what we&rsquo;re gonna get up to.</p>
<p>There are immediate term goals, though.</p>
<h3>First steps <a href="#first-steps" name="first-steps" class="header-anchor">#</a></h3>
<p>I think it&rsquo;s important to reset the baseline before we shake things up too much. Think of it as a ramp up to gain momentum, rather than running into a china store with arms flailing. </p>
<ul>
<li>We&rsquo;re gonna clear out a bit of backlog, tidying up issues and PRs</li>
<li>Tidy up the website a bit, visually and structurally</li>
<li>Make sure all documentation is up to date with the current development</li>
<li>Tag 0.2.0 with a list of relevant changes since 0.1.0</li>
</ul>
<p>Once we tag 0.2.0, we&rsquo;ll be in a good place to move forward. And, everything up until now will have a well defined checkpoint preserved, if people want to refer to it.</p>
<h3>Steps so far <a href="#steps-so-far" name="steps-so-far" class="header-anchor">#</a></h3>
<p>Since the announcement and transition, I&rsquo;ve been making my way through all the mailing list posts, issues and PRs in the backlog and reading all the way back to the early days. </p>
<p>I&rsquo;ve also been talking to community members one on one and getting personal experiences and thoughts on Wren. Forming a full picture will help us since we&rsquo;ll have an overview of what&rsquo;s most relevant (and what isn&rsquo;t) as time has passed, and gives us actionable things to do for the next milestone. I think it&rsquo;s an important step. </p>
<p>We&rsquo;ve also been investigating some of the PRs with the community to get those sorted out, since they&rsquo;re in the way.</p>
<p>Lastly, I&rsquo;ve already done a bit of clean up on the website and documentation theme, added a new logo, and of course added the blog.</p>
<h3>Thanks! <a href="#thanks" name="thanks" class="header-anchor">#</a></h3>
<p>Lastly, I wanted to say thanks to munificent, the community and all the contributors that have made Wren possible to this point. It&rsquo;s a wonderful thing and I look forward to seeing where we take it, together.</p>
<p>I hope you&rsquo;ll join us on the journey!</p>
<h3>More <a href="#more" name="more" class="header-anchor">#</a></h3>
<ul>
<li><a href="http://wren.io/blog/rss.xml">The Wren Blog RSS</a></li>
<li>Join the <a href="https://discord.gg/Kx6PxSX">discord community</a></li>
<li>Visit the <a href="https://github.com/wren-lang">wren-lang organization</a> on GitHub.</li>
<li>Follow <a href="https://twitter.com/munificentbob">@munificentbob</a> or <a href="https://twitter.com/ruby0x1">@ruby0x1</a> on twitter</li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,123 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>0.2.0 and beyond &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</nav>
<nav class="small">
<table>
<tr>
<td>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>0.2.0 and beyond</h2>
<p>30 Sep 2019</p>
<hr />
<h3>0.2.0 is here <a href="#0.2.0-is-here" name="0.2.0-is-here" class="header-anchor">#</a></h3>
<p>It&rsquo;s time to tag a release!
Let&rsquo;s check our goals from <a href="0-hello-wren.html">the last blog post</a>:</p>
<ul>
<li><s>We&rsquo;re gonna clear out a bit of backlog, tidying up issues and PRs</s></li>
<li><s>Tidy up the website a bit, visually and structurally</s></li>
<li><s>Make sure all documentation is up to date with the current development</s></li>
<li><s>Tag 0.2.0 with a list of relevant changes since 0.1.0</s></li>
</ul>
<p>So far so good.</p>
<h3>Backlog <a href="#backlog" name="backlog" class="header-anchor">#</a></h3>
<p>Clearing out the issues on a repo after some time has passed is always a bit tricky. </p>
<p>Many issues are outdated (or unrelated), and some need a proper response. Some are related to future ideals, things that will take a while to get to. Some are related to the Wren CLI. It can be difficult to reason about the state of the tasks when they&rsquo;re all over the place, so we&rsquo;ve been consolidating.</p>
<p>The good news is the issue list has been drastically reduced, 70+ issues being closed (or resolved). Around 21 of those are marked for future consideration, and 23 moved to the Wren CLI repository. More consolidation will still continue.</p>
<p><strong>The goal is that the active issues are as relevant as possible in the immediate term.</strong></p>
<p>A tricky but important aspect to mention here is the perception of closing an issue&hellip;
A closed issue doesn&rsquo;t necessarily mean anything final, it&rsquo;s just a categorization tool!</p>
<p>The other categorization tool which operates <em>within</em> open/closed categories, is the <em>label</em>. Labels allow us to distinguish clearly the different types of issues, which makes open/closed less binary and more nuanced and rich. We rely on both to make sense of the list.</p>
<p>For example, discussions of future tasks, ideas or goals <a href="https://github.com/wren-lang/wren/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+label%3Afuture+">are tagged <code>future</code></a>. Now we can refer to them later, and re-open them when they become active and relevant again.</p>
<p><strong>We&rsquo;re in this together.</strong> <br />
Please don&rsquo;t be discouraged if an issue is closed! Discussion is absolutely encouraged and ideas, proposals and input is very necessary. Feel free to keep a discussion going, even if the issue it&rsquo;s attached to has been marked as closed.</p>
<h3>0.2.0 <a href="#0.2.0" name="0.2.0" class="header-anchor">#</a></h3>
<p>We&rsquo;ve been hammering away on Wren since 0.1.0 for quite a while. The <a href="https://github.com/wren-lang/wren/compare/0.1.0...5338275dcdd97fd8d9fc614f420a645500836a59">change list on GitHub</a> is too long to display!</p>
<p>Most importantly, before we start iterating on the language further, I wanted to make sure we had a checkpoint to look back to. That&rsquo;s largely what 0.2.0 is about.</p>
<p>There&rsquo;s quite a lot of good changes, with <strong>290 commits from 41 contributors!</strong>
Thanks to everyone getting involved, every little bit has helped Wren, no matter how small the contribution.</p>
<h3>0.3.0 <a href="#0.3.0" name="0.3.0" class="header-anchor">#</a></h3>
<p>With 0.2.0 wrapped up, our next release won&rsquo;t be as far away this time.</p>
<p><strong>The primary goal for 0.3.0 is separating the VM from the CLI.</strong></p>
<p>This includes updated documentation, splitting the source repos, migrating all the tests, issues and more.
All the code and documentation will still be easy to access in one place, but clarity around Wren as a project will improve a lot.</p>
<p>The migration has already started, you can <a href="https://github.com/wren-lang/wren-cli">find the wren-cli repository here</a>.
I&rsquo;m working on some of the refactoring on the <a href="https://github.com/wren-lang/wren/tree/wren-cli-refactor">wren-cli-refactor branch.</a></p>
<p>With that, we&rsquo;ll also have a cleaner build process for the CLI.
On some platforms (Windows especially), there have been several pain points, these will be addressed.
There&rsquo;s also gonna be an additional build target, namely emscripten, so we can easily run Wren examples on the Wren website and documentation.</p>
<p>And finally, we&rsquo;ll have some proper prebuilt releases with 0.3.0.
I know many people have just wanted to grab an executable and give the language a go, but that hasn&rsquo;t been an option.
We&rsquo;ll fix that with 0.3.0.</p>
<p>The 0.3.0 goals in simple form:
- VM / CLI split
- Build consistency/reliablity
- Web build for embedding in docs
- Prebuilt releases</p>
<h3>Beyond <a href="#beyond" name="beyond" class="header-anchor">#</a></h3>
<p>I don&rsquo;t have any concrete plans for 0.4.0 right now, but once the dust settles from 0.3.0 we&rsquo;ll have a clearer view.</p>
<p>There&rsquo;s definitely things in the pipeline though, I&rsquo;ve been playing with <a href="https://github.com/wren-lang/wren/pull/701">adding compound assignments like <code>+=</code></a>.</p>
<p>More details about in development features and fixes can be found on the repo in the meantime.</p>
<p>Thanks for reading!</p>
<h3>More <a href="#more" name="more" class="header-anchor">#</a></h3>
<ul>
<li><a href="http://wren.io/blog/rss.xml">The Wren Blog RSS</a></li>
<li>Join the <a href="https://discord.gg/Kx6PxSX">discord community</a></li>
<li>Visit the <a href="https://github.com/wren-lang">wren-lang organization</a> on GitHub to get involved.</li>
<li>Follow the developers <a href="https://twitter.com/munificentbob">@munificentbob</a> or <a href="https://twitter.com/ruby0x1">@ruby0x1</a> on twitter</li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,170 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>0.3.0 released! &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</nav>
<nav class="small">
<table>
<tr>
<td>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>0.3.0 released!</h2>
<p>5 June 2020</p>
<hr />
<p>In this post we&rsquo;ll cover 0.3.0 and the goals for 0.4.0 <a href="#goals-for-0.4.0">#</a>.</p>
<h2>About the 0.3.0 release <a href="#about-the-0.3.0-release" name="about-the-0.3.0-release" class="header-anchor">#</a></h2>
<p>Let&rsquo;s revisit our goals from <a href="1-0.2.0-and-beyond.html">the last blog post</a>, <br />
and mark what we managed to get done:</p>
<ul>
<li><s>VM / CLI split</s> <a href="#vm--cli-split">#</a></li>
<li><s>Build consistency/reliablity</s> <a href="#build-consistencyreliability">#</a></li>
<li><s>Web build for embedding in docs</s> <a href="#web-build-for-embedding-in-docs">#</a></li>
<li><s>Prebuilt releases</s> <a href="#prebuilt-releases">#</a></li>
</ul>
<h2>The details <a href="#the-details" name="the-details" class="header-anchor">#</a></h2>
<h3>VM / CLI split <a href="#vm--cli-split" name="vm--cli-split" class="header-anchor">#</a></h3>
<p>With 0.3.0 we&rsquo;ve separated the CLI from the Wren repo,
and updated the docs to make the distinction clearer.</p>
<p>The <a href="../cli">CLI now has its own corner of the docs</a>, so that the modules
and API docs aren&rsquo;t overlapped like before. This opens up space for the
CLI to get better, fuller documentation, and removes confusion about
built in modules vs ones that are in the CLI only.</p>
<p>The code structure is clearer, too, and all the tests and utils are now specific.</p>
<h3>Build consistency/reliability <a href="#build-consistencyreliability" name="build-consistencyreliability" class="header-anchor">#</a></h3>
<p>Previously, builds on Windows could be a little fickle, and there was sometimes
issues with the dependencies on the CLI side.</p>
<p>To solve this, premake is now used to generate platform specific project files that
&lsquo;just work&rsquo;, making it a one step process to build the VM or CLI. Both projects
now have a <code>projects/</code> folder which includes ready to go project files for primary platforms.</p>
<p><small>The original <code>Makefile</code> and <code>util/wren.mk</code> no longer exist, so there might be some work needed
to reintegrate if you relied on those. You can find the updated makefile in <code>projects/make/</code>, or <code>projects/make.mac/</code>.</small></p>
<p>The <strong>amalgamated build</strong> was fixed too, so that embedding in your own project is as simple as
including a single c file (and the <code>wren.h</code> header).</p>
<p>On the <strong>CLI</strong> side, the pre-build steps were removed and dependencies vendored in repo,
so that the project just builds with less potential points of error, especially across platforms.</p>
<p>And finally the <strong>docs</strong>! Previously <a href="https://sass-lang.com/">SASS</a> was used, and code highlighting
was done at generation time using pygments, a python code highlighter. Both of these dependencies
have been removed, code highlighting is now done on the client side instead (see another reason why below).
The benefit here that it is now <em>easy</em> to edit the docs, just a simple python command, no setup!</p>
<h3>Web build for embedding in docs <a href="#web-build-for-embedding-in-docs" name="web-build-for-embedding-in-docs" class="header-anchor">#</a></h3>
<p>The goal was two part here, one is to have a page to just try out Wren.
Type in some code, run it. That&rsquo;s the first big step and we&rsquo;ve now got that on the docs page.</p>
<h4><a href="../try" target="_blank" class="dark-link">Try Wren directly in your browser!</a></h4>
<p>This should work on desktop or mobile, and will continue to be improved over time.</p>
<p>The second part of that goal is having the VM available to make examples on each page interactive.
This is implemented, <em>but not activated on any pages yet</em>.</p>
<p>In the near future inline doc examples will have a small button that you can
press to see the code result right there, live. Since there&rsquo;s a lot of examples,
and sometimes they&rsquo;re fragments of code that don&rsquo;t run in isolation,
it will take time to propagate it through the pages.</p>
<p>Mainly, I didn&rsquo;t want this to hold up 0.3.0, but expect to start seeing it soon.</p>
<h3>Prebuilt releases <a href="#prebuilt-releases" name="prebuilt-releases" class="header-anchor">#</a></h3>
<p>In addition to the browser based build that removes a barrier to trying out Wren,
Wren CLI has prebuilt binaries for Mac, Windows and Linux now! This gives
an easy path to just tinkering with Wren before embedding it.</p>
<hr />
<h2>Goals for 0.4.0 <a href="#goals-for-0.4.0" name="goals-for-0.4.0" class="header-anchor">#</a></h2>
<p>With 0.4.0 the goal is to address a couple of bigger todos, but also to push the language
itself, and the embedding experience forward.</p>
<p>You can see some of the <a href="https://github.com/wren-lang/wren/pulls?q=is%3Apr+is%3Aopen+label%3A0.4.0">work in progress tasks</a> here,
but there&rsquo;s a few things I&rsquo;d like to resolve in 0.4.0.</p>
<p><strong>Compound operators</strong> <br />
I&rsquo;ve really missed having <code>+=</code> and friends, <br />
so I&rsquo;ve been working on a (broken, wip) <a href="https://github.com/wren-lang/wren/pull/701">PR here</a>.
I&rsquo;ve since had a better idea to implement it and will hope to address that in 0.4.0.</p>
<p><strong>Chained methods (&lsquo;fluent interfaces&rsquo;)</strong> <br />
Currently in Wren it&rsquo;s required that the period (<code>.</code>) be on the same line as the method.</p>
<pre class="snippet">
example.
some().
functions().
here()
</pre>
<p>This isn&rsquo;t as elegant as we&rsquo;d want for this form of API,
so <strong>in 0.4.0 the goal is</strong> allowing a newline, as you&rsquo;d expect:</p>
<pre class="snippet">
example
.some()
.functions()
.here()
</pre>
<p>This doesn&rsquo;t seem like a big deal but when your calls are wider,
longer and possibly accept block functions. It&rsquo;s hard to read,
and can be less fun to track down a missing <code>.</code> in a big chunk of code.</p>
<pre class="snippet">
example.
some {|args, and, stuff|
...
}.
here()
</pre>
<p><strong>C Side APIs</strong> <br />
Some APIs for dealing with <code>Map</code> have been proposed several times,
it&rsquo;s time to bring that into the API. There&rsquo;s some additions for <code>List</code> as well,
like a helper to set an element in a list.</p>
<p><strong>Other goals</strong> <br />
There&rsquo;s a few more things but I&rsquo;m still exploring their viability. <br />
Keep an eye on the <a href="https://github.com/wren-lang/wren">PRs/issues</a> or the <a href="https://github.com/wren-lang/wren/pulls?q=is%3Apr+is%3Aopen+label%3A0.4.0">0.4.0 label</a> to see when they&rsquo;re discussed.</p>
<h2>Till next time <a href="#till-next-time" name="till-next-time" class="header-anchor">#</a></h2>
<hr />
<ul>
<li><a href="http://wren.io/blog/rss.xml">The Wren Blog RSS</a></li>
<li>Join the <a href="https://discord.gg/Kx6PxSX">discord community</a></li>
<li>Visit the <a href="https://github.com/wren-lang">wren-lang organization</a> on GitHub to get involved.</li>
<li>Follow the developers <a href="https://twitter.com/munificentbob">@munificentbob</a> or <a href="https://twitter.com/ruby0x1">@ruby0x1</a> on twitter</li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,206 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>0.4.0 released! &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</nav>
<nav class="small">
<table>
<tr>
<td>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>0.4.0 released!</h2>
<p>8 April 2021</p>
<hr />
<p>This post is all about the 0.4.0 release since it&rsquo;s a big one! <br />
<small>(A separate post for 0.5.0 goals would likely come later.)</small></p>
<h2>0.4.0 details <a href="#0.4.0-details" name="0.4.0-details" class="header-anchor">#</a></h2>
<p><strong>0.4.0 contains 145 commits from 28 contributors.</strong></p>
<p>The <a href="https://github.com/wren-lang/wren/releases/tag/0.4.0">full release notes</a>
link to each PR or commit, and contains a lot more details than this post.</p>
<p><strong>Goals</strong> <br />
As usual, let&rsquo;s revisit the goals from the <a href="2-0.3.0-released.html#goals-for-0.4.0">0.3.0 post</a>.</p>
<p>Most importantly - compound operators didn&rsquo;t land in 0.4.0 for various reasons.
Still working on it, it&rsquo;s just a fun and nuanced problem and I don&rsquo;t want to
keep 0.4.0 back cos of it.</p>
<p>With that out the way, let&rsquo;s see what 0.4.0 contains! </p>
<h2>0.4.0 highlights <a href="#0.4.0-highlights" name="0.4.0-highlights" class="header-anchor">#</a></h2>
<p>Below we&rsquo;ll highlight some key features, fixes and improvements from the release. </p>
<p><strong>A lot of work came from the community, much thanks to everyone contributing!</strong></p>
<p>You can find all the details and the contributions in the <a href="https://github.com/wren-lang/wren/releases/tag/0.4.0">release notes</a>.</p>
<p><strong>Take note!</strong> There are two minor breaking changes in the API on the release notes. </p>
<hr />
<h3>Bug fixes <a href="#bug-fixes" name="bug-fixes" class="header-anchor">#</a></h3>
<p>Several important bugs have been fixed, sneaky stack corruptions and some user
experience fixes that clarify confusing states. </p>
<h3>Documentation <a href="#documentation" name="documentation" class="header-anchor">#</a></h3>
<p>A lot of work has gone into documentation this release, revising, fixing, adding
and closing gaps that were left. For example, Wren supports multi-line strings
but this was never mentioned anywhere! </p>
<h3>New <strong>continue</strong> keyword <a href="#new-continue-keyword" name="new-continue-keyword" class="header-anchor">#</a></h3>
<p>Loops can now use continue, which is a welcome addition.</p>
<h3>New <strong>as</strong> keyword <a href="#new-as-keyword" name="new-as-keyword" class="header-anchor">#</a></h3>
<p>You can now use <code>import "..." for Name as OtherName</code> to avoid name conflicts,
or to use aliases/shorthand for imported variables.</p>
<h3>Raw strings <a href="#raw-strings" name="raw-strings" class="header-anchor">#</a></h3>
<p>Wren now supports triple quotes for a string <code>"""</code>.</p>
<p>This type of string is only unique in how it&rsquo;s parsed, the content of the
string is ignored (no interpolation or escapes are processed), which allows
complex strings to be expressed without needing to escape things. </p>
<p>A common example is json or regex, where there&rsquo;s a lot of escaping that obscures
the string content and makes it hard to read and maintain. </p>
<p>If they span multiple lines, the string ignores the open and closing newlines
and whitespace and preserves anything in between.</p>
<pre class="snippet">
var json = """
{
"hello": "wren",
"from" : "json"
}
"""
</pre>
<h3>Attributes <a href="#attributes" name="attributes" class="header-anchor">#</a></h3>
<p>Attributes are user-defined metadata associated with a class or method that
can be used at runtime, by external tools (and potentially by Wren itself).</p>
<pre class="snippet">
#hidden = true
#doc = "A simple example class"
class Example {}
</pre>
<p>They can be:</p>
<ul>
<li>a <code>#key</code> on it&rsquo;s own</li>
<li>a <code>#key = value</code></li>
<li>a <code>#group(with, multiple = true, keys = "value")</code></li>
</ul>
<p><strong>Example</strong> </p>
<p>Below you can one obvious use case, a wip version where attributes for docs were
parsed and sent over to <a href="https://code.visualstudio.com/">vscode</a> to display.</p>
<video preload="auto" controls="" loop="loop" style="max-width:100%; width:auto; margin:auto; display:block;">
<source src="https://i.imgur.com/W9DWysP.mp4" type="video/mp4">
</video>
<p><strong>Runtime access</strong> <br />
By default, attributes are compiled out and ignored.
For an attribute to be visible at runtime, mark it for runtime access using an
exclamation:</p>
<pre class="snippet">
#doc = "not runtime data"
#!runtimeAccess = true
#!maxIterations = 16
</pre>
<p>Attributes at runtime are stored on the class itself. You can access them via
<code>YourClass.attributes</code>. If any attributes are made available, they&rsquo;ll be found here:</p>
<ul>
<li><code>YourClass.attributes.self</code> for the class attributes</li>
<li><code>YourClass.attributes.methods</code> for the method attributes</li>
</ul>
<p>All the details for <a href="https://wren.io/classes.html#attributes">Attributes can be found here</a>.</p>
<h3>Chained methods fixes (&lsquo;fluent interfaces&rsquo;) <a href="#chained-methods-fixes-('fluent-interfaces')" name="chained-methods-fixes-('fluent-interfaces')" class="header-anchor">#</a></h3>
<p>Mentioned in the last post, you can now use this pattern in code as intended,
the same-line requirement for the <code>.</code> has been removed.</p>
<pre class="snippet">
example
.some()
.functions()
.here()
</pre>
<h3>List additions <a href="#list-additions" name="list-additions" class="header-anchor">#</a></h3>
<p>Lists are now sortable via <code>list.sort()</code> and <code>list.sort {|a, b| ... }</code>.
You can find an index of something via <code>list.indexOf(value)</code>, and remove a value
via <code>list.remove(value)</code>. There&rsquo;s also <code>list.swap(index0, index1)</code> for moving
items around within a list.</p>
<p>For the API, <code>wrenSetListElement</code> now exists, and both set and
<code>wrenGetListElement</code> now accept negative indices same as the language side.</p>
<h3>Num additions <a href="#num-additions" name="num-additions" class="header-anchor">#</a></h3>
<p>A few new constants:</p>
<ul>
<li><code>Num.tau</code></li>
<li><code>Num.nan</code> </li>
<li><code>Num.infinity</code></li>
<li><code>Num.minSafeInteger</code>/<code>Num.maxSafeInteger</code></li>
</ul>
<p>And some new methods on a number:</p>
<ul>
<li><code>num.min(other)</code></li>
<li><code>num.max(other)</code></li>
<li><code>num.clamp(min, max)</code></li>
<li><code>num.cbrt</code></li>
<li><code>num.exp</code></li>
<li><code>num.log2</code></li>
</ul>
<h3>Map access from the API <a href="#map-access-from-the-api" name="map-access-from-the-api" class="header-anchor">#</a></h3>
<p>You can now create and access maps from the API:</p>
<ul>
<li><code>wrenSetSlotNewMap</code></li>
<li><code>wrenGetMapCount</code></li>
<li><code>wrenGetMapContainsKey</code></li>
<li><code>wrenGetMapValue</code></li>
<li><code>wrenSetMapValue</code></li>
<li><code>wrenRemoveMapValue</code></li>
</ul>
<h2>Till next time <a href="#till-next-time" name="till-next-time" class="header-anchor">#</a></h2>
<hr />
<ul>
<li><a href="http://wren.io/blog/rss.xml">The Wren Blog RSS</a></li>
<li>Join the <a href="https://discord.gg/Kx6PxSX">discord community</a></li>
<li>Visit the <a href="https://github.com/wren-lang">wren-lang organization</a> on GitHub to get involved.</li>
<li>Follow the developers <a href="https://twitter.com/munificentbob">@munificentbob</a> or <a href="https://twitter.com/ruby0x1">@ruby0x1</a> on twitter</li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,81 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Development blogs &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</nav>
<nav class="small">
<table>
<tr>
<td>
<ul>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../contributing.html">Contributing</a></li>
<li><a href="../blog">Blog</a></li>
<li><a href="../try">Try it!</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Development blogs</h2>
<p><a href="3-0.4.0-released.html"><h3>0.4.0 released!</h3></a></p>
<blockquote>
<p><date>8 April 2021</date> • 0.4.0 is a big release, here&rsquo;s all the info! </p>
</blockquote>
<p><a href="2-0.3.0-released.html"><h3>0.3.0 released!</h3></a></p>
<blockquote>
<p><date>5 June 2020</date> • 0.3.0 release info! Plus some notes and goals for the next release, 0.4.0.</p>
</blockquote>
<p><a href="1-0.2.0-and-beyond.html"><h3>0.2.0 and beyond</h3></a></p>
<blockquote>
<p><date>30 Sep 2019</date> • Checkpoints, and the plans for 0.3.0.</p>
</blockquote>
<p><a href="0-hello-wren.html"><h3>System.print(&ldquo;hello wren&rdquo;)</h3></a></p>
<blockquote>
<p><date>4 Feb 2019</date> • A short post introducing the blog, the new maintainer, and the immediate term plans for Wren.</p>
</blockquote>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,35 +0,0 @@
<rss version="2.0">
<channel><title>Wren - development blog</title>
<link>https://wren.io/</link>
<description>The development blog of the Wren programming language.</description>
<language>en-us</language>
<item>
<title>0.4.0 released</title>
<link>https://wren.io/blog/3-0.4.0-released.html</link>
<description>0.4.0 is a big release, here's all the info!</description>
<guid>https://wren.io/blog/3-0.4.0-released.html</guid>
<pubDate>Thu, 08 Apr 2021 00:00:00 GMT</pubDate>
</item>
<item>
<title>0.3.0 released</title>
<link>https://wren.io/blog/2-0.3.0-released.html</link>
<description>0.3.0 release info! Plus some notes and goals for the next release, 0.4.0.</description>
<guid>https://wren.io/blog/2-0.3.0-released.html</guid>
<pubDate>Mon, 05 Jun 2020 00:00:00 GMT</pubDate>
</item>
<item>
<title>0.2.0 and beyond</title>
<link>https://wren.io/blog/1-0.2.0-and-beyond.html</link>
<description>Checkpoints, and the plans for 0.3.0.</description>
<guid>https://wren.io/blog/1-0.2.0-and-beyond.html</guid>
<pubDate>Mon, 30 Sep 2019 00:00:00 GMT</pubDate>
</item>
<item>
<title>System.print("hello wren")</title>
<link>https://wren.io/blog/0-hello-wren.html</link>
<description>A short post introducing the blog, the new maintainer, and the immediate term plans for Wren.</description>
<guid>https://wren.io/blog/0-hello-wren.html</guid>
<pubDate>Mon, 04 Feb 2019 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>

9
builtin/README.md Normal file
View File

@ -0,0 +1,9 @@
The Wren scripts in this directory get converted to C string literals into files
with a `.wren.inc` extension. Those are then `#include`d 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 translation is `util/wren_to_c_string.py`.
When any of the ".wren" files in here are changed, the Makefile automatically
updates the generated C headers.

288
builtin/core.wren Normal file
View File

@ -0,0 +1,288 @@
class Bool {}
class Fiber {}
class Fn {}
class Null {}
class Num {}
class Sequence {
all(f) {
var result = true
for (element in this) {
result = f.call(element)
if (!result) return result
}
return result
}
any(f) {
var result = false
for (element in this) {
result = f.call(element)
if (result) return result
}
return result
}
contains(element) {
for (item in this) {
if (element == item) return true
}
return false
}
count {
var result = 0
for (element in this) {
result = result + 1
}
return result
}
count(f) {
var result = 0
for (element in this) {
if (f.call(element)) result = result + 1
}
return result
}
each(f) {
for (element in this) {
f.call(element)
}
}
isEmpty { iterate(null) ? false : true }
map(transformation) { MapSequence.new(this, transformation) }
where(predicate) { WhereSequence.new(this, predicate) }
reduce(acc, f) {
for (element in this) {
acc = f.call(acc, element)
}
return acc
}
reduce(f) {
var iter = iterate(null)
if (!iter) Fiber.abort("Can't reduce an empty sequence.")
// Seed with the first element.
var result = iteratorValue(iter)
while (iter = iterate(iter)) {
result = f.call(result, iteratorValue(iter))
}
return result
}
join() { join("") }
join(sep) {
var first = true
var result = ""
for (element in this) {
if (!first) result = result + sep
first = false
result = result + element.toString
}
return result
}
toList {
var result = List.new()
for (element in this) {
result.add(element)
}
return result
}
}
class MapSequence is Sequence {
construct new(sequence, fn) {
_sequence = sequence
_fn = fn
}
iterate(iterator) { _sequence.iterate(iterator) }
iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }
}
class WhereSequence is Sequence {
construct new(sequence, fn) {
_sequence = sequence
_fn = fn
}
iterate(iterator) {
while (iterator = _sequence.iterate(iterator)) {
if (_fn.call(_sequence.iteratorValue(iterator))) break
}
return iterator
}
iteratorValue(iterator) { _sequence.iteratorValue(iterator) }
}
class String is Sequence {
bytes { StringByteSequence.new(this) }
codePoints { StringCodePointSequence.new(this) }
static interpolate(interpolation) {
var result = ""
for (part in interpolation.parts) {
if (part is String) {
result = result + part
} else {
result = result + part.call().toString
}
}
return result
}
}
class StringByteSequence is Sequence {
construct new(string) {
_string = string
}
[index] { _string.byteAt_(index) }
iterate(iterator) { _string.iterateByte_(iterator) }
iteratorValue(iterator) { _string.byteAt_(iterator) }
count { _string.byteCount_ }
}
class StringCodePointSequence is Sequence {
construct new(string) {
_string = string
}
[index] { _string.codePointAt_(index) }
iterate(iterator) { _string.iterate(iterator) }
iteratorValue(iterator) { _string.codePointAt_(iterator) }
count { _string.count }
}
class StringInterpolation {
parts { _parts }
construct new_(list) {
_parts = [list[0]]
var i = 1
while (i < list.count) {
_parts.add(InterpolatedField.new_(list[i], list[i + 1]))
_parts.add(list[i + 2])
i = i + 3
}
}
}
class InterpolatedField {
construct new_(fn, source) {
_fn = fn
_source = source
}
call() { _fn.call() }
source { _source }
}
class List is Sequence {
addAll(other) {
for (element in other) {
add(element)
}
return other
}
toString { "[" + join(", ") + "]" }
+(other) {
var result = this[0..-1]
for (element in other) {
result.add(element)
}
return result
}
}
class Map {
keys { MapKeySequence.new(this) }
values { MapValueSequence.new(this) }
toString {
var first = true
var result = "{"
for (key in keys) {
if (!first) result = result + ", "
first = false
result = result + key.toString + ": " + this[key].toString
}
return result + "}"
}
}
class MapKeySequence is Sequence {
construct new(map) {
_map = map
}
iterate(n) { _map.iterate_(n) }
iteratorValue(iterator) { _map.keyIteratorValue_(iterator) }
}
class MapValueSequence is Sequence {
construct new(map) {
_map = map
}
iterate(n) { _map.iterate_(n) }
iteratorValue(iterator) { _map.valueIteratorValue_(iterator) }
}
class Range is Sequence {}
class System {
static print() {
writeString_("\n")
}
static print(obj) {
writeObject_(obj)
writeString_("\n")
return obj
}
static printAll(sequence) {
for (object in sequence) writeObject_(object)
writeString_("\n")
}
static write(obj) {
writeObject_(obj)
return obj
}
static writeAll(sequence) {
for (object in sequence) writeObject_(object)
}
static writeObject_(obj) {
var string = obj.toString
if (string is String) {
writeString_(string)
} else {
writeString_("[invalid toString]")
}
}
}

1
builtin/meta.wren Normal file
View File

@ -0,0 +1 @@
class Meta {}

View File

@ -1,778 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Classes &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Classes</h2>
<p>Every value in Wren is an object, and every object is an instance of a class.
Even <code>true</code> and <code>false</code> are full-featured objects&mdash;instances of the
<a href="modules/core/bool.html">Bool</a> class.</p>
<p>Classes define an objects <em>behavior</em> and <em>state</em>. Behavior is defined by
<a href="method-calls.html"><em>methods</em></a> which live in the class. Every object of the same
class supports the same methods. State is defined in <em>fields</em>, whose values are
stored in each instance.</p>
<h2>Defining a class <a href="#defining-a-class" name="defining-a-class" class="header-anchor">#</a></h2>
<p>Classes are created using the <code>class</code> keyword, unsurprisingly:</p>
<pre class="snippet">
class Unicorn {}
</pre>
<p>This creates a class named <code>Unicorn</code> with no methods or fields.</p>
<h2>Methods <a href="#methods" name="methods" class="header-anchor">#</a></h2>
<p>To let our unicorn do stuff, we need to give it methods.</p>
<pre class="snippet">
class Unicorn {
prance() {
System.print("The unicorn prances in a fancy manner!")
}
}
</pre>
<p>This defines a <code>prance()</code> method that takes no arguments. To add parameters, put
their names inside the parentheses:</p>
<pre class="snippet">
class Unicorn {
prance(where, when) {
System.print("The unicorn prances in %(where) at %(when).")
}
}
</pre>
<p>Since the number of parameters is part of a method&rsquo;s <a href="method-calls.html#signature">signature</a> a class can
define multiple methods with the same name:</p>
<pre class="snippet">
class Unicorn {
prance() {
System.print("The unicorn prances in a fancy manner!")
}
prance(where) {
System.print("The unicorn prances in %(where).")
}
prance(where, when) {
System.print("The unicorn prances in %(where) at %(when).")
}
}
</pre>
<p>It&rsquo;s often natural to have the same conceptual operation work with different
sets of arguments. In other languages, you&rsquo;d define a single method for the
operation and have to check for missing optional arguments. In Wren, they are
different methods that you implement separately.</p>
<p>In addition to named methods with parameter lists, Wren has a bunch of other
different syntaxes for methods. Your classes can define all of them.</p>
<h3>Getters <a href="#getters" name="getters" class="header-anchor">#</a></h3>
<p>A getter leaves off the parameter list and the parentheses:</p>
<pre class="snippet">
class Unicorn {
// Unicorns are always fancy.
isFancy { true }
}
</pre>
<h3>Setters <a href="#setters" name="setters" class="header-anchor">#</a></h3>
<p>A setter has <code>=</code> after the name, followed by a single parenthesized parameter:</p>
<pre class="snippet">
class Unicorn {
rider=(value) {
System.print("I am being ridden by %(value).")
}
}
</pre>
<p>By convention, the parameter is usually named <code>value</code> but you can call it
whatever makes your heart flutter.</p>
<h3>Operators <a href="#operators" name="operators" class="header-anchor">#</a></h3>
<p>Prefix operators, like getters, have no parameter list:</p>
<pre class="snippet">
class Unicorn {
- {
System.print("Negating a unicorn is weird.")
}
}
</pre>
<p>Infix operators, like setters, have a single parenthesized parameter for the
right-hand operand:</p>
<pre class="snippet">
class Unicorn {
-(other) {
System.print("Subtracting %(other) from a unicorn is weird.")
}
}
</pre>
<p>A subscript operator puts the parameters inside square brackets and can have
more than one:</p>
<pre class="snippet">
class Unicorn {
[index] {
System.print("Unicorns are not lists!")
}
[x, y] {
System.print("Unicorns are not matrices either!")
}
}
</pre>
<p>Unlike with named methods, you can&rsquo;t define a subscript operator with an empty
parameter list.</p>
<p>As the name implies, a subscript setter looks like a combination of a subscript
operator and a setter:</p>
<pre class="snippet">
class Unicorn {
[index]=(value) {
System.print("You can't stuff %(value) into me at %(index)!")
}
}
</pre>
<h2>Method Scope <a href="#method-scope" name="method-scope" class="header-anchor">#</a></h2>
<p>Up to this point, &ldquo;<a href="variables.html#scope">scope</a>&rdquo; has been used to talk exclusively about
<a href="variables.html">variables</a>. In a procedural language like C, or a functional one like Scheme,
that&rsquo;s the only kind of scope there is. But object-oriented languages like Wren
introduce another kind of scope: <em>object scope</em>. It contains the methods that
are available on an object. When you write:</p>
<pre class="snippet">
unicorn.isFancy
</pre>
<p>You&rsquo;re saying &ldquo;look up the method <code>isFancy</code> in the scope of the object
<code>unicorn</code>&rdquo;. In this case, the fact that you want to look up a <em>method</em>
<code>isFancy</code> and not a <em>variable</em> <code>isFancy</code> is explicit. That&rsquo;s what <code>.</code> does and
the object to the left of the period is the object you want to look up the
method on.</p>
<h3><code>this</code> <a href="#this" name="this" class="header-anchor">#</a></h3>
<p>Things get more interesting when you&rsquo;re inside the body of a method. When the
method is called on some object and the body is being executed, you often need
to access that object itself. You can do that using <code>this</code>.</p>
<pre class="snippet">
class Unicorn {
name { "Francis" }
printName() {
System.print(this.name) //> Francis
}
}
</pre>
<p>The <code>this</code> keyword works sort of like a variable, but has special behavior. It
always refers to the instance whose method is currently being executed. This
lets you invoke methods on &ldquo;yourself&rdquo;.</p>
<p>It&rsquo;s an error to refer to <code>this</code> outside of a method. However, it&rsquo;s perfectly
fine to use it inside a <a href="functions.html">function</a> declared <em>inside</em> a method. When you do,
<code>this</code> still refers to the instance whose <em>method</em> is being called:</p>
<pre class="snippet">
class Unicorn {
name { "Francis" }
printNameThrice() {
(1..3).each {
// Use "this" inside the function passed to each().
System.print(this.name) //> Francis
} //> Francis
} //> Francis
}
</pre>
<p>This is unlike Lua and JavaScript which can &ldquo;forget&rdquo; <code>this</code> when you create a
callback inside a method. Wren does what you want here and retains the
reference to the original object.</p>
<p>(In technical terms, a function&rsquo;s closure includes <code>this</code>. Wren can do this
because it makes a distinction between methods and functions.)</p>
<h3>Implicit <code>this</code> <a href="#implicit-this" name="implicit-this" class="header-anchor">#</a></h3>
<p>Using <code>this.</code> every time you want to call a method on yourself works, but it&rsquo;s
tedious and verbose, which is why some languages don&rsquo;t require it. You can do a
&ldquo;self send&rdquo; by calling a method (or getter or setter) without any explicit
receiver:</p>
<pre class="snippet">
class Unicorn {
name { "Francis" }
printName() {
System.print(name) //> Francis
}
}
</pre>
<p>Code like this gets tricky when there is also a variable outside of the class
with the same name. Consider:</p>
<pre class="snippet">
var name = "variable"
class Unicorn {
name { "Francis" }
printName() {
System.print(name) // ???
}
}
</pre>
<p>Should <code>printName()</code> print &ldquo;variable&rdquo; or &ldquo;Francis&rdquo;? A method body has a foot in
each of two worlds. It is surrounded by the lexical scope where it&rsquo;s defined in
the program, but it also has the object scope of the methods on <code>this</code>.</p>
<p>Which scope wins? Every language has to decide how to handle this and there
is a surprising plethora of approaches. Wren&rsquo;s approach to resolving a name
inside a method works like this:</p>
<ol>
<li>If there is a local variable inside the method with that name, that wins.</li>
<li>Else, if the name starts with a lowercase letter, treat it like a method on
<code>this</code>.</li>
<li>Otherwise, look for a variable with that name in the surrounding scope.</li>
</ol>
<p>So, in the above example, we hit case #2 and it prints &ldquo;Francis&rdquo;. Distinguishing
self sends from outer variables based on the <em>case</em> of the first letter in the
name probably seems weird but it works surprisingly well. Method names are
lowercase in Wren. Class names are capitalized.</p>
<p>Most of the time, when you&rsquo;re in a method and want to access a name from outside
of the class, it&rsquo;s usually the name of some other class. This rule makes that
work.</p>
<p>Here&rsquo;s an example that shows all three cases:</p>
<pre class="snippet">
var shadowed = "surrounding"
var lowercase = "surrounding"
var Capitalized = "surrounding"
class Scope {
shadowed { "object" }
lowercase { "object" }
Capitalized { "object" }
test() {
var shadowed = "local"
System.print(shadowed) //> local
System.print(lowercase) //> object
System.print(Capitalized) //> surrounding
}
}
</pre>
<p>It&rsquo;s a bit of a strange rule, but Ruby works more or less the same way.</p>
<h2>Constructors <a href="#constructors" name="constructors" class="header-anchor">#</a></h2>
<p>We&rsquo;ve seen how to define kinds of objects and how to declare methods on them.
Our unicorns can prance around, but we don&rsquo;t actually <em>have</em> any unicorns to do
it. To create <em>instances</em> of a class, we need a <em>constructor</em>. You define one
like so:</p>
<pre class="snippet">
class Unicorn {
construct new(name, color) {
System.print("My name is " + name + " and I am " + color + ".")
}
}
</pre>
<p>The <code>construct</code> keyword says we&rsquo;re defining a constructor, and <code>new</code> is its
name. In Wren, all constructors have names. The word &ldquo;new&rdquo; isn&rsquo;t special to
Wren, it&rsquo;s just a common constructor name.</p>
<p>To make a unicorn now, we call the constructor method on the class itself:</p>
<pre class="snippet">
var fred = Unicorn.new("Fred", "palomino")
</pre>
<p>Giving constructors names is handy because it means you can have more than one,
and each can clarify how it creates the instance:</p>
<pre class="snippet">
class Unicorn {
construct brown(name) {
System.print("My name is " + name + " and I am brown.")
}
}
var dave = Unicorn.brown("Dave")
</pre>
<p>Note that we have to declare a constructor because, unlike some other
languages, Wren doesn&rsquo;t give you a default one. This is useful because some
classes aren&rsquo;t designed to be constructed. If you have an abstract base class
that just contains methods to be inherited by other classes, it doesn&rsquo;t need
and won&rsquo;t have a constructor.</p>
<p>Like other methods, constructors can obviously have arguments, and can be
overloaded by <a href="#signature">arity</a>. A constructor <em>must</em> be a named method with
a (possibly empty) argument list. Operators, getters, and setters cannot be
constructors.</p>
<p>A constructor returns the instance of the class being created, even if you
don&rsquo;t explicitly use <code>return</code>. It is valid to use <code>return</code> inside of a
constructor, but it is an error to have an expression after the return.
That rule applies to <code>return this</code> as well, return handles that implicitly inside
a constructor, so just <code>return</code> is enough.</p>
<pre class="snippet">
return //> valid, returns 'this'
return variable //> invalid
return null //> invalid
return this //> also invalid
</pre>
<p>A constructor is actually a pair of methods. You get a method on the class:</p>
<pre class="snippet">
Unicorn.brown("Dave")
</pre>
<p>That creates the new instance, then it invokes the <em>initializer</em> on that
instance. This is where the constructor body you defined gets run.</p>
<p>This distinction is important because it means inside the body of the
constructor, you can access <code>this</code>, assign <a href="#fields">fields</a>, call superclass
constructors, etc.</p>
<h2>Fields <a href="#fields" name="fields" class="header-anchor">#</a></h2>
<p>All state stored in instances is stored in <em>fields</em>. Each field has a name
that starts with an underscore.</p>
<pre class="snippet">
class Rectangle {
area { _width * _height }
// Other stuff...
}
</pre>
<p>Here, <code>_width</code> and <code>_height</code> in the <code>area</code> <a href="classes.html#methods">getter</a> refer
to fields on the rectangle instance. You can think of them like <code>this.width</code>
and <code>this.height</code> in other languages.</p>
<p>When a field name appears, Wren looks for the nearest enclosing class and looks
up the field on the instance of that class. Field names cannot be used outside
of an instance method. They <em>can</em> be used inside a <a href="functions.html">function</a>
in a method. Wren will look outside any nested functions until it finds an
enclosing method.</p>
<p>Unlike <a href="variables.html">variables</a>, fields are implicitly declared by simply
assigning to them. If you access a field before it has been initialized, its
value is <code>null</code>.</p>
<h3>Encapsulation <a href="#encapsulation" name="encapsulation" class="header-anchor">#</a></h3>
<p>All fields are <em>private</em> in Wren&mdash;an object&rsquo;s fields can only be directly
accessed from within methods defined on the object&rsquo;s class. </p>
<p>In short, if you want to make a property of an object visible,
<strong>you need to define a getter to expose it</strong>:</p>
<pre class="snippet">
class Rectangle {
width { _width }
height { _height }
// ...
}
</pre>
<p>To allow outside code to modify the field,
<strong>you need to provide setters to provide access</strong>:</p>
<pre class="snippet">
class Rectangle {
width=(value) { _width = value }
height=(value) { _height = value }
}
</pre>
<p>This might be different from what you&rsquo;re used to, so here are two important facts:</p>
<ul>
<li>You can&rsquo;t access fields from a base class.</li>
<li>You can&rsquo;t access fields on another instance of your own class.</li>
</ul>
<p>Here is an example in code:</p>
<pre class="snippet">
class Shape {
construct new() {
_shape = "none"
}
}
class Rectangle is Shape {
construct new() {
//This will print null!
//_shape from the parent class is private,
//we are reading `_shape` from `this`,
//which has not been set, so returns null.
System.print("I am a %(_shape)")
//a local variable, all variables are private
_width = 10
var other = Rectangle.new()
//other._width is not accessible from here,
//even though we are also a rectangle. The field
//is private, and other._width is invalid syntax!
}
}
...
</pre>
<p>One thing we&rsquo;ve learned in the past forty years of software engineering is that
encapsulating state tends to make code easier to maintain, so Wren defaults to
keeping your object&rsquo;s state pretty tightly bundled up. Don&rsquo;t feel that you have
to or even should define getters or setters for most of your object&rsquo;s fields.</p>
<h2>Metaclasses and static members <a href="#metaclasses-and-static-members" name="metaclasses-and-static-members" class="header-anchor">#</a></h2>
<p><strong>TODO</strong></p>
<h3>Static fields <a href="#static-fields" name="static-fields" class="header-anchor">#</a></h3>
<p>A name that starts with <em>two</em> underscores is a <em>static</em> field. They work
similar to <a href="#fields">fields</a> except the data is stored on the class itself, and
not the instance. They can be used in <em>both</em> instance and static methods.</p>
<pre class="snippet">
class Foo {
construct new() {}
static setFromStatic(a) { __a = a }
setFromInstance(a) { __a = a }
static printFromStatic() {
System.print(__a)
}
printFromInstance() {
System.print(__a)
}
}
</pre>
<p>Just like instance fields, static fields are initially <code>null</code>:</p>
<pre class="snippet">
Foo.printFromStatic() //> null
</pre>
<p>They can be used from static methods:</p>
<pre class="snippet">
Foo.setFromStatic("first")
Foo.printFromStatic() //> first
</pre>
<p>And also instance methods. When you do so, there is still only one static field
shared among all instances of the class:</p>
<pre class="snippet">
var foo1 = Foo.new()
var foo2 = Foo.new()
foo1.setFromInstance("second")
foo2.printFromInstance() //> second
</pre>
<h2>Inheritance <a href="#inheritance" name="inheritance" class="header-anchor">#</a></h2>
<p>A class can inherit from a &ldquo;parent&rdquo; or <em>superclass</em>. When you invoke a method
on an object of some class, if it can&rsquo;t be found, it walks up the chain of
superclasses looking for it there.</p>
<p>By default, any new class inherits from Object, which is the superclass from
which all other classes ultimately descend. You can specify a different parent
class using <code>is</code> when you declare the class:</p>
<pre class="snippet">
class Pegasus is Unicorn {}
</pre>
<p>This declares a new class Pegasus that inherits from Unicorn.</p>
<p>Note that you should not create classes that inherit from the built-in types
(Bool, Num, String, Range, List). The built-in types expect their internal bit
representation to be very specific and get horribly confused when you invoke one
of the inherited built-in methods on the derived type.</p>
<p>The metaclass hierarchy does <em>not</em> parallel the regular class hierarchy. So, if
Pegasus inherits from Unicorn, Pegasus&rsquo;s metaclass does not inherit from
Unicorn&rsquo;s metaclass. In more prosaic terms, this means that static methods are
not inherited.</p>
<pre class="snippet">
class Unicorn {
// Unicorns cannot fly. :(
static canFly { false }
}
class Pegasus is Unicorn {}
Pegasus.canFly //! Static methods are not inherited.
</pre>
<p>This also means constructors are not inherited:</p>
<pre class="snippet">
class Unicorn {
construct new(name) {
System.print("My name is " + name + ".")
}
}
class Pegasus is Unicorn {}
Pegasus.new("Fred") //! Pegasus does not define new().
</pre>
<p>Each class gets to control how it may be constructed independently of its base
classes. However, constructor <em>initializers</em> are inherited since those are
instance methods on the new object.</p>
<p>This means you can do <code>super</code> calls inside a constructor:</p>
<pre class="snippet">
class Unicorn {
construct new(name) {
System.print("My name is " + name + ".")
}
}
class Pegasus is Unicorn {
construct new(name) {
super(name)
}
}
Pegasus.new("Fred") //> My name is Fred
</pre>
<h2>Super <a href="#super" name="super" class="header-anchor">#</a></h2>
<p><strong>TODO: Integrate better into page. Should explain this before mentioning
super above.</strong></p>
<p>Sometimes you want to invoke a method on yourself, but using methods defined in
one of your <a href="classes.html#inheritance">superclasses</a>. You typically do this in
an overridden method when you want to access the original method being
overridden.</p>
<p>To do that, you can use the special <code>super</code> keyword as the receiver in a method
call:</p>
<pre class="snippet">
class Base {
method() {
System.print("base method")
}
}
class Derived is Base {
method() {
super.method() //> base method
}
}
</pre>
<p>You can also use <code>super</code> without a method name inside a constructor to invoke a
base class constructor:</p>
<pre class="snippet">
class Base {
construct new(arg) {
System.print("base got " + arg)
}
}
class Derived is Base {
construct new() {
super("value") //> base got value
}
}
</pre>
<h2>Attributes <a href="#attributes" name="attributes" class="header-anchor">#</a></h2>
<p><small><strong>experimental stage</strong>: subject to minor changes</small></p>
<p>A class and methods within a class can be tagged with &lsquo;meta attributes&rsquo;.</p>
<p>Like this:</p>
<pre class="snippet">
#hidden = true
class Example {}
</pre>
<p>These attributes are metadata, they give you a way to annotate and store
any additional information about a class, which you can optionally access at runtime.
This information can also be used by external tools, to provide additional
hints and information from code to the tool.</p>
<p><small>
Since this feature has just been introduced, <strong>take note</strong>.</p>
<p><strong>Currently</strong> there are no attributes with a built-in meaning.
Attributes are user-defined metadata. This may not remain
true as some may become well defined through convention or potentially
through use by Wren itself.
</small></p>
<p>Attributes are placed before a class or method definition,
and use the <code>#</code> hash/pound symbol. </p>
<p>They can be </p>
<ul>
<li>a <code>#key</code> on it&rsquo;s own</li>
<li>a <code>#key = value</code></li>
<li>a <code>#group(with, multiple = true, keys = "value")</code></li>
</ul>
<p>An attribute <em>key</em> can only be a <code>Name</code>. This is the same type of name
as a method name, a class name or variable name, an identifier that matches
the Wren identifier rules. A name results in a String value at runtime.</p>
<p>An attribute <em>value</em> can be any of these literal values: <code>Name, String, Bool, Num</code>.
Values cannot contain expressions, just a value, there is no compile time
evaluation.</p>
<p>Groups can span multiple lines, methods have their own attributes, and duplicate
keys are valid.</p>
<pre class="snippet">
#key
#key = value
#group(
multiple,
lines = true,
lines = 0
)
class Example {
#test(skip = true, iterations = 32)
doStuff() {}
}
</pre>
<h3>Accessing attributes at runtime <a href="#accessing-attributes-at-runtime" name="accessing-attributes-at-runtime" class="header-anchor">#</a></h3>
<p>By default, attributes are compiled out and ignored.</p>
<p>For an attribute to be visible at runtime, mark it for runtime
access using an exclamation:</p>
<pre class="snippet">
#doc = "not runtime data"
#!runtimeAccess = true
#!maxIterations = 16
</pre>
<p>Attributes at runtime are stored on the class. You can access them via
<code>YourClass.attributes</code>. The <code>attributes</code> field on a class will
be null if a class has no attributes or if it&rsquo;s attributes aren&rsquo;t marked.</p>
<p>If the class contains class or method attributes, it will be an object with
two getters:</p>
<ul>
<li><code>YourClass.attributes.self</code> for the class attributes</li>
<li><code>YourClass.attributes.methods</code> for the method attributes</li>
</ul>
<p>Attributes are stored by group in a regular Wren Map.
Keys that are not grouped, use <code>null</code> as the group key.</p>
<p>Values are stored in a list, since duplicate keys are allowed, multiple
values need to be stored. They&rsquo;re stored in order of definition.</p>
<p>Method attributes are stored in a map by method signature, and each method
has it&rsquo;s own attributes that match the above structure. The method signature
is prefixed by <code>static</code> or <code>foreign static</code> as needed.</p>
<p>Let&rsquo;s see what that looks like:</p>
<pre class="snippet">
// Example.attributes.self =
// {
// null: { "key":[null] },
// group: { "key":[value, 32, false] }
// }
#!key
#ignored //compiled out
#!group(key=value, key=32, key=false)
class Example {
#!getter
getter {}
// { regular(_,_): { null: { regular:[null] } } }
#!regular
regular(arg0, arg1) {}
// { static other(): { null: { isStatic:[true] } } }
#!isStatic = true
static other() {}
// { foreign static example(): { null: { isForeignStatic:[32] } } }
#!isForeignStatic=32
foreign static example()
}
</pre>
<p><br><hr>
<a class="right" href="concurrency.html">Concurrency &rarr;</a>
<a href="functions.html">&larr; Functions</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,108 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Wren CLI &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>Wren CLI</h2>
<ul>
<li><a href="./">About</a></li>
<li><a target="_blank" href="https://github.com/wren-lang/wren-cli/releases">Downloads</a></li>
<li><a href="usage.html">Usage</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">CLI Modules</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="../">Back to Wren</a></div>
</tr>
<tr>
<td><h2>CLI</h2></td>
<td><h2>API</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">About</a></li>
<li><a target="_blank" href="https://github.com/wren-lang/wren-cli/releases">Downloads</a></li>
<li><a href="usage.html">Usage</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">CLI Modules</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Wren CLI</h2>
<hr />
<h2>What is it? <a href="#what-is-it" name="what-is-it" class="header-anchor">#</a></h2>
<p><strong>The Wren Command-Line Interface</strong> is a tool you can run which gives you a way to run Wren code, and
also includes modules for talking to the operating system&mdash;file IO,
networking, stuff like that. It depends on <a href="http://libuv.org/">libuv</a> for that
functionality.</p>
<p>Wren as a language is intentionally designed to be minimal. <br />
That includes the built in language features, the standard library and the VM itself.</p>
<p>In order to access files, networks and other IO, you&rsquo;d need to make a tool <em>using</em> the language VM.
That&rsquo;s what the CLI project is! It is not bundled as part of the wren project,
instead it is its own project as a standalone tool you can run.
It exposes its own standard library and modules that may be of interest
if looking for a general purpose single binary scriptable tool.</p>
<p>Wren CLI is a work in progress, and contributions are welcome to make it more useful over time.</p>
<h2>Why does it exist? <a href="#why-does-it-exist" name="why-does-it-exist" class="header-anchor">#</a></h2>
<ul>
<li>It&rsquo;s fun to make things.</li>
<li>It&rsquo;s always a good idea to test the language you&rsquo;re making!</li>
<li>Interest was expressed in a scriptable tool using the Wren language.</li>
<li>It&rsquo;s helpful for others to learn from, since it is a real world usage example showing several concepts.</li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,105 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>CLI Modules &ndash; Wren</title>
<script type="application/javascript" src="../../prism.js" data-manual></script>
<script type="application/javascript" src="../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../"><img src="../../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren CLI</a></li>
</ul>
<section>
<h2>Built In</h2>
<ul>
<li><a href="../../modules">Wren modules</a></li>
</ul>
</section>
<section>
<h2>CLI modules</h2>
<ul>
<li><a href="io">io</a></li>
<li><a href="os">os</a></li>
<li><a href="scheduler">scheduler</a></li>
<li><a href="timer">timer</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><h2>core</h2></td>
<td><h2>optional</h2></td>
<td><h2>cli</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="core">core</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="meta">meta</a></li>
<li><a href="random">random</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="io">io</a></li>
<li><a href="os">os</a></li>
<li><a href="scheduler">scheduler</a></li>
<li><a href="timer">timer</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>CLI Modules</h1>
<p>The Wren CLI executable extends the built in language modules with its own,
which offer access to IO and other facilities for scripting.</p>
<p>The CLI modules are deeply tied to <a href="http://libuv.org">libuv</a>, each other, and other internals
of the command-line app, so can&rsquo;t easily be separated out and pulled into host
applications that want to embed Wren. Scripts written for the CLI then,
are specific to the CLI unless another host implements the same API.</p>
<ul>
<li><a href="io">io</a></li>
<li><a href="os">os</a></li>
<li><a href="scheduler">scheduler</a></li>
<li><a href="timer">timer</a></li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,96 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Directory Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">io module</a></li>
</ul>
<section>
<h2>io classes</h2>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">io module</a></td>
</tr>
<tr>
<td colspan="2"><h2>io classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Directory Class</h1>
<p>A directory on the file system.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3>Directory.<strong>exists</strong>(path) <a href="#directory.exists(path)" name="directory.exists(path)" class="header-anchor">#</a></h3>
<p>Whether a directory exists at <code>path</code>. This returns <code>false</code> for files or other
special file system entities.</p>
<h3>Directory.<strong>list</strong>(path) <a href="#directory.list(path)" name="directory.list(path)" class="header-anchor">#</a></h3>
<p>Lists the contents of the directory at <code>path</code>. Returns a sorted list of path
strings for all of the contents of the directory.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,115 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>FileFlags Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">io module</a></li>
</ul>
<section>
<h2>io classes</h2>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">io module</a></td>
</tr>
<tr>
<td colspan="2"><h2>io classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>FileFlags Class</h1>
<p>Contains constants for the various file flags used to open or create a file.
These correspond directly to the flags that can be passed to the POSIX
<a href="http://linux.die.net/man/2/open"><code>open()</code></a> syscall.</p>
<p>They are integers and can be bitwise or&rsquo;ed together to produce a composite
flag.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3>FileFlags.<strong>readOnly</strong> <a href="#fileflags.readonly" name="fileflags.readonly" class="header-anchor">#</a></h3>
<p>The file can be read from but not written. Equivalent to <code>O_RDONLY</code>.</p>
<h3>FileFlags.<strong>writeOnly</strong> <a href="#fileflags.writeonly" name="fileflags.writeonly" class="header-anchor">#</a></h3>
<p>The file can be written but not read from. Equivalent to <code>O_WRONLY</code>.</p>
<h3>FileFlags.<strong>readWrite</strong> <a href="#fileflags.readwrite" name="fileflags.readwrite" class="header-anchor">#</a></h3>
<p>The file can be both read from and written to. Equivalent to <code>O_RDWR</code>.</p>
<h3>FileFlags.<strong>sync</strong> <a href="#fileflags.sync" name="fileflags.sync" class="header-anchor">#</a></h3>
<p>Writes will block until the data has been physically written to the underling
hardware. This does <em>not</em> affect whether or the file API is synchronous. File
operations are always asynchronous in Wren and may allow other scheduled fibers
to run.</p>
<p>This is a lower-level flag that ensures that when a write completes, it has
been flushed all the way to disc.</p>
<h3>FileFlags.<strong>create</strong> <a href="#fileflags.create" name="fileflags.create" class="header-anchor">#</a></h3>
<p>Creates a new file if a file at the given path does not already exist.</p>
<h3>FileFlags.<strong>truncate</strong> <a href="#fileflags.truncate" name="fileflags.truncate" class="header-anchor">#</a></h3>
<p>If the file already exists and can be written to, its previous contents are
discarded.</p>
<h3>FileFlags.<strong>exclusive</strong> <a href="#fileflags.exclusive" name="fileflags.exclusive" class="header-anchor">#</a></h3>
<p>Ensures that a new file must be created. If a file already exists at the given
path, this flag will cause the operation to fail.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,185 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>File Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">io module</a></li>
</ul>
<section>
<h2>io classes</h2>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">io module</a></td>
</tr>
<tr>
<td colspan="2"><h2>io classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>File Class</h1>
<p>Lets you work with files on the file system. An instance of this class
represents an open file with a file descriptor.</p>
<p>When you are done with a file object, it&rsquo;s a good idea to explicitly close it.
If you don&rsquo;t, the GC will close it when the file is no longer used and gets
finalized, but that may take a while. In the meantime, leaving it open wastes
a file descriptor.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3>File.<strong>create</strong>(path, fn) <a href="#file.create(path,-fn)" name="file.create(path,-fn)" class="header-anchor">#</a></h3>
<p>Opens the file at <code>path</code> for writing and passes it to <code>fn</code>. If there is already
a file at that path, it is truncated. After the function returns, the file is
automatically closed.</p>
<pre class="snippet">
File.create("numbers.txt") {|file|
file.writeBytes("one two three")
}
</pre>
<h3>File.<strong>delete</strong>(path) <a href="#file.delete(path)" name="file.delete(path)" class="header-anchor">#</a></h3>
<p>Deletes the file at <code>path</code>.</p>
<h3>File.<strong>exists</strong>(path) <a href="#file.exists(path)" name="file.exists(path)" class="header-anchor">#</a></h3>
<p>Whether a regular file exists at <code>path</code>. This returns <code>false</code> for directories
or other special file system entities.</p>
<h3>File.<strong>open</strong>(path, fn) <a href="#file.open(path,-fn)" name="file.open(path,-fn)" class="header-anchor">#</a></h3>
<p>Opens the file at <code>path</code> for reading and passes it to <code>fn</code>. After the function
returns, the file is automatically closed.</p>
<pre class="snippet">
File.open("words.txt") {|file|
file.readBytes(5)
}
</pre>
<h3>File.<strong>read</strong>(path) <a href="#file.read(path)" name="file.read(path)" class="header-anchor">#</a></h3>
<p>Reads the entire contents of the file at <code>path</code> and returns it as a string.</p>
<pre class="snippet">
File.read("words.txt")
</pre>
<p>No encoding or decoding is done. If the file is UTF-8, then the resulting
string will be a UTF-8 string. Otherwise, it will be a string of bytes in
whatever encoding the file uses.</p>
<h3>File.<strong>realPath</strong>(path) <a href="#file.realpath(path)" name="file.realpath(path)" class="header-anchor">#</a></h3>
<p>Resolves <code>path</code>, traversing symlinks and removining any unneeded <code>./</code> and <code>../</code>
components. Returns the canonical absolute path to the file.</p>
<pre class="snippet">
var path = "/some/./symlink/a/../b/file.txt"
System.print(File.realPath(path)) //> /real/path/a/file.txt
</pre>
<h3>File.<strong>size</strong>(path) <a href="#file.size(path)" name="file.size(path)" class="header-anchor">#</a></h3>
<p>Returns the size in bytes of the contents of the file at <code>path</code>.</p>
<h2>Constructors <a href="#constructors" name="constructors" class="header-anchor">#</a></h2>
<h3>File.<strong>create</strong>(path) <a href="#file.create(path)" name="file.create(path)" class="header-anchor">#</a></h3>
<p>Opens the file at <code>path</code> for writing. If there is already a file at that path,
it is truncated.</p>
<pre class="snippet">
var file = File.create("colors.txt")
file.writeBytes("chartreuse lime teal")
file.close()
</pre>
<h3>File.<strong>open</strong>(path) <a href="#file.open(path)" name="file.open(path)" class="header-anchor">#</a></h3>
<p>Opens the file at <code>path</code> for reading. You are responsible for closing it when
done with it.</p>
<h2>Methods <a href="#methods" name="methods" class="header-anchor">#</a></h2>
<h3><strong>descriptor</strong> <a href="#descriptor" name="descriptor" class="header-anchor">#</a></h3>
<p>The numeric file descriptor used to access the file.</p>
<h3><strong>isOpen</strong> <a href="#isopen" name="isopen" class="header-anchor">#</a></h3>
<p>Whether the file is still open or has been closed.</p>
<h3><strong>size</strong> <a href="#size" name="size" class="header-anchor">#</a></h3>
<p>The size of the contents of the file in bytes.</p>
<h3><strong>close</strong>() <a href="#close()" name="close()" class="header-anchor">#</a></h3>
<p>Closes the file. After calling this, you can&rsquo;t read or write from it.</p>
<h3><strong>readBytes</strong>(count) <a href="#readbytes(count)" name="readbytes(count)" class="header-anchor">#</a></h3>
<p>Reads up to <code>count</code> bytes starting from the beginning of the file.</p>
<pre class="snippet">
// Assume this file contains "I am a file!".
File.open("example.txt") {|file|
System.print(file.readBytes(6)) //> I am a
}
</pre>
<h3><strong>readBytes</strong>(count, offset) <a href="#readbytes(count,-offset)" name="readbytes(count,-offset)" class="header-anchor">#</a></h3>
<p>Reads up to <code>count</code> bytes starting at <code>offset</code> bytes from the beginning of
the file.</p>
<pre class="snippet">
// Assume this file contains "I am a file!".
File.open("example.txt") {|file|
System.print(file.readBytes(6, 2)) //> am a f
}
</pre>
<h3><strong>writeBytes</strong>(bytes) <a href="#writebytes(bytes)" name="writebytes(bytes)" class="header-anchor">#</a></h3>
<p>Writes the raw bytes of the string <code>bytes</code> to the end of the file.</p>
<h3><strong>writeBytes</strong>(bytes, offset) <a href="#writebytes(bytes,-offset)" name="writebytes(bytes,-offset)" class="header-anchor">#</a></h3>
<p>Writes the raw bytes of the string <code>bytes</code> to the to the file, starting at
<code>offset</code>. Any overlapping bytes already in the file at the offset are
overwritten.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,96 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Module "io" &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">io module</a></li>
</ul>
<section>
<h2>io classes</h2>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">io module</a></td>
</tr>
<tr>
<td colspan="2"><h2>io classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Module "io"</h1>
<p>Provides access to operating system streams and the file system.</p>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,119 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Stat Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">io module</a></li>
</ul>
<section>
<h2>io classes</h2>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">io module</a></td>
</tr>
<tr>
<td colspan="2"><h2>io classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Stat Class</h1>
<p>A data structure describing the low-level details of a file system entry.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3>Stat.<strong>path</strong>(path) <a href="#stat.path(path)" name="stat.path(path)" class="header-anchor">#</a></h3>
<p>&ldquo;Stats&rdquo; the file or directory at <code>path</code>.</p>
<h2>Methods <a href="#methods" name="methods" class="header-anchor">#</a></h2>
<h3><strong>blockCount</strong> <a href="#blockcount" name="blockcount" class="header-anchor">#</a></h3>
<p>The number of system blocks allocated on disk for the file.</p>
<h3><strong>blockSize</strong> <a href="#blocksize" name="blocksize" class="header-anchor">#</a></h3>
<p>The preferred block size in bytes for interacting with the file. It may vary
from file to file.</p>
<h3><strong>device</strong> <a href="#device" name="device" class="header-anchor">#</a></h3>
<p>The ID of the device containing the entry.</p>
<h3><strong>group</strong> <a href="#group" name="group" class="header-anchor">#</a></h3>
<p>Numeric group ID of the file&rsquo;s owner.</p>
<h3><strong>inode</strong> <a href="#inode" name="inode" class="header-anchor">#</a></h3>
<p>The <a href="https://en.wikipedia.org/wiki/Inode">inode</a> number of the entry.</p>
<h3><strong>isDirectory</strong> <a href="#isdirectory" name="isdirectory" class="header-anchor">#</a></h3>
<p>Whether the file system entity is a directory.</p>
<h3><strong>isFile</strong> <a href="#isfile" name="isfile" class="header-anchor">#</a></h3>
<p>Whether the file system entity is a regular file, as opposed to a directory or
other special entity.</p>
<h3><strong>linkCount</strong> <a href="#linkcount" name="linkcount" class="header-anchor">#</a></h3>
<p>The number of hard links to the entry.</p>
<h3><strong>mode</strong> <a href="#mode" name="mode" class="header-anchor">#</a></h3>
<p>A bit field describing the entry&rsquo;s type and protection flags.</p>
<h3><strong>size</strong> <a href="#size" name="size" class="header-anchor">#</a></h3>
<p>The size of the entry in bytes.</p>
<h3><strong>specialDevice</strong> <a href="#specialdevice" name="specialdevice" class="header-anchor">#</a></h3>
<p>The device ID for the entry, if it&rsquo;s a special file.</p>
<h3><strong>user</strong> <a href="#user" name="user" class="header-anchor">#</a></h3>
<p>Numeric user ID of the file&rsquo;s owner.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,115 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Stdin Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">io module</a></li>
</ul>
<section>
<h2>io classes</h2>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">io module</a></td>
</tr>
<tr>
<td colspan="2"><h2>io classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Stdin Class</h1>
<p>The standard input stream.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3><strong>isRaw</strong> <a href="#israw" name="israw" class="header-anchor">#</a></h3>
<p>Returns <code>true</code> if stdin is in raw mode. When in raw mode, input is not echoed
or buffered, and all characters, even non-printing and control characters go
into stdin.</p>
<p>Defaults to <code>false</code>.</p>
<h3><strong>isRaw</strong>=(value) <a href="#israw=(value)" name="israw=(value)" class="header-anchor">#</a></h3>
<p>Sets raw mode on or off.</p>
<h3><strong>isTerminal</strong> <a href="#isterminal" name="isterminal" class="header-anchor">#</a></h3>
<p>Returns <code>true</code> if Stdin is connected to a &ldquo;TTY&rdquo;. This is true when the user is
running Wren in an interactive terminal, and false if it its input is coming
from a pipe.</p>
<h3><strong>readByte</strong>() <a href="#readbyte()" name="readbyte()" class="header-anchor">#</a></h3>
<p>Reads one byte of input from stdin. Blocks the current fiber until a byte has
been received.</p>
<p>Returns the byte value as a number or <code>null</code> if stdin is closed.</p>
<p>Note that output is not automatically flushed when calling this. If you want to
display a prompt before reading input, you&rsquo;ll want to call <code>Stdout.flush()</code>
after printing the prompt.</p>
<h3><strong>readLine</strong>() <a href="#readline()" name="readline()" class="header-anchor">#</a></h3>
<p>Reads one line of input from stdin. Blocks the current fiber until a full line
of input has been received.</p>
<p>Returns the string of input or <code>null</code> if stdin is closed.</p>
<p>Note that output is not automatically flushed when calling this. If you want to
display a prompt before reading input, you&rsquo;ll want to call <code>Stdout.flush()</code>
after printing the prompt.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,94 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Stdout Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">io module</a></li>
</ul>
<section>
<h2>io classes</h2>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">io module</a></td>
</tr>
<tr>
<td colspan="2"><h2>io classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="directory.html">Directory</a></li>
<li><a href="file.html">File</a></li>
<li><a href="file-flags.html">FileFlags</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="stat.html">Stat</a></li>
<li><a href="stdin.html">Stdin</a></li>
<li><a href="stdout.html">Stdout</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Stdout Class</h1>
<p>The standard output stream.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3><strong>flush()</strong> <a href="#flush()" name="flush()" class="header-anchor">#</a></h3>
<p>Flushes all buffered data to the stream. Ensures any data written to stdout
that is in the buffer gets written to the file or terminal that stdout is
connected to.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,86 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Module "os" &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">os module</a></li>
</ul>
<section>
<h2>os classes</h2>
<ul>
<li><a href="platform.html">Platform</a></li>
<li><a href="process.html">Process</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">os module</a></td>
</tr>
<tr>
<td colspan="2"><h2>os classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="platform.html">Platform</a></li>
<li><a href="process.html">Process</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Module "os"</h1>
<p>The os module exposes classes for accessing capabilities provided by the
underlying operating system.</p>
<ul>
<li><a href="platform.html">Platform</a></li>
<li><a href="process.html">Process</a></li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,101 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Platform Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">os module</a></li>
</ul>
<section>
<h2>os classes</h2>
<ul>
<li><a href="platform.html">Platform</a></li>
<li><a href="process.html">Process</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">os module</a></td>
</tr>
<tr>
<td colspan="2"><h2>os classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="platform.html">Platform</a></li>
<li><a href="process.html">Process</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Platform Class</h1>
<p>The Platform class exposes basic information about the operating system Wren is
running on top of.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3><strong>name</strong> <a href="#name" name="name" class="header-anchor">#</a></h3>
<p>The name of the platform. This roughly describes the operating system, and is
usually one of:</p>
<ul>
<li>&ldquo;iOS&rdquo;</li>
<li>&ldquo;Linux&rdquo;</li>
<li>&ldquo;OS X&rdquo;</li>
<li>&ldquo;POSIX&rdquo;</li>
<li>&ldquo;Unix&rdquo;</li>
<li>&ldquo;Windows&rdquo;</li>
</ul>
<p>If Wren was compiled for an unknown operating system, returns &ldquo;Unknown&rdquo;.</p>
<h3><strong>isPosix</strong> <a href="#isposix" name="isposix" class="header-anchor">#</a></h3>
<p>Returns <code>true</code> if the host operating system is known to support the POSIX
standard. This is true for Linux and other Unices, as well as the various Apple
operating systems.</p>
<h3><strong>isWindows</strong> <a href="#iswindows" name="iswindows" class="header-anchor">#</a></h3>
<p>Returns <code>true</code> if the host operating system is some flavor of Windows.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,106 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Process Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">os module</a></li>
</ul>
<section>
<h2>os classes</h2>
<ul>
<li><a href="platform.html">Platform</a></li>
<li><a href="process.html">Process</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">os module</a></td>
</tr>
<tr>
<td colspan="2"><h2>os classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="platform.html">Platform</a></li>
<li><a href="process.html">Process</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Process Class</h1>
<p>The Process class lets you work with operating system processes, including the
currently running one.</p>
<h2>Static Methods <a href="#static-methods" name="static-methods" class="header-anchor">#</a></h2>
<h3><strong>allArguments</strong> <a href="#allarguments" name="allarguments" class="header-anchor">#</a></h3>
<p>The list of command-line arguments that were passed when the Wren process was
spawned. This includes the Wren executable itself, the path to the file being
run (if any), and any other options passed to Wren itself.</p>
<p>If you run:</p>
<pre><code>$ wren file.wren arg
</code></pre>
<p>This returns:</p>
<pre class="snippet">
System.print(Process.allArguments) //> ["wren", "file.wren", "arg"]
</pre>
<h3><strong>arguments</strong> <a href="#arguments" name="arguments" class="header-anchor">#</a></h3>
<p>The list of command-line arguments that were passed to your program when the
Wren process was spawned. This does not include arguments handled by Wren
itself.</p>
<p>If you run:</p>
<pre><code>$ wren file.wren arg
</code></pre>
<p>This returns:</p>
<pre class="snippet">
System.print(Process.arguments) //> ["arg"]
</pre>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,83 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Module "scheduler" &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">scheduler module</a></li>
</ul>
<section>
<h2>scheduler classes</h2>
<ul>
<li><a href="scheduler.html">Scheduler</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">scheduler module</a></td>
</tr>
<tr>
<td colspan="2"><h2>scheduler classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="scheduler.html">Scheduler</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Module "scheduler"</h1>
<p>This module provides a vehicle to allow other operations to be performed asynchronously whilst waiting for the main operation to be completed.</p>
<p>It contains a single class:</p>
<ul>
<li><a href="scheduler.html">Scheduler</a></li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,98 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Scheduler Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">scheduler module</a></li>
</ul>
<section>
<h2>scheduler classes</h2>
<ul>
<li><a href="scheduler.html">Scheduler</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">scheduler module</a></td>
</tr>
<tr>
<td colspan="2"><h2>scheduler classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="scheduler.html">Scheduler</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Scheduler Class</h1>
<p>The Scheduler class maintains a list of fibers, to be started one after the other, when a signal to do so is received. The signal (a private method call) is typically transmitted by <em>long running</em> methods in the File or Timer classes which suspend the current fiber so that Wren can carry out other tasks in the meantime.</p>
<h2>Static Method <a href="#static-method" name="static-method" class="header-anchor">#</a></h2>
<h3>Scheduler.<strong>add</strong>(callable) <a href="#scheduler.add(callable)" name="scheduler.add(callable)" class="header-anchor">#</a></h3>
<p>Adds a new fiber to the scheduler&rsquo;s fibers list. This fiber calls <code>callable</code> and then transfers to the next fiber in the list, if there is one.</p>
<p><code>callable</code> is a function or other object which has a call() method.</p>
<pre class="snippet">
var a = 3
Scheduler.add {
a = a * a
}
Scheduler.add {
a = a + 1
}
System.print(a) // still 3
Timer.sleep(3000) // wait 3 seconds
System.print(a) // now 3 * 3 + 1 = 10
</pre>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,83 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Module "timer" &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">timer module</a></li>
</ul>
<section>
<h2>timer classes</h2>
<ul>
<li><a href="timer.html">Timer</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">timer module</a></td>
</tr>
<tr>
<td colspan="2"><h2>timer classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="timer.html">Timer</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Module "timer"</h1>
<p>This module provides a mechanism to suspend the current fiber for a given period of time either as a simple delay or to allow other operations to be performed asynchronously in the meantime.</p>
<p>It contains a single class:</p>
<ul>
<li><a href="timer.html">Timer</a></li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,83 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Timer Class &ndash; Wren</title>
<script type="application/javascript" src="../../../prism.js" data-manual></script>
<script type="application/javascript" src="../../../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../../../prism.css" />
<link rel="stylesheet" type="text/css" href="../../../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="module">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../../../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../../../"><img src="../../../wren.svg" class="logo"></a>
<ul>
<li><a href="../../">Back to Wren CLI</a></li>
<li><a href="../">Back to CLI Modules</a></li>
<li><a href="./">timer module</a></li>
</ul>
<section>
<h2>timer classes</h2>
<ul>
<li><a href="timer.html">Timer</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="../">Back to CLI Modules</a></td>
<td><a href="./">timer module</a></td>
</tr>
<tr>
<td colspan="2"><h2>timer classes</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="timer.html">Timer</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Timer Class</h1>
<h2>Static Method <a href="#static-method" name="static-method" class="header-anchor">#</a></h2>
<h3>Timer.<strong>sleep</strong>(milliseconds) <a href="#timer.sleep(milliseconds)" name="timer.sleep(milliseconds)" class="header-anchor">#</a></h3>
<p>Suspends the current fiber for the given number of milliseconds. It is a runtime error if this is not a non-negative number.</p>
<p>This method is often used in conjunction with the Scheduler class which runs any scheduled tasks in separate fibers whilst the current fiber is sleeping.</p>
<p>Note that this method also suspends the System.clock method which will not give the correct running time for a program as a result.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,131 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Wren CLI Usage &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>Wren CLI</h2>
<ul>
<li><a href="./">About</a></li>
<li><a target="_blank" href="https://github.com/wren-lang/wren-cli/releases">Downloads</a></li>
<li><a href="usage.html">Usage</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">CLI Modules</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="../">Back to Wren</a></div>
</tr>
<tr>
<td><h2>CLI</h2></td>
<td><h2>API</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">About</a></li>
<li><a target="_blank" href="https://github.com/wren-lang/wren-cli/releases">Downloads</a></li>
<li><a href="usage.html">Usage</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">CLI Modules</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Wren CLI Usage</h2>
<hr />
<p>You can <a href="https://github.com/wren-lang/wren-cli/releases">download a build for your OS from the releases page</a>.</p>
<h3>Interactive mode <a href="#interactive-mode" name="interactive-mode" class="header-anchor">#</a></h3>
<p>If you just run <code>wren_cli</code> without any arguments, it starts the interpreter in
interactive mode, where you can type in a line of code, and it immediately executes
it. You can exit the interpreter using good old Ctrl-C or Ctrl-D.</p>
<p>Here&rsquo;s something to try:</p>
<pre class="snippet">
System.print("Hello, world!")
</pre>
<p>Or a little more exciting:</p>
<pre class="snippet">
for (i in 1..10) System.print("Counting up %(i)")
</pre>
<h3>Running scripts <a href="#running-scripts" name="running-scripts" class="header-anchor">#</a></h3>
<p>The standalone interpreter can also load scripts from files and run them. Just
pass the name of the script to <code>wren_cli</code>. Create a file named &ldquo;my_script.wren&rdquo; in
your favorite text editor and paste this into it:</p>
<pre class="snippet">
for (yPixel in 0...24) {
var y = yPixel / 12 - 1
for (xPixel in 0...80) {
var x = xPixel / 30 - 2
var x0 = x
var y0 = y
var iter = 0
while (iter < 11 && x0 * x0 + y0 * y0 <= 4) {
var x1 = (x0 * x0) - (y0 * y0) + x
var y1 = 2 * x0 * y0 + y
x0 = x1
y0 = y1
iter = iter + 1
}
System.write(" .-:;+=xX$& "[iter])
}
System.print("")
}
</pre>
<p>Now run:</p>
<pre><code>$ ./wren_cli my_script.wren
</code></pre>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,51 +0,0 @@
function withLineNumbers(highlight, options = {}) {
const opts = Object.assign({ class: "codejar-linenumbers", wrapClass: "codejar-wrap", width: "35px" }, options);
let lineNumbers;
return function (editor) {
highlight(editor);
if (!lineNumbers) {
lineNumbers = init(editor, opts);
}
const code = editor.textContent || "";
const linesCount = code.replace(/\n+$/, "\n").split("\n").length + 1;
let text = "";
for (let i = 1; i < linesCount; i++) {
text += `${i}\n`;
}
lineNumbers.innerText = text;
};
}
function init(editor, opts) {
const css = getComputedStyle(editor);
const wrap = document.createElement("div");
wrap.className = opts.wrapClass;
wrap.style.position = "relative";
const lineNumbers = document.createElement("div");
lineNumbers.className = opts.class;
wrap.appendChild(lineNumbers);
// Add own styles
lineNumbers.style.position = "absolute";
lineNumbers.style.top = "0px";
lineNumbers.style.left = "0px";
lineNumbers.style.bottom = "0px";
lineNumbers.style.width = opts.width;
lineNumbers.style.overflow = "hidden";
lineNumbers.style.backgroundColor = "rgba(255, 255, 255, 0.05)";
lineNumbers.style.color = "#fff";
lineNumbers.style.setProperty("mix-blend-mode", "difference");
// Copy editor styles
lineNumbers.style.fontFamily = css.fontFamily;
lineNumbers.style.fontSize = css.fontSize;
lineNumbers.style.lineHeight = css.lineHeight;
lineNumbers.style.paddingTop = css.paddingTop;
lineNumbers.style.paddingLeft = css.paddingLeft;
lineNumbers.style.borderTopLeftRadius = css.borderTopLeftRadius;
lineNumbers.style.borderBottomLeftRadius = css.borderBottomLeftRadius;
// Tweak editor styles
editor.style.paddingLeft = `calc(${opts.width} + ${lineNumbers.style.paddingLeft})`;
editor.style.whiteSpace = "pre";
// Swap editor with a wrap
editor.parentNode.insertBefore(wrap, editor);
wrap.appendChild(editor);
return lineNumbers;
}

View File

@ -1,401 +0,0 @@
function CodeJar(editor, highlight, opt = {}) {
const options = Object.assign({ tab: "\t" }, opt);
let listeners = [];
let history = [];
let at = -1;
let focus = false;
let callback;
let prev; // code content prior keydown event
let isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
editor.setAttribute("contentEditable", isFirefox ? "true" : "plaintext-only");
editor.setAttribute("spellcheck", "false");
editor.style.outline = "none";
editor.style.overflowWrap = "break-word";
editor.style.overflowY = "auto";
editor.style.resize = "vertical";
editor.style.whiteSpace = "pre-wrap";
highlight(editor);
const debounceHighlight = debounce(() => {
const pos = save();
highlight(editor);
restore(pos);
}, 30);
let recording = false;
const shouldRecord = (event) => {
return !isUndo(event) && !isRedo(event)
&& event.key !== "Meta"
&& event.key !== "Control"
&& event.key !== "Alt"
&& !event.key.startsWith("Arrow");
};
const debounceRecordHistory = debounce((event) => {
if (shouldRecord(event)) {
recordHistory();
recording = false;
}
}, 300);
const on = (type, fn) => {
listeners.push([type, fn]);
editor.addEventListener(type, fn);
};
on("keydown", event => {
if (event.defaultPrevented)
return;
prev = toString();
handleNewLine(event);
handleTabCharacters(event);
handleJumpToBeginningOfLine(event);
handleSelfClosingCharacters(event);
handleUndoRedo(event);
if (shouldRecord(event) && !recording) {
recordHistory();
recording = true;
}
});
on("keyup", event => {
if (event.defaultPrevented)
return;
if (event.isComposing)
return;
if (prev !== toString())
debounceHighlight();
debounceRecordHistory(event);
if (callback)
callback(toString());
});
on("focus", _event => {
focus = true;
});
on("blur", _event => {
focus = false;
});
on("paste", event => {
recordHistory();
handlePaste(event);
recordHistory();
if (callback)
callback(toString());
});
function save() {
const s = window.getSelection();
const pos = { start: 0, end: 0, dir: undefined };
visit(editor, el => {
if (el === s.anchorNode && el === s.focusNode) {
pos.start += s.anchorOffset;
pos.end += s.focusOffset;
pos.dir = s.anchorOffset <= s.focusOffset ? "->" : "<-";
return "stop";
}
if (el === s.anchorNode) {
pos.start += s.anchorOffset;
if (!pos.dir) {
pos.dir = "->";
}
else {
return "stop";
}
}
else if (el === s.focusNode) {
pos.end += s.focusOffset;
if (!pos.dir) {
pos.dir = "<-";
}
else {
return "stop";
}
}
if (el.nodeType === Node.TEXT_NODE) {
if (pos.dir != "->")
pos.start += el.nodeValue.length;
if (pos.dir != "<-")
pos.end += el.nodeValue.length;
}
});
return pos;
}
function restore(pos) {
const s = window.getSelection();
let startNode, startOffset = 0;
let endNode, endOffset = 0;
if (!pos.dir)
pos.dir = "->";
if (pos.start < 0)
pos.start = 0;
if (pos.end < 0)
pos.end = 0;
// Flip start and end if the direction reversed
if (pos.dir == "<-") {
const { start, end } = pos;
pos.start = end;
pos.end = start;
}
let current = 0;
visit(editor, el => {
if (el.nodeType !== Node.TEXT_NODE)
return;
const len = (el.nodeValue || "").length;
if (current + len >= pos.start) {
if (!startNode) {
startNode = el;
startOffset = pos.start - current;
}
if (current + len >= pos.end) {
endNode = el;
endOffset = pos.end - current;
return "stop";
}
}
current += len;
});
// If everything deleted place cursor at editor
if (!startNode)
startNode = editor;
if (!endNode)
endNode = editor;
// Flip back the selection
if (pos.dir == "<-") {
[startNode, startOffset, endNode, endOffset] = [endNode, endOffset, startNode, startOffset];
}
s.setBaseAndExtent(startNode, startOffset, endNode, endOffset);
}
function beforeCursor() {
const s = window.getSelection();
const r0 = s.getRangeAt(0);
const r = document.createRange();
r.selectNodeContents(editor);
r.setEnd(r0.startContainer, r0.startOffset);
return r.toString();
}
function afterCursor() {
const s = window.getSelection();
const r0 = s.getRangeAt(0);
const r = document.createRange();
r.selectNodeContents(editor);
r.setStart(r0.endContainer, r0.endOffset);
return r.toString();
}
function handleNewLine(event) {
if (event.key === "Enter") {
const before = beforeCursor();
const after = afterCursor();
let [padding] = findPadding(before);
let newLinePadding = padding;
// If last symbol is "{" ident new line
if (before[before.length - 1] === "{") {
newLinePadding += options.tab;
}
if (isFirefox) {
preventDefault(event);
insert("\n" + newLinePadding);
}
else {
// Normal browsers
if (newLinePadding.length > 0) {
preventDefault(event);
insert("\n" + newLinePadding);
}
}
// Place adjacent "}" on next line
if (newLinePadding !== padding && after[0] === "}") {
const pos = save();
insert("\n" + padding);
restore(pos);
}
}
}
function handleSelfClosingCharacters(event) {
const open = `([{'"`;
const close = `)]}'"`;
const codeAfter = afterCursor();
if (close.includes(event.key) && codeAfter.substr(0, 1) === event.key) {
const pos = save();
preventDefault(event);
pos.start = ++pos.end;
restore(pos);
}
else if (open.includes(event.key)) {
const pos = save();
preventDefault(event);
const text = event.key + close[open.indexOf(event.key)];
insert(text);
pos.start = ++pos.end;
restore(pos);
}
}
function handleTabCharacters(event) {
if (event.key === "Tab") {
preventDefault(event);
if (event.shiftKey) {
const before = beforeCursor();
let [padding, start,] = findPadding(before);
if (padding.length > 0) {
const pos = save();
// Remove full length tab or just remaining padding
const len = Math.min(options.tab.length, padding.length);
restore({ start, end: start + len });
document.execCommand("delete");
pos.start -= len;
pos.end -= len;
restore(pos);
}
}
else {
insert(options.tab);
}
}
}
function handleJumpToBeginningOfLine(event) {
if (event.key === "ArrowLeft" && event.metaKey) {
preventDefault(event);
const before = beforeCursor();
let [padding, start, end] = findPadding(before);
if (before.endsWith(padding)) {
if (event.shiftKey) {
const pos = save();
restore({ start, end: pos.end }); // Select from line start.
}
else {
restore({ start, end: start }); // Jump to line start.
}
}
else {
if (event.shiftKey) {
const pos = save();
restore({ start: end, end: pos.end }); // Select from beginning of text.
}
else {
restore({ start: end, end }); // Jump to beginning of text.
}
}
}
}
function handleUndoRedo(event) {
if (isUndo(event)) {
preventDefault(event);
at--;
const record = history[at];
if (record) {
editor.innerHTML = record.html;
restore(record.pos);
}
if (at < 0)
at = 0;
}
if (isRedo(event)) {
preventDefault(event);
at++;
const record = history[at];
if (record) {
editor.innerHTML = record.html;
restore(record.pos);
}
if (at >= history.length)
at--;
}
}
function recordHistory() {
if (!focus)
return;
const html = editor.innerHTML;
const pos = save();
const lastRecord = history[at];
if (lastRecord) {
if (lastRecord.html === html
&& lastRecord.pos.start === pos.start
&& lastRecord.pos.end === pos.end)
return;
}
at++;
history[at] = { html, pos };
history.splice(at + 1);
const maxHistory = 300;
if (at > maxHistory) {
at = maxHistory;
history.splice(0, 1);
}
}
function handlePaste(event) {
preventDefault(event);
const text = (event.originalEvent || event).clipboardData.getData("text/plain");
const pos = save();
insert(text);
highlight(editor);
restore({ start: pos.end + text.length, end: pos.end + text.length });
}
function visit(editor, visitor) {
const queue = [];
if (editor.firstChild)
queue.push(editor.firstChild);
let el = queue.pop();
while (el) {
if (visitor(el) === "stop")
break;
if (el.nextSibling)
queue.push(el.nextSibling);
if (el.firstChild)
queue.push(el.firstChild);
el = queue.pop();
}
}
function isCtrl(event) {
return event.metaKey || event.ctrlKey;
}
function isUndo(event) {
return isCtrl(event) && !event.shiftKey && event.code === "KeyZ";
}
function isRedo(event) {
return isCtrl(event) && event.shiftKey && event.code === "KeyZ";
}
function insert(text) {
text = text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
document.execCommand("insertHTML", false, text);
}
function debounce(cb, wait) {
let timeout = 0;
return (...args) => {
clearTimeout(timeout);
timeout = window.setTimeout(() => cb(...args), wait);
};
}
function findPadding(text) {
// Find beginning of previous line.
let i = text.length - 1;
while (i >= 0 && text[i] !== "\n")
i--;
i++;
// Find padding of the line.
let j = i;
while (j < text.length && /[ \t]/.test(text[j]))
j++;
return [text.substring(i, j) || "", i, j];
}
function toString() {
return editor.textContent || "";
}
function preventDefault(event) {
event.preventDefault();
}
return {
updateOptions(options) {
options = Object.assign(Object.assign({}, options), options);
},
updateCode(code) {
editor.textContent = code;
highlight(editor);
},
onUpdate(cb) {
callback = cb;
},
toString,
destroy() {
for (let [type, fn] of listeners) {
editor.removeEventListener(type, fn);
}
},
};
}

View File

@ -1,287 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Concurrency &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Concurrency</h2>
<p>Lightweight concurrency is a key feature of Wren and it is expressed using
<em>fibers</em>. They control how all code is executed, and take the place of
exceptions in <a href="error-handling.html">error handling</a>.</p>
<p>Fibers are a bit like threads except they are <em>cooperatively</em> scheduled. That
means Wren doesn&rsquo;t pause one fiber and switch to another until you tell it to.
You don&rsquo;t have to worry about context switches at random times and all of the
headaches those cause.</p>
<p>Wren takes care of all of the fibers in the VM, so they don&rsquo;t use OS thread
resources, or require heavyweight context switches. Each just needs a bit of
memory for its stack. A fiber will get garbage collected like any other object
when not referenced any more, so you can create them freely.</p>
<p>They are lightweight enough that you can, for example, have a separate fiber for
each entity in a game. Wren can handle thousands of them without breaking a
sweat. For example, when you run Wren in interactive mode, it creates a new
fiber for every line of code you type in.</p>
<h2>Creating fibers <a href="#creating-fibers" name="creating-fibers" class="header-anchor">#</a></h2>
<p>All Wren code runs within the context of a fiber. When you first start a Wren
script, a main fiber is created for you automatically. You can spawn new fibers
using the Fiber class&rsquo;s constructor:</p>
<pre class="snippet">
var fiber = Fiber.new {
System.print("This runs in a separate fiber.")
}
</pre>
<p>It takes a <a href="functions.html">function</a> containing the code the fiber should execute. The
function can take zero or one parameter, but no more than that. Creating the
fiber does not immediately run it. It just wraps the function and sits there,
waiting to be activated.</p>
<h2>Invoking fibers <a href="#invoking-fibers" name="invoking-fibers" class="header-anchor">#</a></h2>
<p>Once you&rsquo;ve created a fiber, you run it by calling its <code>call()</code> method:</p>
<pre class="snippet">
fiber.call()
</pre>
<p>This suspends the current fiber and executes the called one until it reaches the
end of its body or until it passes control to yet another fiber. If it reaches
the end of its body, it is considered <em>done</em>:</p>
<pre class="snippet">
var fiber = Fiber.new {
System.print("It's alive!")
}
System.print(fiber.isDone) //> false
fiber.call() //> It's alive!
System.print(fiber.isDone) //> true
</pre>
<p>When a called fiber finishes, it automatically passes control <em>back</em> to the
fiber that called it. It&rsquo;s a runtime error to try to call a fiber that is
already done.</p>
<h2>Yielding <a href="#yielding" name="yielding" class="header-anchor">#</a></h2>
<p>The main difference between fibers and functions is that a fiber can be
suspended in the middle of its operation and then resumed later. Calling
another fiber is one way to suspend a fiber, but that&rsquo;s more or less the same
as one function calling another.</p>
<p>Things get interesting when a fiber <em>yields</em>. A yielded fiber passes control
<em>back</em> to the fiber that ran it, but <em>remembers where it is</em>. The next time the
fiber is called, it picks up right where it left off and keeps going.</p>
<p>You make a fiber yield by calling the static <code>yield()</code> method on Fiber:</p>
<pre class="snippet">
var fiber = Fiber.new {
System.print("Before yield")
Fiber.yield()
System.print("Resumed")
}
System.print("Before call") //> Before call
fiber.call() //> Before yield
System.print("Calling again") //> Calling again
fiber.call() //> Resumed
System.print("All done") //> All done
</pre>
<p>Note that even though this program uses <em>concurrency</em>, it is still
<em>deterministic</em>. You can reason precisely about what it&rsquo;s doing and aren&rsquo;t at
the mercy of a thread scheduler playing Russian roulette with your code.</p>
<h2>Passing values <a href="#passing-values" name="passing-values" class="header-anchor">#</a></h2>
<p>Calling and yielding fibers is used for passing control, but it can also pass
<em>data</em>. When you call a fiber, you can optionally pass a value to it.</p>
<p>If you create a fiber using a function that takes a parameter, you can pass a
value to it through <code>call()</code>:</p>
<pre class="snippet">
var fiber = Fiber.new {|param|
System.print(param)
}
fiber.call("Here you go") //> Here you go
</pre>
<p>If the fiber has yielded and is waiting to resume, the value you pass to call
becomes the return value of the <code>yield()</code> call when it resumes:</p>
<pre class="snippet">
var fiber = Fiber.new {|param|
System.print(param)
var result = Fiber.yield()
System.print(result)
}
fiber.call("First") //> First
fiber.call("Second") //> Second
</pre>
<p>Fibers can also pass values <em>back</em> when they yield. If you pass an argument to
<code>yield()</code>, that will become the return value of the <code>call()</code> that was used to
invoke the fiber:</p>
<pre class="snippet">
var fiber = Fiber.new {
Fiber.yield("Reply")
}
System.print(fiber.call()) //> Reply
</pre>
<p>This is sort of like how a function call may return a value, except that a fiber
may return a whole sequence of values, one every time it yields.</p>
<h2>Full coroutines <a href="#full-coroutines" name="full-coroutines" class="header-anchor">#</a></h2>
<p>What we&rsquo;ve seen so far is very similar to what you can do with languages like
Python and C# that have <em>generators</em>. Those let you define a function call that
you can suspend and resume. When using the function, it appears like a sequence
you can iterate over.</p>
<p>Wren&rsquo;s fibers can do that, but they can do much more. Like Lua, they are full
<em>coroutines</em>&mdash;they can suspend from anywhere in the callstack. The function
you use to create a fiber can call a method that calls another method that calls
some third method which finally calls yield. When that happens, <em>all</em> of those
method calls &mdash; the entire callstack &mdash; gets suspended. For example:</p>
<pre class="snippet">
var fiber = Fiber.new {
(1..10).each {|i|
Fiber.yield(i)
}
}
</pre>
<p>Here, we&rsquo;re calling <code>yield()</code> from within a <a href="functions.html">function</a> being
passed to the <code>each()</code> method. This works fine in Wren because that inner
<code>yield()</code> call will suspend the call to <code>each()</code> and the function passed to it
as a callback.</p>
<h2>Transferring control <a href="#transferring-control" name="transferring-control" class="header-anchor">#</a></h2>
<p>Fibers have one more trick up their sleeves. When you execute a fiber using
<code>call()</code>, the fiber tracks which fiber it will return to when it yields. This
lets you build up a chain of fiber calls that will eventually unwind back to
the main fiber when all of the called ones yield or finish.</p>
<p>This is usually what you want. But if you&rsquo;re doing something low level, like
writing your own scheduler to manage a pool of fibers, you may not want to treat
them explicitly like a stack.</p>
<p>For rare cases like that, fibers also have a <code>transfer()</code> method. This switches
execution to the transferred fiber and &ldquo;forgets&rdquo; the fiber that was transferred
<em>from</em>. The previous one is suspended, leaving it in whatever state it was in.
You can resume the previous fiber by explicitly transferring back to it, or even
calling it. If you don&rsquo;t, execution stops when the last transferred fiber
returns.</p>
<p>Where <code>call()</code> and <code>yield()</code> are analogous to calling and returning from
functions, <code>transfer()</code> works more like an unstructured goto. It lets you freely
switch control between a number of fibers, all of which act as peers to one
another.</p>
<p><br><hr>
<a class="right" href="error-handling.html">Error Handling &rarr;</a>
<a href="classes.html">&larr; Classes</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,221 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Contributing &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Contributing</h2>
<p>Like the bird, Wren&rsquo;s ecosystem is small but full of life. Almost everything is
under active development and there&rsquo;s lots to do. We&rsquo;d be delighted to have you
help.</p>
<p>The first thing to do is to join <a href="https://discord.gg/Kx6PxSX">the discord community</a> (or <a href="https://groups.google.com/forum/#!forum/wren-lang">the mailing list</a>) and say,
&ldquo;Hi&rdquo;. There are no strangers to Wren, just friends we haven&rsquo;t met yet.</p>
<h2>Growing the ecosystem <a href="#growing-the-ecosystem" name="growing-the-ecosystem" class="header-anchor">#</a></h2>
<p>The simplest and often most helpful way to join the Wren party is to be a Wren
<em>user</em>. Create an application that embeds Wren. Write a library or a handy
utility in Wren. Add syntax highlighting support for Wren to your favorite text
editor. Share that stuff and it will help the next Wren user to come along.</p>
<p>If you do any of the above, let us know by adding it to <a href="https://github.com/wren-lang/wren/wiki">the wiki</a>. <br />
We like to keep track of:</p>
<ul>
<li><a href="https://github.com/wren-lang/wren/wiki/Applications">Applications</a> that host Wren as a scripting language.</li>
<li><a href="https://github.com/wren-lang/wren/wiki/Modules">Modules</a> written in Wren that others can use.</li>
<li><a href="https://github.com/wren-lang/wren/wiki/Language-Bindings">Language bindings</a> that let you interact with Wren from other
languages.</li>
<li><a href="https://github.com/wren-lang/wren/wiki/Tools">Tools and utilities</a> that make it easier to be a Wren programmer.</li>
</ul>
<h2>Contributing to Wren <a href="#contributing-to-wren" name="contributing-to-wren" class="header-anchor">#</a></h2>
<p>You&rsquo;re also more than welcome to contribute to Wren itself, both the core VM and
the command-line interpreter. The source is developed <a href="https://github.com/wren-lang/">on GitHub</a>. Our
hope is that the codebase, tests, and <a href="https://github.com/wren-lang/wren/tree/main/doc/site">documentation</a> are easy to
understand and contribute to. If they aren&rsquo;t, that&rsquo;s a bug.</p>
<p>You can learn how to build wren on the <a href="getting-started.html#building-wren">getting started page</a>.</p>
<h3>Finding something to hack on <a href="#finding-something-to-hack-on" name="finding-something-to-hack-on" class="header-anchor">#</a></h3>
<p>Between the <a href="https://github.com/wren-lang/wren/issues">issue tracker</a> and searching for <code>TODO</code> comments in the
code, it&rsquo;s pretty easy to find something that needs doing, though we don&rsquo;t
always do a good job of writing everything down.</p>
<p>If nothing there suits your fancy, new ideas are welcome as well! If you have an
idea for a significant change or addition, please file a <a href="https://github.com/wren-lang/wren/labels/proposal">proposal</a> to discuss
it before writing lots of code. Wren tries very <em>very</em> hard to be minimal which
means often having to say &ldquo;no&rdquo; to language additions, even really cool ones.</p>
<h3>Hacking on docs <a href="#hacking-on-docs" name="hacking-on-docs" class="header-anchor">#</a></h3>
<p>The <a href="/">documentation</a> is one of the easiest&mdash;and most
important!&mdash;parts of Wren to contribute to. The source for the site is
written in <a href="http://daringfireball.net/projects/markdown/">Markdown</a> and lives under <code>doc/site</code>. A
simple Python 3 script, <code>util/generate_docs.py</code>, converts that to HTML and CSS.</p>
<pre><code>$ python util/generate_docs.py
</code></pre>
<p>This generates the site in <code>build/docs/</code>. You can run any simple static web
server from there. Python includes one:</p>
<pre><code>$ cd build/docs
$ python -m http.server
</code></pre>
<p>Running that script every time you change a line of Markdown can be slow,
so there is also a file watching version that will automatically regenerate the
docs when you edit a file:</p>
<pre><code>$ python util/generate_docs.py --watch
</code></pre>
<h3>Hacking on the VM <a href="#hacking-on-the-vm" name="hacking-on-the-vm" class="header-anchor">#</a></h3>
<p>The basic process is simple:</p>
<ol>
<li>
<p><strong>Make sure you can build and run the tests locally.</strong> It&rsquo;s good to ensure
you&rsquo;re starting from a happy place before you poke at the code. Running the
tests is as simple as <a href="getting-started.html#building-wren">building the vm project</a>,
which generates <code>bin/wren_test</code> and then running the following python 3 script:</p>
<pre><code>$ python util/test.py
</code></pre>
<p>If there are no failures, you&rsquo;re good to go.</p>
</li>
<li>
<p><strong><a href="https://help.github.com/articles/fork-a-repo/">Fork the repo</a> so you can change it locally.</strong> Please make your
changes in separate <a href="https://www.atlassian.com/git/tutorials/comparing-workflows/centralized-workflow">feature branches</a> to make things a little easier.</p>
</li>
<li>
<p><strong>Change the code.</strong> Please follow the style of the surrounding code. That
basically means <code>camelCase</code> names, <code>{</code> on the next line, keep within 80
columns, and two spaces of indentation. If you see places where the existing
code is inconsistent, let us know.</p>
</li>
<li>
<p><strong>Write some tests for your new functionality.</strong> They live under <code>test/</code>.
Take a look at some existing tests to get an idea of how to define
expectations.</p>
</li>
<li>
<p><strong>Make sure the tests all pass, both the old ones and your new ones.</strong></p>
</li>
<li>
<p><strong>Add your name and email to the <a href="https://github.com/wren-lang/wren/tree/main/AUTHORS">AUTHORS</a> file if you haven&rsquo;t already.</strong></p>
</li>
<li>
<p><strong>Send a <a href="https://github.com/wren-lang/wren/pulls">pull request</a>.</strong> Pat yourself on the back for contributing to a
fun open source project! </p>
</li>
</ol>
<h2>Getting help <a href="#getting-help" name="getting-help" class="header-anchor">#</a></h2>
<p>If at any point you have questions, feel free to <a href="https://github.com/wren-lang/wren/issues">file an issue</a> or ask
on the <a href="https://discord.gg/Kx6PxSX">discord community</a> (or the <a href="https://groups.google.com/forum/#!forum/wren-lang">mailing list</a>). If you&rsquo;re a Redditor, try the
<a href="https://www.reddit.com/r/wren_lang/">/r/wren_lang</a> subreddit. You can also email me directly (<code>robert</code> at
<code>stuffwithstuff.com</code>) if you want something less public.</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,361 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Control Flow &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Control Flow</h2>
<p>Control flow is used to determine which chunks of code are executed and how many
times. <em>Branching</em> statements and expressions decide whether or not to execute
some code and <em>looping</em> ones execute something more than once.</p>
<h2>Truth <a href="#truth" name="truth" class="header-anchor">#</a></h2>
<p>All control flow is based on <em>deciding</em> whether or not to do something. This
decision depends on some expression&rsquo;s value. We take the entire universe of
possible objects and divide them into two buckets: some we consider &ldquo;true&rdquo; and
the rest are &ldquo;false&rdquo;. If the expression results in a value in the true bucket,
we do one thing. Otherwise, we do something else.</p>
<p>Obviously, the boolean <code>true</code> is in the &ldquo;true&rdquo; bucket and <code>false</code> is in
&ldquo;false&rdquo;, but what about values of other types? The choice is ultimately
arbitrary, and different languages have different rules. Wren&rsquo;s rules follow
Ruby:</p>
<ul>
<li>The boolean value <code>false</code> is false.</li>
<li>The null value <code>null</code> is false.</li>
<li>Everything else is true.</li>
</ul>
<p>This means <code>0</code>, empty strings, and empty collections are all considered &ldquo;true&rdquo;
values.</p>
<h2>If statements <a href="#if-statements" name="if-statements" class="header-anchor">#</a></h2>
<p>The simplest branching statement, <code>if</code> lets you conditionally skip a chunk of
code. It looks like this:</p>
<pre class="snippet">
if (ready) System.print("go!")
</pre>
<p>That evaluates the parenthesized expression after <code>if</code>. If it&rsquo;s true, then the
statement after the condition is evaluated. Otherwise it is skipped. Instead of
a statement, you can have a <a href="syntax.html#blocks">block</a>:</p>
<pre class="snippet">
if (ready) {
System.print("getSet")
System.print("go!")
}
</pre>
<p>You may also provide an <code>else</code> branch. It will be executed if the condition is
false:</p>
<pre class="snippet">
if (ready) System.print("go!") else System.print("not ready!")
</pre>
<p>And, of course, it can take a block too:</p>
<pre class="snippet">
if (ready) {
System.print("go!")
} else {
System.print("not ready!")
}
</pre>
<h2>Logical operators <a href="#logical-operators" name="logical-operators" class="header-anchor">#</a></h2>
<p>Unlike most other <a href="method-calls.html#operators">operators</a> in Wren which are just a special syntax for
<a href="method-calls.html">method calls</a>, the <code>&amp;&amp;</code> and <code>||</code> operators are special. This is because they
only conditionally evaluate the right operand&mdash;they short-circuit.</p>
<p>A <code>&amp;&amp;</code> (&ldquo;logical and&rdquo;) expression evaluates the left-hand argument. If it&rsquo;s
false, it returns that value. Otherwise it evaluates and returns the right-hand
argument.</p>
<pre class="snippet">
System.print(false && 1) //> false
System.print(1 && 2) //> 2
</pre>
<p>A <code>||</code> (&ldquo;logical or&rdquo;) expression is reversed. If the left-hand argument is
<em>true</em>, it&rsquo;s returned, otherwise the right-hand argument is evaluated and
returned:</p>
<pre class="snippet">
System.print(false || 1) //> 1
System.print(1 || 2) //> 1
</pre>
<h2>The conditional operator <code>?:</code> <a href="#the-conditional-operator-" name="the-conditional-operator-" class="header-anchor">#</a></h2>
<p>Also known as the &ldquo;ternary&rdquo; operator since it takes three arguments, Wren has
the little &ldquo;if statement in the form of an expression&rdquo; you know and love from C
and similar languages.</p>
<pre class="snippet">
System.print(1 != 2 ? "math is sane" : "math is not sane!")
</pre>
<p>It takes a condition expression, followed by <code>?</code>, followed by a then
expression, a <code>:</code>, then an else expression. Just like <code>if</code>, it evaluates the
condition. If true, it evaluates and returns the then expression. Otherwise
it does the else expression.</p>
<h2>While statements <a href="#while-statements" name="while-statements" class="header-anchor">#</a></h2>
<p>It&rsquo;s hard to write a useful program without executing some chunk of code
repeatedly. To do that, you use looping statements. There are two in Wren, and
they should be familiar if you&rsquo;ve used other imperative languages.</p>
<p>The simplest, a <code>while</code> statement executes a chunk of code as long as a
condition continues to hold. For example:</p>
<pre class="snippet">
// Hailstone sequence.
var n = 27
while (n != 1) {
if (n % 2 == 0) {
n = n / 2
} else {
n = 3 * n + 1
}
}
</pre>
<p>This evaluates the expression <code>n != 1</code>. If it is true, then it executes the
following body. After that, it loops back to the top, and evaluates the
condition again. It keeps doing this as long as the condition evaluates to
something true.</p>
<p>The condition for a while loop can be any expression, and must be surrounded by
parentheses. The body of the loop is usually a curly block but can also be a
single statement:</p>
<pre class="snippet">
var n = 27
while (n != 1) if (n % 2 == 0) n = n / 2 else n = 3 * n + 1
</pre>
<h2>For statements <a href="#for-statements" name="for-statements" class="header-anchor">#</a></h2>
<p>While statements are useful when you want to loop indefinitely or according to
some complex condition. But in most cases, you&rsquo;re looping through
a <a href="lists.html">list</a>, a series of numbers, or some other &ldquo;sequence&rdquo; object.
That&rsquo;s what <code>for</code> is, uh, for. It looks like this:</p>
<pre class="snippet">
for (beatle in ["george", "john", "paul", "ringo"]) {
System.print(beatle)
}
</pre>
<p>A <code>for</code> loop has three components:</p>
<ol>
<li>
<p>A <em>variable name</em> to bind. In the example, that&rsquo;s <code>beatle</code>. Wren will create
a new variable with that name whose scope is the body of the loop.</p>
</li>
<li>
<p>A <em>sequence expression</em>. This determines what you&rsquo;re looping over. It gets
evaluated <em>once</em> before the body of the loop. In this case, it&rsquo;s a list
literal, but it can be any expression.</p>
</li>
<li>
<p>A <em>body</em>. This is a curly block or a single statement. It gets executed once
for each iteration of the loop.</p>
</li>
</ol>
<h2>Break statements <a href="#break-statements" name="break-statements" class="header-anchor">#</a></h2>
<p>Sometimes, right in the middle of a loop body, you decide you want to bail out
and stop. To do that, you can use a <code>break</code> statement. It&rsquo;s just the <code>break</code>
keyword all by itself. That immediately exits out of the nearest enclosing
<code>while</code> or <code>for</code> loop.</p>
<pre class="snippet">
for (i in [1, 2, 3, 4]) {
System.print(i) //> 1
if (i == 3) break //> 2
} //> 3
</pre>
<h2>Continue statements <a href="#continue-statements" name="continue-statements" class="header-anchor">#</a></h2>
<p>During the execution of a loop body, you might decide that you want to skip the
rest of this iteration and move on to the next one. You can use a <code>continue</code>
statement to do that. It&rsquo;s just the <code>continue</code> keyword all by itself. Execution
will immediately jump to the beginning of the next loop iteration (and check the
loop conditions).</p>
<pre class="snippet">
for (i in [1, 2, 3, 4]) {
if (i == 2) continue //> 1
System.print(i) //> 3
} //> 4
</pre>
<h2>Numeric ranges <a href="#numeric-ranges" name="numeric-ranges" class="header-anchor">#</a></h2>
<p>Lists are one common use for <code>for</code> loops, but sometimes you want to walk over a
sequence of numbers, or loop a number of times. For that, you can create a
<a href="values.html#ranges">range</a>, like so:</p>
<pre class="snippet">
for (i in 1..100) {
System.print(i)
}
</pre>
<p>This loops over the numbers from 1 to 100, including 100 itself. If you want to
leave off the last value, use three dots instead of two:</p>
<pre class="snippet">
for (i in 1...100) {
System.print(i)
}
</pre>
<p>This looks like some special &ldquo;range&rdquo; syntax in the <code>for</code> loop, but it&rsquo;s actually
just a pair of operators. The <code>..</code> and <code>...</code> syntax are infix &ldquo;range&rdquo; operators.
Like <a href="method-calls.html#operators">other operators</a>, they are special syntax for a regular method
call. The number type implements them and returns a <a href="values.html#ranges">range object</a> that knows
how to iterate over a series of numbers.</p>
<h2>The iterator protocol <a href="#the-iterator-protocol" name="the-iterator-protocol" class="header-anchor">#</a></h2>
<p>Lists and ranges cover the two most common kinds of loops, but you should also
be able to define your own sequences. To enable that, the semantics of <code>for</code>
are defined in terms of an &ldquo;iterator protocol&rdquo;. The loop itself doesn&rsquo;t know
anything about lists or ranges, it just knows how to call two particular
methods on the object that resulted from evaluating the sequence expression.</p>
<p>When you write a loop like this:</p>
<pre class="snippet">
for (i in 1..100) {
System.print(i)
}
</pre>
<p>Wren sees it something like this:</p>
<pre class="snippet">
var iter_ = null
var seq_ = 1..100
while (iter_ = seq_.iterate(iter_)) {
var i = seq_.iteratorValue(iter_)
System.print(i)
}
</pre>
<p>First, Wren evaluates the sequence expression and stores it in a hidden
variable (written <code>seq_</code> in the example but in reality it doesn&rsquo;t have a name
you can use). It also creates a hidden &ldquo;iterator&rdquo; variable and initializes it
to <code>null</code>.</p>
<p>Each iteration, it calls <code>iterate()</code> on the sequence, passing in the current
iterator value. (In the first iteration, it passes in <code>null</code>.) The sequence&rsquo;s
job is to take that iterator and advance it to the next element in the
sequence. (Or, in the case where the iterator is <code>null</code>, to advance it to the
<em>first</em> element). It then returns either the new iterator, or <code>false</code> to
indicate that there are no more elements.</p>
<p>If <code>false</code> is returned, Wren exits out of the loop and we&rsquo;re done. If anything
else is returned, that means that we have advanced to a new valid element. To
get that, Wren then calls <code>iteratorValue()</code> on the sequence and passes in the
iterator value that it just got from calling <code>iterate()</code>. The sequence uses
that to look up and return the appropriate element.</p>
<p>The built-in <a href="lists.html">List</a> and <a href="values.html#ranges">Range</a> types implement
<code>iterate()</code> and <code>iteratorValue()</code> to walk over their respective sequences. You
can implement the same methods in your classes to make your own types iterable.</p>
<p><br><hr>
<a class="right" href="variables.html">Variables &rarr;</a>
<a href="method-calls.html">&larr; Method Calls</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

78
doc/error-handling.txt Normal file
View File

@ -0,0 +1,78 @@
Q: Can we use fibers for error-handling?
The goal here is to avoid adding support for exception handling if we're already
going to support fibers. A potential bonus would be being able to have
restartable error-handling.
The general idea is that instead of putting code in a "try" block, you throw it
onto a new fiber. If an error occurs, that fiber is paused, and returns control
back to the spawning fiber. The parent fiber can then decipher the error and
either abandon the fiber, or try to fix the error and resume somehow.
The first question is what kinds of errors is this useful for. For things like
parsing strings where failure is common and error-handling needs to be
lightweight, I think using fibers is too heavy, both in performance and code.
A better answer there is to lean on dynamic typing and return null on parse
failure.
On the other hand, it might be nice to be able to resume here if the code that
provided the string is far away and you don't want to have to manually propagate
the error out.
Programmatic errors like invalid argument types should halt the fiber but the
programmer will not want to resume that at runtime. Using the mechanism here is
fine since it would then dump a stack trace, etc. But it won't take advantage
of resuming.
Resuming is probably useful for things like IO errors where the error can't be
easily predicted beforehand but where you may want to handle it gracefully. For
example, if a file can't be opened, the caller may want to wait a while and
try again.
--
After thinking about it, maybe resuming is a bridge too far. Erlang's model is
that a failure just kills the process. I'll note that Erlang does have try and
catch, though.
The goals for error-handling in a scripting language are:
0. Have simple semantics and implementation.
1. Make it easy for developers to track down programmatic errors so they can
fix them. This means bugs like wrong argument types should fail immediately
and loudly, and should provide context (a callstack) about where the error
occurred.
2. For runtime errors like parsing an invalid string or opening a missing file,
the program should be able to easily detect the error at handle it.
3. It *may* be useful for programmers to be able to trap all errors and try to
keep the program alive, or at least log the error in a meaningful way. When
you have user-defined scripts, or a lot of code, or code authored by
non-technical people, it's nice if a failure in one part can be reported but
not take down the entire system.
Two close-at-hand examples:
- The REPL. A bug in code in the REPL shouldn't kill the whole REPL session.
- The test framework. In order to write tests in Wren that test programmatic
runtime errors, we need to be able to detect them and output something.
The test runner could just parse the error output when the entire process
dies, but that means you can only have one error test per test file.
Given those, I'm thinking:
1. Programmatic errors take down the entire fiber and dump a callstack.
Normally, they will also take down the parent fiber and so on until the
entire program goes down.
2. Runtime errors return error codes (or null). Things like parsing a string to
a number, etc. should just return an error that you are responsible for
handling.
3. When handing off control to a fiber, there is a "guarded run" method that
will run the fiber. If it fails with a programmatic error, the invoked fiber
dies, but the parent does not. It gets the callstack and error as some sort
of object it can poke at.

29
doc/implicit fields.txt Normal file
View File

@ -0,0 +1,29 @@
Q: Can fields be implicitly declared?
The idea is that just using a name starting with "_" somewhere in a class
automatically defines a field with that name. Implicit fields are particularly
nice because it means they don't have to be defined all before methods. (Since
we have a single-pass compiler, we would have to otherwise a method could
only refer to previously defined fields.)
One potential problem is with nested classes. This is more important if we
consider a module effectively a class. Consider:
class Outer {
foo {
_blah = "value"
}
class Inner {
IO.write(_blah) // Does this declare field in Inner, or access Outer?
}
}
Looking at this, though, I think there's already a question how referring to an
outer field would work. Having an instance of Inner doesn't imply you also have
an instance of Outer. We definitely don't want to recapitulate inner classes
in Java.
Q: What about static fields?
A: Different naming convention? __foo?

View File

@ -0,0 +1,65 @@
This is the number of times each instruction was executed when running the
delta_blue benchmark:
3753021 CODE_LOAD_LOCAL
2233991 CODE_RETURN
2151580 CODE_LOAD_FIELD_THIS
2121398 CODE_CALL_1
1827535 CODE_CALL_0
1328364 CODE_POP
1136064 CODE_JUMP_IF
715071 CODE_LOAD_GLOBAL
428374 CODE_STORE_FIELD_THIS
424999 CODE_NULL
355344 CODE_STORE_LOCAL
341762 CODE_LOOP
118855 CODE_CONSTANT
93048 CODE_CALL_2
75280 CODE_AND
59920 CODE_JUMP
16842 CODE_LIST
16660 CODE_TRUE
10040 CODE_OR
8200 CODE_LOAD_UPVALUE
8140 CODE_SUPER_1
6540 CODE_FALSE
6076 CODE_STORE_GLOBAL
4000 CODE_SUPER_3
2020 CODE_SUPER_2
2000 CODE_SUPER_0
2000 CODE_CALL_5
2000 CODE_CALL_3
160 CODE_CLOSURE
74 CODE_METHOD_INSTANCE
11 CODE_CLASS
4 CODE_METHOD_STATIC
0 CODE_SUPER_9
0 CODE_SUPER_8
0 CODE_SUPER_7
0 CODE_SUPER_6
0 CODE_SUPER_5
0 CODE_SUPER_4
0 CODE_SUPER_16
0 CODE_SUPER_15
0 CODE_SUPER_14
0 CODE_SUPER_13
0 CODE_SUPER_12
0 CODE_SUPER_11
0 CODE_SUPER_10
0 CODE_STORE_UPVALUE
0 CODE_STORE_FIELD
0 CODE_LOAD_FIELD
0 CODE_IS
0 CODE_CLOSE_UPVALUE
0 CODE_CALL_9
0 CODE_CALL_8
0 CODE_CALL_7
0 CODE_CALL_6
0 CODE_CALL_4
0 CODE_CALL_16
0 CODE_CALL_15
0 CODE_CALL_14
0 CODE_CALL_13
0 CODE_CALL_12
0 CODE_CALL_11
0 CODE_CALL_10

View File

@ -0,0 +1,146 @@
var baz = "top level"
class Foo {
bar {
baz
_baz
}
baz { "getter" }
_baz { "private getter" }
this {
_baz = "field"
}
}
Given `_foo`, how do we tell if it is:
1. A call to a private getter
2. Accessing a private field
3. Tearing off a reference to a private method
It's not 3 because of arity overloading. Wren doesn't really have method
tear-off because of this.)
This is hard because the getter may not be defined yet. One option is:
It's always a call to a private getter. After the class is defined, we see if
there are any private getters that were not implemented and define implicit
getters for them that return fields.
That's weird if you take into account setters, though. Consider:
class Foo {
a { IO.write(_prop) }
_prop = value { ... }
}
For first reference to `_prop`, compile it to getter call. Then see setter
defined for it, so we no longer implicitly make a field. But there's no getter,
so now the above call will fail.
Probably do want call to fail here, so that may be OK.
---
Given `_foo(arg)`, how do we tell if it is:
1. A call to a private method
2. A call to a private getter, which returns a field that's a fn, and invoking
it.
Since arity is part of the name, the answer here is 1.
---
Given `foo(arg)` inside a class, how do we tell if it is:
1. A call to a method on this.
2. Accessing a field `foo` on this, which returns a fn, and invoking it.
3. Calling a getter `foo` on this, which returns a fn, and invoking it.
4. A call to a top-level fn.
Let's just dismiss 3. Since arity affects naming, `foo(arg)` and `(foo)(arg)`
are really different things in Wren. The parentheses and args are effectively
part of the name.
That covers 2 as well. If we ditch top level fns, we're left with 1. This is
good, I think. It means the common case of calling methods on yourself is nice
and terse.
---
Given `foo` inside a class, how do we tell if it is:
1. Accessing a field on this.
2. Calling a getter on this.
3. Accessing a global variable.
4. Accessing a top-level getter.
5. Accessing a local variable.
We can probably ditch 4. We can ditch 1 because Wren doesn't have public fields.
Because both getters and global variables can be used before they are defined,
we can't determine statically (in a single pass compiler) if there is a global
variable or getter named `foo` in order to disambiguate. Even if we could, we'd
still have to answer the ambiguous case where it's both.
If we assume it's a global and the user wants a getter, they can always do
`this.foo` to be explicit. If we assume it's getter, how would they indicate a
global?
One option is to have a different naming convention for globals, like a
capitalized initial variable. That lines up with class names at the top level
anyway. It just means if we have variables for imported modules, we'll want to
capitalize those.
We still have to distinguish locals, but since those are declared before use, we
can determine that statically. I.e. locals will shadow implicit getters.
---
OK, so here's one proposal:
class MyClass {
method {
_foo // access field
_foo(arg) // not valid
foo // local var or getter on this
foo(arg) // method on this
Foo // global variable
}
}
This is simple, and straightforward to compile. Using capitalization for globals
is a bit weird, and not having private methods is a bummer, but maybe simplicity
is the right answer.
Here's another:
class MyClass {
method {
_foo // private getter on this
_foo(arg) // private method on this
foo // local var or getter on this
foo(arg) // method on this
Foo // global variable
}
}
To get rid of the weird capitalization rule for globals, one option is to not
allow forward references to globals. That would break mutually recursive
references to classes, though:
class A {
foo { B.new }
}
class B {
foo { A.new }
}
So, not a fan of that.
Ignoring that, the main difference between the two proposals is the second has
private methods. Since the first proposal is practically a subset of the second,
let's start with that one first.

View File

@ -0,0 +1,76 @@
Q1: What does this resolve to:
foo(arg)
It could be:
1. this.foo(arg)
2. EnclosingClass.foo(arg) // i.e. a static method call
3. a call to a top-level function foo()
If we adopt the idea that a module is just a class definition (with some
syntactic differences) and classes can be nested, then 3 really means "a call
to a static method on the class surrounding the enclosing class".
I *don't* think we want the answer to the question to vary based on the name
in question. We can't rely on name resolution to disambiguate because we don't
know the full set of surrounding names in a single pass compiler. Also, it's
semantically squishier.
I think the right answer is 1, it's an implicit call on this. That's what you
want most often, I think. For imported modules, we could import them with a
"prefix" (really import them as objects bound to named variables), so calling
a top-level function in another module would be something like:
someModule.foo(arg)
This leaves the question of how *do* you call top level functions in your own
module? I.e., how do we call foo here:
def foo(arg) { IO.write("called foo!") }
class SomeClass {
bar {
// Want to call foo here...
}
}
This is analogous to:
class SomeModule {
static foo(arg) { IO.write("called foo!") }
class SomeClass {
bar {
// Want to call foo here...
}
}
}
The obvious solution is to use the class name:
class SomeModule {
static foo(arg) { IO.print("called foo!") }
class SomeClass {
bar {
SomeModule.foo(arg)
}
}
}
Which just leaves the question of what the class name of a top-level "module
class" is.
Idea: it's unnamed, so you just use a leading ".":
def foo(arg) { IO.print("called foo!") }
class SomeClass {
bar {
.foo(arg)
}
}
This mirrors C++'s unnamed scope thing:
::foo(arg);

62
doc/site outline.txt Normal file
View File

@ -0,0 +1,62 @@
-- new
- introduction
- getting started
- tutorial
- community
- contributing
- guide
- basic syntax
scripts, comments, newlines, names
- values
null, bools, numbers, strings, and ranges
- collections
lists and maps
- expressions
calls, this, super, operators, is
- control flow
if, while, for, sequence protocol, && ||, ?:
- variables
var, assignment, scope, blocks
- functions
block arguments, closures
- classes
- concurrency
- error handling
- modules
- embedding
- core module
...
- cli modules
- io
- scheduler
- timer
...
- reference
- performance
- faq
-- current
- getting started
- language
- syntax
- expressions
- variables
- control flow
- error handling
- modules
- types
- values
- classes
- fibers
- functions
- lists
- maps
- reference
- core
- embedding api
- performance
- community
- contributing
- qa

411
doc/site/classes.markdown Normal file
View File

@ -0,0 +1,411 @@
^title Classes
^category types
Every value in Wren is an object, and every object is an instance of a class.
Even `true` and `false` are full-featured objects&mdash;instances of the
[`Bool`](core/bool.html) class.
Classes contain both *behavior* and *state*. Behavior is defined in *methods*
which are stored in the class. State is defined in *fields*, whose values are
stored in each instance.
## Defining a class
Classes are created using the `class` keyword, unsurprisingly:
:::wren
class Unicorn {}
This creates a class named `Unicorn` with no methods or fields.
## Methods
To let our unicorn do stuff, we need to give it methods.
:::wren
class Unicorn {
prance() {
System.print("The unicorn prances in a fancy manner!")
}
}
This defines a `prance()` method that takes no arguments. To support
parameters, put their names inside the parentheses:
:::wren
class Unicorn {
prance(where, when) {
System.print("The unicorn prances in " + where + " at " + when)
}
}
### Signature
Unlike most other dynamically-typed languages, in Wren you can have multiple
methods in a class with the same name, as long as they have a different
*signature*. In technical terms, you can *overload by arity*. So this class is
fine:
:::wren
class Unicorn {
prance() {
System.print("The unicorn prances in a fancy manner!")
}
prance(where) {
System.print("The unicorn prances in " + where)
}
prance(where, when) {
System.print("The unicorn prances in " + where + " at " + when)
}
}
And you can call each of the methods like so:
:::wren
var unicorn = Unicorn.new()
unicorn.prance()
unicorn.prance("Antwerp")
unicorn.prance("Brussels", "high noon")
The number of arguments provided at the callsite determines which method is
chosen.
It's often natural to have the same conceptual operation work with different
sets of arguments. In other languages, you'd define a single method for the
operation and have to check for "undefined" or missing arguments. Wren just
treats them as different methods that you can implement separately.
### Getters
Many methods on a class exist to expose or compute some property of the object.
For example:
:::wren
System.print("string".count) // "6".
These *getters* are just another kind of method&mdash;one without a parameter
list. You can define them like so:
:::wren
class Unicorn {
isFancy { true } // Unicorns are always fancy.
}
Whether or not a method name has parentheses is also part of its signature.
This lets you distinguish between a method that takes an *empty* argument list
(`()`) and no argument list at all:
:::wren
class Confusing {
method { "no argument list" }
method() { "empty argument list" }
}
var confusing = Confusing.new()
confusing.method // "no argument list".
confusing.method() // "empty argument list".
Like the example says, having two methods that differ just by an empty set of
parentheses is pretty confusing. That's not what this is for. Instead, it
ensures that the way you *declare* the method is the way you *call* it.
Unlike other languages with "optional parentheses", Wren wants to make sure you
call a getter like a getter and a `()` method like a `()` method. These don't
work:
:::wren
"string".count()
list.clear
Methods that don't need arguments and don't modify the underlying object are
usually getters:
:::wren
"string".count
(1..10).min
1.23.sin
[1, 2, 3].isEmpty
When a method doesn't need any parameters, but does modify the object, it's
helpful to draw attention to that by requiring an empty set of parentheses:
:::wren
list.clear()
Also, when a method supports multiple arities, it's typical to include the `()`
in the zero-argument case to be consistent with the other versions:
Fn.new { "a function" }.call()
Fiber.yield()
### Operators
Operators are just special syntax for a method call on the left hand operand
(or only operand in the case of unary operators like `!` and `~`). In other
words, you can think of `a + b` as meaning `a.+(b)`.
You can define operators in your class like so:
:::wren
class Unicorn {
// Infix:
+(other) {
System.print("Adding to a unicorn?")
}
// Prefix:
! {
System.print("Negating a unicorn?!")
}
}
This can be used to define any of these operators:
:::wren
// Infix:
+ - * / % < > <= >= == != & |
// Prefix:
! ~ -
Note that `-` can be both a prefix and infix operator. If there's a parameter
list, it's the infix one, otherwise, it's prefix. Since Wren supports
overloading by arity, it's no problem for a class to define both.
### Subscript operators
**TODO**
### Setters
**TODO**
## Constructors
Unicorns can prance around now, but we don't actually *have* any unicorns to do
it. To create instances of a class, we need a *constructor*. You can define one
like so:
:::wren
class Unicorn {
construct new(name, color) {
System.print("My name is " + name + " and I am " + color + ".")
}
}
The `construct` keyword says we're defining a constructor, and `new` is its
name. In Wren, all constructors have names, just like [methods][#methods]. The
word "new" isn't special to Wren, it's just a common constructor name.
To make a unicorn now, we just call the constructor method on the class itself:
:::wren
var fred = Unicorn.new("Fred", "palomino")
Giving constructors names is handy because it means you can have more than one,
and each can clarify how it creates the instance:
:::wren
class Unicorn {
construct brown(name) {
System.print("My name is " + name + " and I am brown.")
}
}
var dave = Unicorn.brown("Dave")
Note that we have to declare a constructor because, unlike some other
languages, Wren doesn't give you a default one. This is useful because some
classes aren't designed to be constructed. If you have an abstract base class
that just contains methods to be inherited by other classes, it doesn't need
and won't have a constructor.
Like other methods, constructors can obviously have arguments, and can be
overloaded by [arity](#signature). A constructor *must* be a named method with
a (possibly empty) argument list. Operators, getters, and setters cannot be
constructors.
A constructor is actually a pair of methods. You get a method on the class:
:::wren
Unicorn.brown("Dave")
That creates the new instance, then it invokes the *initializer* on that
instance. This is where the constructor body you defined gets run.
This distinction is important because it means inside the body of the
constructor, you can access `this`, assign [fields](#fields), call superclass
constructors, etc.
## Fields
All state stored in instances is stored in *fields*. Each field has a named
that starts with an underscore.
:::wren
class Rectangle {
area { _width * _height }
// Other stuff...
}
Here, `_width` and `_height` in the `area` [getter](classes.html#methods) refer
to fields on the rectangle instance. You can think of them like `this.width`
and `this.height` in other languages.
When a field name appears, Wren looks for the nearest enclosing class and looks
up the field on the instance of that class. Field names cannot be used outside
of an instance method. They *can* be used inside a [function](functions.html)
in a method. Wren will look outside any nested functions until it finds an
enclosing method.
Unlike [variables](variables.html), fields are implicitly declared by simply
assigning to them. If you access a field before it has been initialized, its
value is `null`.
### Encapsulation
All fields are *private* in Wren&mdash;an object's fields can only be directly
accessed from within methods defined on the object's class. You cannot even
access fields on another instance of your own class, unlike C++ and Java.
If you want to make a property of an object visible, you need to define a
getter to expose it:
:::wren
class Rectangle {
width { _width }
height { _height }
// ...
}
To allow outside code to modify the field, you'll also need to provide setters:
:::wren
class Rectangle {
width=(value) { _width = value }
height=(value) { _height = value }
}
One thing we've learned in the past forty years of software engineering is that
encapsulating state tends to make code easier to maintain, so Wren defaults to
keeping your object's state pretty tightly bundled up. Don't feel that you have
to or even should define getters or setters for most of your object's fields.
## Metaclasses and static members
**TODO**
### Static fields
A name that starts with *two* underscores is a *static* field. They work
similar to [fields](#fields) except the data is stored on the class itself, and
not the instance. They can be used in *both* instance and static methods.
:::wren
class Foo {
// Set the static field.
static set(a) {
__a = a
}
setFromInstance(a) {
__a = a
}
// Can use __a in both static methods...
static bar { __a }
// ...and instance ones.
baz { __a }
}
Just like instance fields, static fields are initially `null`:
:::wren
System.print(Foo.bar) // null.
They can be used from static methods:
:::wren
Foo.set("foo")
System.print(Foo.bar) // foo.
And also instance methods. When you do so, there is still only one static field
shared among all instances of the class:
:::wren
var foo1 = Foo.new()
var foo2 = Foo.new()
foo1.setFromInstance("updated")
System.print(foo2.baz) // updated.
## Inheritance
A class can inherit from a "parent" or *superclass*. When you invoke a method
on an object of some class, if it can't be found, it walks up the chain of
superclasses looking for it there.
By default, any new class inherits from `Object`, which is the superclass from
which all other classes ultimately descend. You can specify a different parent
class using `is` when you declare the class:
:::wren
class Pegasus is Unicorn {}
This declares a new class `Pegasus` that inherits from `Unicorn`.
Note that you should not create classes that inherit from the built-in types (Bool, Num, String, Range, List). The built-in types expect their internal bit representation to be very specific and get horribly confused when you invoke one of the inherited built-in methods on the derived type.
The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if
`Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will not inherit from
`Unicorn`'s metaclass. In more prosaic terms, this means that static methods
are not inherited.
:::wren
class Unicorn {
// Unicorns cannot fly. :(
static canFly { false }
}
class Pegasus is Unicorn {}
Pegasus.canFly // ERROR: Static methods are not inherited.
This also means constructors are not inherited:
:::wren
class Unicorn {
this new(name) {
System.print("My name is " + name + ".")
}
}
class Pegasus is Unicorn {}
Pegasus.new("Fred") // Error!
Each class gets to control how it may be constructed independently of its base
classes. However, constructor *initializers* are inherited since those are
instance methods on the new object.
This means you can do `super` calls inside a constructor:
:::wren
class Unicorn {
this new(name) {
System.print("My name is " + name + ".")
}
}
class Pegasus is Unicorn {
this new(name) {
super(name)
}
}
Pegasus.new("Fred") // Prints "My name is Fred.".

View File

@ -0,0 +1,49 @@
^title Community
^category reference
Like the [bird](https://en.wikipedia.org/wiki/Wren), Wren's community is small,
but it exists!
## User group
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.
## Libraries
There are some third-party libraries that are written in Wren. Here's the list:
- [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.
## 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)
## Editor integrations
If you want Wren syntax highlighting in your editor, look no further:
- [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][]!
[pull request]: https://github.com/munificent/wren/pulls

View File

@ -0,0 +1,125 @@
^title Contributing
^category reference
It should be obvious by now that Wren is under active development and there's
lots left to do. We'd be delighted to have you participate.
## Getting acquainted
[Pull requests][pull request] and [bug reports][issue] are always welcome. But,
if you'd like to dip your toes in the water before diving in, please join
[the mailing list][list] and say, "Hi". There's no strangers to Wren, just
friends we haven't met yet.
## The source
Wren uses the OSI-approved [MIT license][mit]. I'm not sure exactly what that
means, but I went with the most permissive license I could find.
The source is developed [on GitHub][github]. My hope is that the codebase,
tests, and [documentation][docs] are easy to understand and contribute to. If
they aren't, that's a bug.
## Finding something to hack on
Eventually, the [issue tracker][issue] will be populated with a more complete
set of changes and features I have in mind. Until then, one easy way to find
things that need doing is to look for `TODO` comments in the code.
Also, writing code in Wren and seeing what problems you run into is incredibly
helpful. Embedding Wren in an application will also exercise lots of corners of
the system and highlight problems and missing features.
Of course, new ideas are also welcome as well! If you have an idea for a
significant change or addition, please file a [proposal][] to discuss it
before writing lots of code. Wren tries very *very* hard to be minimal which
means often having to say "no" to language additions, even really cool ones.
## Hacking on docs
The [documentation][] is one of the easiest&mdash;and most
important!&mdash;parts of Wren to contribute to. The source for the site is
written in [Markdown][] (and a little [SASS][]) and lives under `doc/site`. A
simple Python script, `util/generate_docs.py`, converts that to HTML and CSS.
[documentation]: /
[markdown]: http://daringfireball.net/projects/markdown/
[sass]: http://sass-lang.com/
The site uses [Pygments][] for syntax highlighting, with a custom lexer plug-in
for Wren. To install that, run:
[pygments]: http://pygments.org
:::sh
$ cd util/pygments-lexer
$ sudo python setup.py develop
$ cd ../.. # Back to the root Wren directory.
Now you can build the docs:
:::sh
$ make docs
This generates the site in `build/docs/`. You can run any simple static web
server from there. Python includes one:
:::sh
$ cd build/docs
$ python -m SimpleHTTPServer
Running `make docs` is a drag every time you change a line of Markdown or SASS,
so there is also a file watching version that will automatically regenerate the
docs when you edit a file:
:::sh
$ make watchdocs
## Hacking on the VM
The basic process is simple:
1. **Make sure you can build and run the tests locally.** It's good to ensure
you're starting from a happy place before you poke at the code. Running the
tests is as simple as:
:::sh
$ make test
If there are no failures, you're good to go.
2. **[Fork the repo][fork] so you can change it locally.** Please make your
changes in separate [feature branches][] to make things a little easier on
me.
3. **Change the code.** Please follow the style of the surrounding code. That
basically means `camelCase` names, `{` on the next line, keep within 80
columns, and two spaces of indentation. If you see places where the existing
code is inconsistent, let me know.
4. **Write some tests for your new functionality.** They live under `test/`.
Take a look at some existing tests to get an idea of how to define
expectations.
5. **Make sure the tests all pass, both the old ones and your new ones.**
6. **Add your name and email to the [AUTHORS][] file if you haven't already.**
7. **Send a [pull request][].** Pat yourself on the back for contributing to a
fun open source project! I'll take it from here and hopefully we'll get it
landed smoothly.
If at any point you have questions, feel free to [file an issue][issue] or ask
on the [mailing list][list]. You can also email me directly (`robert` at
`stuffwithstuff.com`) if you want something less public. *Thank you!*
[mit]: http://opensource.org/licenses/MIT
[github]: https://github.com/munificent/wren
[fork]: https://help.github.com/articles/fork-a-repo/
[docs]: https://github.com/munificent/wren/tree/master/doc/site
[issue]: https://github.com/munificent/wren/issues
[proposal]: https://github.com/munificent/wren/labels/proposal
[feature branches]: https://www.atlassian.com/git/tutorials/comparing-workflows/centralized-workflow
[authors]: https://github.com/munificent/wren/tree/master/AUTHORS
[pull request]: https://github.com/munificent/wren/pulls
[list]: https://groups.google.com/forum/#!forum/wren-lang

View File

@ -0,0 +1,204 @@
^title Control Flow
^category language
Control flow is used to determine which chunks of code are executed and how
many times. *Branching* statements decide whether or not to execute some code
and *looping* ones execute something more than once.
## Truth
All control flow is based on *deciding* whether or not to do something. This
decision is conditional on the value of some expression. We take the entire
universe of possible values and divide them into two buckets: some we consider
"true" and the rest are "false". If the expression results in a value in the
true bucket, we do one thing. Otherwise, we do something else.
Obviously, the boolean `true` is in the "true" bucket and `false` is in
"false", but what about values of other types? The choice is ultimately
arbitrary, and different languages have different rules. Wren's rules follow
Ruby:
* The boolean value `false` is false.
* The null value `null` is false.
* Everything else is true.
This means `0`, empty strings, and empty collections are all considered "true"
values.
## If statements
The simplest branching statement, `if` lets you conditionally skip a chunk of
code. It looks like this:
:::wren
if (ready) System.print("go!")
That evaluates the parenthesized expression after `if`. If it's true, then the
statement after the condition is evaluated. Otherwise it is skipped. Instead of
a statement, you can have a [block](syntax.html#blocks):
:::wren
if (ready) {
System.print("getSet")
System.print("go!")
}
You may also provide an `else` branch. It will be executed if the condition is
false:
:::wren
if (ready) System.print("go!") else System.print("not ready!")
And, of course, it can take a block too:
:::wren
if (ready) {
System.print("go!")
} else {
System.print("not ready!")
}
## While statements
It's hard to write a useful program without executing some chunk of code
repeatedly. To do that, you use looping statements. There are two in Wren, and
they should be familiar if you've used other imperative languages.
The simplest, a `while` statement executes a chunk of code as long as a
condition continues to hold. For example:
:::wren
// Hailstone sequence.
var n = 27
while (n != 1) {
if (n % 2 == 0) {
n = n / 2
} else {
n = 3 * n + 1
}
}
This evaluates the expression `n != 1`. If it is true, then it executes the
following body. After that, it loops back to the top, and evaluates the
condition again. It keeps doing this as long as the condition evaluates to
something true.
The condition for a while loop can be any expression, and must be surrounded by
parentheses. The body of the loop is usually a curly block but can also be a
single statement:
:::wren
var n = 27
while (n != 1) if (n % 2 == 0) n = n / 2 else n = 3 * n + 1
## For statements
While statements are useful when you want to loop indefinitely or according to
some complex condition. But in most cases, you're looping through
a [list](lists.html), a series of numbers, or some other "sequence" object.
That's what `for` is, uh, for. It looks like this:
:::wren
for (beatle in ["george", "john", "paul", "ringo"]) {
System.print(beatle)
}
A `for` loop has three components:
1. A *variable name* to bind. In the example, that's `beatle`. Wren will create
a new variable with that name whose scope is the body of the loop.
2. A *sequence expression*. This determines what you're looping over. It gets
evaluated *once* before the body of the loop. In this case, it's a list
literal, but it can be any expression.
3. A *body*. This is a curly block or a single statement. It gets executed once
for each iteration of the loop.
## Break statements
Sometimes, right in the middle of a loop body, you decide you want to bail out
and stop. To do that, you can use a `break` statement. It's just the `break`
keyword all by itself. That will immediately exit out of the nearest enclosing
`while` or `for` loop.
:::wren
for (i in [1, 2, 3, 4]) {
System.print(i)
if (i == 3) break
}
So this program will print the numbers from 1 to 3, but will not print 4.
## Numeric ranges
Lists are one common use for `for` loops, but sometimes you want to walk over a
sequence of numbers, or loop a number of times. For that, you can create a
[range](values.html#ranges), like so:
:::wren
for (i in 1..100) {
System.print(i)
}
This loops over the numbers from 1 to 100, including 100 itself. If you want to
leave off the last value, use three dots instead of two:
:::wren
for (i in 1...100) {
System.print(i)
}
This looks like some special "range" syntax in the `for` loop, but it's
actually just a pair of operators. The `..` and `...` syntax are infix "range"
operators. Like [other operators](expressions.html#operators), they are just
special syntax for a regular method call. The number type implements them and
returns a [range object](values.html#ranges) that knows how to iterate over a
series of numbers.
## The iterator protocol
Lists and ranges cover the two most common kinds of loops, but you should also
be able to define your own sequences. To enable that, the semantics of `for`
are defined in terms of an "iterator protocol". The loop itself doesn't know
anything about lists or ranges, it just knows how to call two particular
methods on the object that resulted from evaluating the sequence expression.
When you write a loop like this:
:::wren
for (i in 1..100) {
System.print(i)
}
Wren sees it something like this:
:::wren
var iter_ = null
var seq_ = 1..100
while (iter_ = seq_.iterate(iter_)) {
var i = seq_.iteratorValue(iter_)
System.print(i)
}
First, Wren evaluates the sequence expression and stores it in a hidden
variable (written `seq_` in the example but in reality it doesn't have a name
you can use). It also creates a hidden "iterator" variable and initializes it
to `null`.
Each iteration, it calls `iterate()` on the sequence, passing in the current
iterator value. (In the first iteration, it passes in `null`.) The sequence's
job is to take that iterator and advance it to the next element in the
sequence. (Or, in the case where the iterator is `null`, to advance it to the
*first* element). It then returns either the new iterator, or `false` to
indicate that there are no more elements.
If `false` is returned, Wren exits out of the loop and we're done. If anything
else is returned, that means that we have advanced to a new valid element. To
get that, Wren then calls `iteratorValue()` on the sequence and passes in the
iterator value that it just got from calling `iterate()`. The sequence uses
that to look up and return the appropriate element.
The built-in [List](lists.html) and [Range](values.html#ranges) types implement
`iterate()` and `iteratorValue()` to walk over their respective sequences. You
can implement the same methods in your classes to make your own types iterable.

View File

@ -0,0 +1,18 @@
^title Bool Class
^category core
Boolean values. There are two instances, `true` and `false`.
## Methods
### **!** operator
Returns the logical complement of the value.
:::wren
System.print(!true) // "false".
System.print(!false) // "true".
### toString
The string representation of the value, either `"true"` or `"false"`.

View File

@ -0,0 +1,28 @@
^title Class Class
^category core
## Methods
### **name**
The name of the class.
### **supertype**
The superclass of this class.
:::wren
class Crustacean {}
class Crab is Crustacean {}
System.print(Crab.supertype) // "Crustacean".
A class with no explicit superclass implicitly inherits Object:
:::wren
System.print(Crustacean.supertype) // "Object".
Object forms the root of the class hierarchy and has no supertype:
:::wren
System.print(Object.supertype) // "null".

View File

@ -0,0 +1,140 @@
^title Fiber Class
^category core
A lightweight coroutine. [Here](../fibers.html) is a gentle introduction.
### Fiber.**new**(function)
Creates a new fiber that executes `function` in a separate coroutine when the
fiber is run. Does not immediately start running the fiber.
:::wren
var fiber = Fiber.new {
System.print("I won't get printed")
}
## Static Methods
### Fiber.**current**
The currently executing fiber.
### Fiber.**suspend**()
Pauses the current fiber, and stops the interpreter. Control returns to the
host application.
To resume execution, the host application will need to invoke the interpreter
again. If there is still a reference to the suspended fiber, it can be resumed.
### Fiber.**yield**()
Pauses the current fiber and transfers control to the parent fiber. "Parent"
here means the last fiber that was started using `call` and not `run`.
:::wren
var fiber = Fiber.new {
System.print("Before yield")
Fiber.yield()
System.print("After yield")
}
fiber.call() // "Before yield"
System.print("After call") // "After call"
fiber.call() // "After yield"
When resumed, the parent fiber's `call()` method returns `null`.
If a yielded fiber is resumed by calling `call()` or `run()` with an argument,
`yield()` returns that value.
:::wren
var fiber = Fiber.new {
System.print(Fiber.yield()) // "value"
}
fiber.call() // Run until the first yield.
fiber.call("value") // Resume the fiber.
If it was resumed by calling `call()` or `run()` with no argument, it returns
`null`.
If there is no parent fiber to return to, this exits the interpreter. This can
be useful to pause execution until the host application wants to resume it
later.
:::wren
Fiber.yield()
System.print("this does not get reached")
### Fiber.**yield**(value)
Similar to `Fiber.yield` but provides a value to return to the parent fiber's
`call`.
:::wren
var fiber = Fiber.new {
Fiber.yield("value")
}
System.print(fiber.call()) // "value"
## Methods
### **call**()
Starts or resumes the fiber if it is in a paused state.
:::wren
var fiber = Fiber.new {
System.print("Fiber called")
Fiber.yield()
System.print("Fiber called again")
}
fiber.call() // Start it.
fiber.call() // Resume after the yield() call.
When the called fiber yields, control is transferred back to the fiber that
called it.
If the called fiber is resuming from a yield, the `yield()` method returns
`null` in the called fiber.
:::wren
var fiber = Fiber.new {
System.print(Fiber.yield())
}
fiber.call()
fiber.call() // Prints "null".
### **call**(value)
Invokes the fiber or resumes the fiber if it is in a paused state and sets
`value` as the returned value of the fiber's call to `yield`.
:::wren
var fiber = Fiber.new {
System.print(Fiber.yield())
}
fiber.call()
fiber.call("value") // Prints "value".
### **isDone**
Whether the fiber's main function has completed and the fiber can no longer be
run. This returns `false` if the fiber is currently running or has yielded.
### **transfer**()
**TODO**
### **transfer**(value)
**TODO**
### **transferError**(error)
**TODO**

44
doc/site/core/fn.markdown Normal file
View File

@ -0,0 +1,44 @@
^title Fn Class
^category core
A first class function&mdash;an object that wraps an executable chunk of code.
[Here](../functions.html) is a friendly introduction.
### Fn.**new**(function)
Creates a new function from... `function`. Of course, `function` is already a
function, so this really just returns the argument. It exists mainly to let you
create a "bare" function when you don't want to immediately pass it as a [block
argument](../functions.html#block-arguments) to some other method.
:::wren
var fn = Fn.new {
System.print("The body")
}
It is a runtime error if `function` is not a function.
## Methods
### **arity**
The number of arguments the function requires.
:::wren
System.print(Fn.new {}.arity) // 0.
System.print(Fn.new {|a, b, c| a }.arity) // 3.
### **call**(args...)
Invokes the function with the given arguments.
:::wren
var fn = Fn.new { |arg|
System.print(arg)
}
fn.call("Hello world") // Prints "Hello world".
It is a runtime error if the number of arguments given is less than the arity
of the function. If more arguments are given than the function's arity they are
ignored.

View File

@ -0,0 +1,25 @@
^title Core Library
^category core
Because Wren is designed for [embedding in applications][embedding], its core
library is minimal and is focused on working with objects within Wren. For
stuff like file IO, graphics, etc., it is up to the host application to provide
interfaces for this.
All Wren source files automatically have access to the following classes:
* [Bool](bool.html)
* [Class](class.html)
* [Fiber](fiber.html)
* [Fn](fn.html)
* [List](list.html)
* [Map](map.html)
* [Null](null.html)
* [Num](num.html)
* [Object](object.html)
* [Range](range.html)
* [Sequence](sequence.html)
* [String](string.html)
* [System](system.html)
[embedding]: ../embedding-api.html

View File

@ -0,0 +1,96 @@
^title List Class
^category core
Extends [Sequence](sequence.html).
An indexable contiguous collection of elements. More details [here](../lists.html).
## Methods
### **add**(item)
Appends `item` to the end of the list.
### **clear**()
Removes all elements from the list.
### **count**
The number of elements in the list.
### **insert**(index, item)
Inserts the `item` at `index` in the list.
:::wren
var list = ["a", "b", "c", "d"]
list.insert(1, "e")
System.print(list) // "[a, e, b, c, d]".
The `index` may be one past the last index in the list to append an element.
:::wren
var list = ["a", "b", "c"]
list.insert(3, "d")
System.print(list) // "[a, b, c, d]".
If `index` is negative, it counts backwards from the end of the list. It bases this on the length of the list *after* inserted the element, so that `-1` will append the element, not insert it before the last element.
:::wren
var list = ["a", "b"]
list.insert(-1, "d")
list.insert(-2, "c")
System.print(list) // "[a, b, c, d]".
Returns the inserted item.
:::wren
System.print(["a", "c"].insert(1, "b")) // "b".
It is a runtime error if the index is not an integer or is out of bounds.
### **iterate**(iterator), **iteratorValue**(iterator)
Implements the [iterator protocol](../control-flow.html#the-iterator-protocol)
for iterating over the elements in the list.
### **removeAt**(index)
Removes the element at `index`. If `index` is negative, it counts backwards
from the end of the list where `-1` is the last element. All trailing elements
are shifted up to fill in where the removed element was.
:::wren
var list = ["a", "b", "c", "d"]
list.removeAt(1)
System.print(list) // "[a, c, d]".
Returns the removed item.
System.print(["a", "b", "c"].removeAt(1)) // "b".
It is a runtime error if the index is not an integer or is out of bounds.
### **[**index**]** operator
Gets the element at `index`. If `index` is negative, it counts backwards from
the end of the list where `-1` is the last element.
:::wren
var list = ["a", "b", "c"]
System.print(list[1]) // "b".
It is a runtime error if the index is not an integer or is out of bounds.
### **[**index**]=**(item) operator
Replaces the element at `index` with `item`. If `index` is negative, it counts
backwards from the end of the list where `-1` is the last element.
:::wren
var list = ["a", "b", "c"]
list[1] = "new"
System.print(list) // "[a, new, c]".
It is a runtime error if the index is not an integer or is out of bounds.

View File

@ -0,0 +1,63 @@
^title Map Class
^category core
An associative collection that maps keys to values. More details [here](../maps.html).
## Methods
### **clear**()
Removes all entries from the map.
### **containsKey**(key)
Returns `true` if the map contains `key` or `false` otherwise.
### **count**
The number of entries in the map.
### **keys**
A [Sequence](sequence.html) that can be used to iterate over the keys in the
map. Note that iteration order is undefined. All keys will be iterated over,
but may be in any order, and may even change between invocations of Wren.
### **iterate**(iterator), **iteratorValue**(iterator)
Implements the [iterator protocol](../control-flow.html#the-iterator-protocol)
for iterating over the elements in the list.
### **remove**(key)
Removes [key] and the value associated with it from the map. Returns the value.
If the key was not present, returns `null`.
### **values**
A [Sequence](sequence.html) that can be used to iterate over the values in the
map. Note that iteration order is undefined. All values will be iterated over,
but may be in any order, and may even change between invocations of Wren.
If multiple keys are associated with the same value, the value will appear
multiple times in the sequence.
### **[**key**]** operator
Gets the value associated with `key` in the map. If `key` is not present in the
map, returns `null`.
:::wren
var map = {"george": "harrison", "ringo": "starr"}
System.print(map["ringo"]) // "starr".
System.print(map["pete"]) // "null".
### **[**key**]=**(value) operator
Associates `value` with `key` in the map. If `key` was already in the map, this
replaces the previous association.
It is a runtime error if the key is not a [Bool](bool.html),
[Class](class.html), [Null](null.html), [Num](num.html), [Range](range.html),
or [String](string.html).

View File

@ -0,0 +1,11 @@
^title Null Class
^category core
## Methods
### **!** operator
Returns `true`, since `null` is considered [false](../control-flow.html#truth).
:::wren
System.print(!null) // "true".

164
doc/site/core/num.markdown Normal file
View File

@ -0,0 +1,164 @@
^title Num Class
^category core
## Static Methods
### Num.**fromString**(value)
Attempts to parse `value` as a decimal literal and return it as an instance of
`Num`. If the number cannot be parsed `null` will be returned.
It is a runtime error if `value` is not a string.
### Num.**pi**
The value of π.
## Methods
### **abs**
The absolute value of the number.
:::wren
-123.abs // 123
### **acos**
The arc cosine of the number.
### **asin**
The arc sine of the number.
### **atan**
The arc tangent of the number.
### **atan**(x)
The arc tangent of the number when divided by `x`, using the signs of the two
numbers to determine the quadrant of the result.
### **ceil**
Rounds the number up to the nearest integer.
:::wren
1.5.ceil // 2
(-3.2).ceil // -3
### **cos**
The cosine of the number.
### **floor**
Rounds the number down to the nearest integer.
:::wren
1.5.floor // 1
(-3.2).floor // -4
### **isInfinity**
Whether the number is positive or negative infinity or not.
:::wren
99999.isInfinity // false
(1/0).isInfinity // true
### **isInteger**
Whether the number is an integer or has some fractional component.
:::wren
2.isInteger // true
2.3.isInteger // false
### **isNan**
Whether the number is [not a number](http://en.wikipedia.org/wiki/NaN). This is
`false` for normal number values and infinities, and `true` for the result of
`0/0`, the square root of a negative number, etc.
### **sin**
The sine of the number.
### **sqrt**
The square root of the number. Returns `nan` if the number is negative.
### **tan**
The tangent of the number.
### **-** operator
Negates the number.
:::wren
var a = 123
-a // -123
### **-**(other), **+**(other), **/**(other), **\***(other) operators
The usual arithmetic operators you know and love. All of them do 64-bit
floating point arithmetic. It is a runtime error if the right-hand operand is
not a number. Wren doesn't roll with implicit conversions.
### **%**(denominator) operator
The floating-point remainder of this number divided by `denominator`.
It is a runtime error if `denominator` is not a number.
### **&lt;**(other), **&gt;**(other), **&lt;=**(other), **&gt;=**(other) operators
Compares this and `other`, returning `true` or `false` based on how the numbers
are ordered. It is a runtime error if `other` is not a number.
### **~** operator
Performs *bitwise* negation on the number. The number is first converted to a
32-bit unsigned value, which will truncate any floating point value. The bits
of the result of that are then negated, yielding the result.
### **&**(other) operator
Performs bitwise and on the number. Both numbers are first converted to 32-bit
unsigned values. The result is then a 32-bit unsigned number where each bit is
`true` only where the corresponding bits of both inputs were `true`.
It is a runtime error if `other` is not a number.
### **|**(other) operator
Performs bitwise or on the number. Both numbers are first converted to 32-bit
unsigned values. The result is then a 32-bit unsigned number where each bit is
`true` only where the corresponding bits of both inputs were `true`.
It is a runtime error if `other` is not a number.
### **..**(other) operator
Creates a [Range](range.html) representing a consecutive range of numbers
from the beginning number to the ending number.
:::wren
var range = 1.2..3.4
System.print(range.min) // 1.2
System.print(range.max) // 3.4
System.print(range.isInclusive) // true
### **...**(other) operator
Creates a [Range](range.html) representing a consecutive range of numbers
from the beginning number to the ending number not including the ending number.
:::wren
var range = 1.2...3.4
System.print(range.min) // 1.2
System.print(range.max) // 3.4
System.print(range.isInclusive) // false

View File

@ -0,0 +1,37 @@
^title Object Class
^category core
## Static Methods
## **same**(obj1, obj2)
Returns `true` if *obj1* and *obj2* are the same. For [value
types](../values.html), this returns `true` if the objects have equivalent
state. In other words, numbers, strings, booleans, and ranges compare by value.
For all other objects, this returns `true` only if *obj1* and *obj2* refer to
the exact same object in memory.
This is similar to the built in `==` operator in Object except that this cannot
be overriden. It allows you to reliably access the built-in equality semantics
even on user-defined classes.
## Methods
### **!** operator
Returns `false`, since most objects are considered [true](control-flow.html#truth).
### **==**(other) and **!=**(other) operators
Compares two objects using built-in equality. This compares [value
types](../values.html) by value, and all other objects are compared by
identity&mdash;two objects are equal only if they are the exact same object.
### **toString**
A default string representation of the object.
### **type**
The [Class](#class-class) of the object.

View File

@ -0,0 +1,58 @@
^title Range Class
^category core
A range defines a bounded range of values from a starting point to a possibly
exclusive endpoint. [Here](../range.html) is a friendly introduction.
Extends [Sequence](sequence.html).
## Methods
### **from**
The starting point of the range. A range may be backwards, so this can be
greater than [to].
:::wren
(3..5).min // 3.
(4..2).min // 4.
### **to**
The endpoint of the range. If the range is inclusive, this value is included,
otherwise it is not.
:::wren
(3..5).min // 5.
(4..2).min // 2.
### **min**
The minimum bound of the range. Returns either `from`, or `to`, whichever is
lower.
:::wren
(3..5).min // 3.
(4..2).min // 2.
### **max**
The maximum bound of the range. Returns either `from`, or `to`, whichever is
greater.
:::wren
(3..5).min // 5.
(4..2).min // 4.
### **isInclusive**
Whether or not the range includes `to`. (`from` is always included.)
:::wren
(3..5).isInclusive // true.
(3...5).isInclusive // false.
### **iterate**(iterator), **iteratorValue**(iterator)
Iterates over the range. Starts at `from` and increments by one towards `to`
until the endpoint is reached.

View File

@ -0,0 +1,163 @@
^title Sequence Class
^category core
An abstract base class for any iterable object. Any class that implements the
core [iterator protocol][] can extend this to get a number of helpful methods.
[iterator protocol]: ../control-flow.html#the-iterator-protocol
## Methods
### **all**(predicate)
Tests whether all the elements in the sequence pass the `predicate`.
Iterates over the sequence, passing each element to the function `predicate`.
If it returns something [false](../control-flow.html#truth), stops iterating
and returns the value. Otherwise, returns `true`.
:::wren
[1, 2, 3].all {|n| n > 2} // False.
[1, 2, 3].all {|n| n < 4} // True.
### **any**(predicate)
Tests whether any element in the sequence passes the `predicate`.
Iterates over the sequence, passing each element to the function `predicate`.
If it returns something [true](../control-flow.html#truth), stops iterating and
returns that value. Otherwise, returns `false`.
:::wren
[1, 2, 3].any {|n| n < 1} // False.
[1, 2, 3].any {|n| n > 2} // True.
### **contains**(element)
Returns whether the sequence contains any element equal to the given element.
### **count**
The number of elements in the sequence.
Unless a more efficient override is available, this will iterate over the
sequence in order to determine how many elements it contains.
### **count**(predicate)
Returns the number of elements in the sequence that pass the `predicate`.
Iterates over the sequence, passing each element to the function `predicate`
and counting the number of times the returned value evaluates to `true`.
:::wren
[1, 2, 3].count {|n| n > 2} // 1.
[1, 2, 3].count {|n| n < 4} // 3.
### **each**(function)
Iterates over the sequence, passing each element to the given `function`.
:::wren
["one", "two", "three"].each {|word| System.print(word) }
### **isEmpty**
Returns whether the sequence contains any elements.
This can be more efficient that `count == 0` because this does not iterate over
the entire sequence.
### **join**(separator)
Converts every element in the sequence to a string and then joins the results
together into a single string, each separated by `separator`.
It is a runtime error if `separator` is not a string.
### **join**()
Converts every element in the sequence to a string and then joins the results
together into a single string.
### **map**(transformation)
Creates a new sequence that applies the `transformation` to each element in the
original sequence while it is iterated.
:::wren
var doubles = [1, 2, 3].map {|n| n * 2 }
for (n in doubles) {
System.print(n) // "2", "4", "6".
}
The returned sequence is *lazy*. It only applies the mapping when you iterate
over the sequence, and it does so by holding a reference to the original
sequence.
This means you can use `map(_)` for things like infinite sequences or sequences
that have side effects when you iterate over them. But it also means that
changes to the original sequence will be reflected in the mapped sequence.
To force eager evaluation, just call `.toList` on the result.
:::wren
var numbers = [1, 2, 3]
var doubles = numbers.map {|n| n * 2 }.toList
numbers.add(4)
System.print(doubles) // [2, 4, 6].
### **reduce**(function)
Reduces the sequence down to a single value. `function` is a function that
takes two arguments, the accumulator and sequence item and returns the new
accumulator value. The accumulator is initialized from the first item in the
sequence. Then, the function is invoked on each remaining item in the sequence,
iteratively updating the accumulator.
It is a runtime error to call this on an empty sequence.
### **reduce**(seed, function)
Similar to above, but uses `seed` for the initial value of the accumulator. If
the sequence is empty, returns `seed`.
### **toList**
Creates a [list](list.html) containing all the elements in the sequence.
:::wren
(1..3).toList // [1, 2, 3].
If the sequence is already a list, this creates a copy of it.
### **where**(predicate)
Creates a new sequence containing only the elements from the original sequence
that pass the `predicate`.
During iteration, each element in the original sequence is passed to the
function `predicate`. If it returns `false`, the element is skipped.
:::wren
var odds = (1..10).where {|n| n % 2 == 1 }
for (n in odds) {
System.print(n) // "1", "3", "5", "7", "9".
}
The returned sequence is *lazy*. It only applies the filtering when you iterate
over the sequence, and it does so by holding a reference to the original
sequence.
This means you can use `where(_)` for things like infinite sequences or
sequences that have side effects when you iterate over them. But it also means
that changes to the original sequence will be reflected in the filtered
sequence.
To force eager evaluation, just call `.toList` on the result.
:::wren
var numbers = [1, 2, 3, 4, 5, 6]
var odds = numbers.where {|n| n % 2 == 1 }.toList
numbers.add(7)
System.print(odds) // [1, 3, 5].

View File

@ -0,0 +1,177 @@
^title String Class
^category core
A string is an immutable array of bytes. Strings usually store text, in which
case the bytes are the UTF-8 encoding of the text's code points. But you can put
any kind of byte values in there you want, including null bytes or invalid
UTF-8.
There are a few ways to think of a string:
* As a searchable chunk of text composed of a sequence of textual code points.
* As an iterable sequence of code point numbers.
* As a flat array of directly indexable bytes.
All of those are useful for some problems, so the string API supports all three.
The first one is the most common, so that's what methods directly on the string
class cater to.
In UTF-8, a single Unicode code point&mdash;very roughly a single
"character"&mdash;may encode to one or more bytes. This means you can't
efficiently index by code point. There's no way to jump directly to, say, the
fifth code point in a string without walking the string from the beginning and
counting them as you go.
Because counting code points is relatively slow, the indexes passed to string
methods are *byte* offsets, not *code point* offsets. When you do:
:::wren
someString[3]
That means "get the code point starting at *byte* three", not "get the third
code point in the string". This sounds scary, but keep in mind that the methods
on strings *return* byte indexes too. So, for example, this does what you want:
:::wren
var metalBand = "Fäcëhämmër"
var hPosition = metalBand.indexOf("h")
System.print(metalBand[hPosition]) // "h"
If you want to work with a string as a sequence numeric code points, call the
`codePoints` getter. It returns a [Sequence](sequence.html) that decodes UTF-8
and iterates over the code points, returning each as a number.
If you want to get at the raw bytes, call `bytes`. This returns a Sequence that
ignores any UTF-8 encoding and works directly at the byte level.
## Static Methods
### String.**fromCodePoint**(codePoint)
Creates a new string containing the UTF-8 encoding of `codePoint`.
:::wren
String.fromCodePoint(8225) // "‡"
It is a runtime error if `codePoint` is not an integer between `0` and
`0x10ffff`, inclusive.
## Methods
### **bytes**
Gets a [`Sequence`](sequence.html) that can be used to access the raw bytes of
the string and ignore any UTF-8 encoding. In addition to the normal sequence
methods, the returned object also has a subscript operator that can be used to
directly index bytes.
:::wren
System.print("hello".bytes[1]) // 101, for "e".
The `count` method on the returned sequence returns the number of bytes in the
string. Unlike `count` on the string itself, it does not have to iterate over
the string, and runs in constant time instead.
### **codePoints**
Gets a [`Sequence`](sequence.html) that can be used to access the UTF-8 decode
code points of the string *as numbers*. Iteration and subscripting work similar
to the string itself. The difference is that instead of returning
single-character strings, this returns the numeric code point values.
:::wren
var string = "(ᵔᴥᵔ)"
System.print(string.codePoints[0]) // 40, for "(".
System.print(string.codePoints[4]) // 7461, for "ᴥ".
If the byte at `index` does not begin a valid UTF-8 sequence, or the end of the
string is reached before the sequence is complete, returns `-1`.
:::wren
var string = "(ᵔᴥᵔ)"
System.print(string.codePoints[2]) // -1, in the middle of "ᵔ".
### **contains**(other)
Checks if `other` is a substring of the string.
It is a runtime error if `other` is not a string.
### **count**
Returns the number of code points in the string. Since UTF-8 is a
variable-length encoding, this requires iterating over the entire string, which
is relatively slow.
If the string contains bytes that are invalid UTF-8, each byte adds one to the
count as well.
### **endsWith**(suffix)
Checks if the string ends with `suffix`.
It is a runtime error if `suffix` is not a string.
### **indexOf**(search)
Returns the index of the first byte matching `search` in the string or `-1` if
`search` was not found.
It is a runtime error if `search` is not a string.
### **iterate**(iterator), **iteratorValue**(iterator)
Implements the [iterator protocol](../control-flow.html#the-iterator-protocol)
for iterating over the *code points* in the string:
:::wren
var codePoints = []
for (c in "(ᵔᴥᵔ)") {
codePoints.add(c)
}
System.print(codePoints) // ["(", "ᵔ", "ᴥ", "ᵔ", ")"].
If the string contains any bytes that are not valid UTF-8, this iterates over
those too, one byte at a time.
### **startsWith**(prefix)
Checks if the string starts with `prefix`.
It is a runtime error if `prefix` is not a string.
### **+**(other) operator
Returns a new string that concatenates this string and `other`.
It is a runtime error if `other` is not a string.
### **==**(other) operator
Checks if the string is equal to `other`.
### **!=**(other) operator
Check if the string is not equal to `other`.
### **[**index**]** operator
Returns a string containing the code point starting at byte `index`.
:::wren
System.print("ʕ•ᴥ•ʔ"[5]) // "ᴥ".
Since `ʕ` is two bytes in UTF-8 and `•` is three, the fifth byte points to the
bear's nose.
If `index` points into the middle of a UTF-8 sequence or at otherwise invalid
UTF-8, this returns a one-byte string containing the byte at that index:
:::wren
System.print("I ♥ NY"[3]) // One-byte string whose value is 153.
It is a runtime error if `index` is greater than the number of bytes in the
string.

View File

@ -0,0 +1,43 @@
^title System Class
^category core
The System class is a grab-bag of functionality exposed by the VM, mostly for
use during development or debugging.
## Static Methods
### System.**print**()
Prints a single newline to the console.
### System.**print**(object)
Prints [object] to the console followed by a newline. If not already a string,
the object is converted to a string by calling `toString` on it.
:::wren
System.print("I like bananas") // Prints "I like bananas".
### System.**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.
:::wren
System.printAll([1, [2, 3], 4]) // Prints "1[2, 3]4".
### System.**write**(object)
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.
:::wren
System.write(4 + 5) // Prints "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.
### System.**clock**
Returns the number of seconds (including fractional seconds) since the program
was started. This is usually used for benchmarking.

View File

@ -0,0 +1,139 @@
^title Embedding API
^category reference
Wren is designed to be a scripting language, so the embedding API is as
important as any of its language features. There are two (well, three) ways to
get Wren into your application:
1. **Link to static or dynamic library.** When you [build Wren][build], it
generates both shared and static libraries in `lib` that you can link to.
2. **Include the source directly in your application.** If you want to include
the source directly in your program, you don't need to run any build steps.
Just add the source files in `src/vm` to your project. They should compile
cleanly as C99 or C++89 or anything later.
[build]: getting-started.html
In either case, you also want to add `src/include` to your include path so you
can get to the [public header for Wren][wren.h]:
[wren.h]: https://github.com/munificent/wren/blob/master/src/include/wren.h
:::c
#include "wren.h"
## Creating a Wren VM
Once you've integrated the code into your executable, you need to create a
virtual machine. To do that, you first fill in a `WrenConfiguration`:
:::c
WrenConfiguration config;
wrenInitConfiguration(&config);
This gives you a basic configuration that has reasonable defaults for
everything. If you don't need to tweak stuff, you can leave it at that. If you
do want to turn some knobs and dials, it exposes some fields you can set:
:::c
config.reallocateFn = ...;
The `reallocateFn` is a callback you can provide to control how Wren allocates
and frees memory. If you leave that to the default, it uses `malloc()` and
`free()`.
:::c
config.loadModuleFn = ...;
config.bindForeignMethodFn = ...;
config.bindForeignClassFn = ...;
These three callbacks are how Wren talks back to your program. We'll cover
them in detail later.
:::c
config.initialHeapSize = ...;
config.minHeapSize = ...;
config.heapGrowthPercent = ...;
These let you tune how the garbage collector runs. You can tweak these if you
want, but the defaults are usually fine.
With this ready, you can create the VM:
:::c
WrenVM* vm = wrenNewVM(&config);
This allocates memory for a new VM using the same `reallocateFn` you provided.
The Wren C implementation has no global state, so every single bit of data Wren
uses is bundled up inside a `WrenVM`. You can have multiple Wren VMs running
independently from each other without any problems.
`wrenNewVM()` stores its own copy of the configuration, so after calling it, you
can discard the `WrenConfiguration` struct you filled in. Now you have a live
VM, waiting to run some code!
## Executing Wren code
You can tell the VM to execute a string of Wren source code like so:
:::c
WrenInterpretResult result = wrenInterpret(vm,
"<where>",
"System.print(\"Hi!\")");
The first string parameter is a "source path". It's just an arbitrary string
that describes where the source code is from. It's what shows up in stack traces
if a runtime error occurs in the code. It can be whatever you want as long as
it's not `NULL`.
The other string is the chunk of code to execute&mdash;a series of one or more
statements separated by newlines. Wren runs this code in a special "main"
module. Each time you call this, the code is run in the same module. This way,
top-level names defined in one call can be accessed in later ones.
When you call `wrenInterpret()`, Wren first compiles your source to bytecode. If
an error occurs here, it returns immediately with `WREN_RESULT_COMPILE_ERROR`.
Otherwise, Wren spins up a new [fiber][] and executes the code in that. Your
code can in turn spawn whatever other fibers it wants. It keeps running fibers
until they all complete.
[fiber]: fibers.html
If a [runtime error][] occurs (and another fiber doesn't catch it), it will
abort fibers all the way back to the main one and then return
`WREN_RESULT_RUNTIME_ERROR`. Otherwise, when the last fiber successfully
returns, it returns `WREN_RESULT_SUCCESS`.
[runtime error]: error-handling.html
## Calling a C function from Wren
**TODO**
## Calling a Wren method from C
**TODO**
## Storing a reference to a Wren object in C
**TODO**
## Storing C data in a Wren object
**TODO**
## Shutting down a VM
Once the party is over and you're ready to end your relationship with a VM, you
need to free any memory it allocated. You do that like so:
:::c
wrenFreeVM(vm);
After calling that, you obviously cannot use the `WrenVM*` you passed to it
again. It's dead.
Note that Wren will yell at you if you still have any live `WrenValue` objects
when you call this. This makes sure you haven't lost track of any of them (which
leaks memory) and you don't try to use any of them after the VM has been freed.

View File

@ -0,0 +1,165 @@
^title Error Handling
^category language
Errors come in a few fun flavors.
## Syntax errors
The first errors you're likely to run into are syntax errors. These include
simple bugs where your code doesn't follow the language's grammar, like:
:::wren
1 + * 2
Wren will detect these errors as soon as it tries to read your code. When it
hits one, you'll get a friendly error message, like:
:::text
[script.wren line 1] Error on '*': Unexpected token for expression.
Some slightly more "semantic" errors fall into this bucket too. Things like
using a variable that hasn't been defined, or declaring two variables with the
same name in the same scope. So if you do:
:::wren
var a = "once"
var a = "twice"
Wren tells you:
:::text
[script.wren line 2] Error on 'a': Top-level variable is already defined.
Note that it does this before it executes *any* code. Unlike some other
scripting languages, Wren tries to help you find your errors as soon as
possible when it can.
If it starts running your code, you can be sure you don't have any errors
related to syntax or variable scope.
## Runtime errors
Alas, just fixing all of the "compile-time" errors doesn't mean your code does
what you want. Your program may still have errors that can't be detected
statically. Since they can't be found until your code is run, they're called
"runtime" errors.
Most runtime errors come from the VM itself. They arise from code trying to
perform an operation that the VM can't do. The most common error is a "method
not found" one. If you call a method on an object and its class (and all of its
superclasses) don't define that method, there's nothing Wren can do:
:::wren
class Foo {}
var foo = Foo.new()
foo.someRandomMethod
If you run this, Wren will print:
:::text
Foo does not implement method 'someRandomMethod'.
Then it stops executing code. Unlike some other languages, Wren doesn't keep
plugging away after a runtime error has occurred. A runtime error implies
there's a bug in your code and it wants to draw your attention to it. To help
you out, it prints a stack trace showing where in the code the error occurred,
and all of the method calls that led to it.
Another common runtime error is passing an argument of the wrong type to a
method. For example, lists are indexed using a number. If you try to pass some
other type, it's an error:
:::wren
var list = ["a", "b", "c"]
list["1"]
This exits with:
:::text
Subscript must be a number or a range.
[script.wren line 2] in (script)
These are the most two common kinds of runtime errors, but there are others.
Stuff like out of bounds errors on lists, calling a function with the wrong
number of arguments, etc.
## Handling runtime errors
Most of the time, runtime errors indicate a bug in your code and the best
solution is to fix the bug. However, sometimes it's useful to be able to handle
them at, uh, runtime.
To keep the language simpler, Wren does not have exception handling. Instead,
it takes advantage of [fibers](fibers.html) for handling errors. When a runtime
error occurs, the current fiber is aborted. Normally, Wren will also abort any
fibers that invoked that one, all the way to the main fiber, and then exit the
VM.
However, you can run a fiber using the `try` method. If a runtime error occurs
in the called fiber, the error is captured and the `try` method returns the
error message as a string.
For example, if you run this program:
:::wren
var fiber = Fiber.new {
123.badMethod
}
var error = fiber.try()
System.print("Caught error: " + error)
It prints:
:::text
Caught error: Num does not implement method 'badMethod'.
The called fiber can no longer be used, but any other fibers can proceed as
usual. When a fiber has been aborted because of a runtime error, you can also
get the error from the fiber object. Continuing the above example:
:::wren
System.print(fiber.error)
This also prints:
:::text
Num does not implement method 'badMethod'.
If you have a chain of fiber calls and a runtime error occurs, it will walk the
chain looking for a `try` call, so this can also be used to capture runtime
errors generated in fibers that are invoked by the one you called `try` on.
## Creating runtime errors
Most runtime errors come from within the Wren VM, but you may want to be able
to cause your own runtime errors to occur. This can be done by calling the
`abort()` static method on `Fiber`:
:::wren
Fiber.abort("Something bad happened")
You must pass in an error message, and it must be a string.
## Failures
The last flavor of errors is the highest-level one. All of the above errors
indicate *bugs*&mdash;places where the code itself is incorrect. But some
errors indicate that the code simply couldn't accomplish its task for
unforeseeable reasons. We'll call these "failures".
Consider a program that reads in a string of input from the user and parses it
to a number. Many strings are not valid numbers, so this parsing can fail. The
only way the program could prevent that failure is by validating the string
before its parsed, but validating that a string is a number is pretty much the
same thing as parsing it.
For cases like this where failure can occur and the program *will* want to
handle it, fibers and `try()` are too coarse-grained to work with. Instead,
these operations will indicate failure by *returning* some sort of error
indication.
For example, a method for parsing a number could return a number on success and
`null` to indicate parsing failed. Since Wren is dynamically typed, it's easy
and natural for a method to return different types of values.

View File

@ -0,0 +1,379 @@
^title Expressions
^category language
Wren's syntax is based on C so if you're familiar with that (or any of the
plethora of other languages based on it) you should be right at home. Since
Wren is heavily object-oriented, you'll notice that most of the different
expression forms are just different ways of invoking methods.
## Literals
Literals produce objects of built-in types. The primitive [value](values.html)
types&mdash;numbers, strings and friends&mdash;have literal forms as do the
built in collections: [lists](lists.html) and [maps](maps.html).
[Functions](functions.html) do not have standalone a literal form. Instead,
they are created by passing a [block
argument](functions.html#block-arguments) to a method.
## Identifiers
Names in expressions come in a few flavors. A name that starts with an
underscore denotes a [field](classes.html#fields), a piece of data stored in an
instance of a [class](classes.html). All other names refer to
[variables](variables.html).
## Method calls
Wren is object-oriented, so most code consists of method calls. Most of them
look like so:
:::wren
System.print("hello")
items.add("another")
items.insert(1, "value")
You have a *receiver* expression followed by a `.`, then a name and an argument
list in parentheses. Arguments are separated by commas. Methods that do not
take any arguments can omit the `()`:
:::wren
text.length
These are special "getters" or "accessors" in other languages. In Wren, they're
just method calls. You can also define methods that take an empty argument list:
:::wren
list.clear()
An empty argument list is *not* the same as omitting the parentheses
completely. Wren lets you overload methods by their call signature. This mainly
means [*arity*](classes.html#signature)&mdash;number of parameters&mdash;but
also distinguishes between "empty parentheses" and "no parentheses at all".
You can have a class that defines both `foo` and `foo()` as separate methods.
Think of it like the parentheses and commas between arguments are part of the
method's *name*.
If the last (or only) argument to a method call is a
[function](functions.html), it may be passed as a [block
argument](functions.html#block-arguments):
:::wren
blondie.callMeAt(867, 5309) {
System.print("This is the body!")
}
Semantically, all method calls work like so:
1. Evaluate the receiver and arguments.
2. Look up the method on the receiver's class.
3. Invoke it, passing in the arguments.
## This
The special `this` keyword works sort of like a variable, but has special
behavior. It always refers to the instance whose method is currently being
executed. This lets you invoke methods on "yourself".
It's an error to refer to `this` outside of a method. However, it's perfectly
fine to use it inside a function contained in a method. When you do, `this`
still refers to the instance whose method is being called.
This is unlike Lua and JavaScript which can "forget" `this` when you create a
callback inside a method. Wren does what you want here and retains the
reference to the original object. (In technical terms, a function's closure
includes `this`.)
## Super
Sometimes you want to invoke a method on yourself, but only methods defined in
one of your [superclasses](classes.html#inheritance). You typically do this in
an overridden method when you want to access the original method being
overridden.
To do that, you can use the special `super` keyword as the receiver in a method
call:
:::wren
class Base {
method {
System.print("base method")
}
}
class Derived is Base {
method {
super.method // Prints "base method".
}
}
You can also use `super` without a method name inside a constructor to invoke a
base class constructor:
:::wren
class Base {
this new(arg) {
System.print("base constructor got " + arg)
}
}
class Derived is Base {
this new() {
super("value") // Prints "base constructor got value".
}
}
**TODO: constructors**
## Operators
Wren has most of the same operators you know and love with the same precedence
and associativity. Wren has three prefix operators:
:::wren
! ~ -
They are just method calls on their operand without any other arguments. An
expression like `!possible` means "call the `!` method on `possible`".
We have a few other operators to play with. The remaining ones are
infix&mdash;they have operators on either side. They are:
:::wren
== != < > <= >= .. ... | & + - * / %
Like prefix operators, they are all funny ways of writing method calls. The
left operand is the receiver, and the right operand gets passed to it. So
`a + b` is semantically interpreted as "invoke the `+` method on `a`, passing
it `b`".
Most of these are probably familiar already. The `..` and `...` operators are
"range" operators. The number type implements those to create a
[range](values.html#ranges) object, but they are just regular operators.
Since operators are just method calls, this means Wren supports "operator
overloading" (though "operator over-*riding*" is more accurate). This can be
really useful when the operator is natural for what a class represents, but can
lead to mind-crushingly unreadable code when used recklessly. There's a reason
punctuation represents profanity in comic strips.
## Assignment
The `=` operator is used to *assign* or store a value somewhere. The right-hand
side can be any expression. If the left-hand side is an
[identifier](#identifiers), then the value of the right operand is stored in
the referenced [variable](variables.html) or [field](classes.html#fields).
The left-hand side may also be a method call, like:
:::wren
point.x = 123
In this case, the entire expression is a single "setter" method call. The above
example invokes the `x=` setter on the `point` object, and passing in `123`.
Sort of like `point.x=(123)`.
Since these are just regular method calls, you can define whatever setters you
like in your classes. However, you cannot change the behavior of *simple*
assignment. If the left-hand side is a variable name or field, an assignment
expression will always just store the value there.
## Subscript operators
Most languages use square brackets (`[]`) for working with collection-like
objects. For example:
:::wren
list[0] // Gets the first item in a list.
map["key"] // Gets the value associated with "key".
You know the refrain by now. In Wren, these are just method calls that a class
may define. Subscript operators may take multiple arguments, which is useful
for things like multi-dimensional arrays:
:::wren
matrix[3, 5]
Subscripts may also be used on the left-hand side of an assignment:
:::wren
list[0] = "item"
map["key"] = "value"
Again, these are just method calls. The last example is equivalent to invoking
the `[]=` method on `map`, passing in `"key"` and `"value"`.
## Logical operators
The `&&` and `||` operators are not like the other infix operators. They work
more like [control flow](control-flow.html) structures than operators because
they conditionally execute some code&mdash;they short-circuit. Depending on the
value of the left-hand side, the right-hand operand expression may or may not
be evaluated. Because of this, they cannot be overloaded and their behavior is
fixed.
A `&&` ("logical and") expression evaluates the left-hand argument. If it's
[false](control-flow.html#truth), it returns that value. Otherwise it evaluates
and returns the right-hand argument.
:::wren
System.print(false && 1) // false
System.print(1 && 2) // 2
An `||` ("logical or") expression is reversed. If the left-hand argument is
[true](control-flow.html#truth), it's returned, otherwise the right-hand
argument is evaluated and returned:
:::wren
System.print(false || 1) // 1
System.print(1 || 2) // 1
## The conditional operator `?:`
Also known as the "ternary" operator since it takes three arguments, Wren has
the little "if statement in the form of an expression" you know and love from C
and its brethren.
:::wren
System.print(1 != 2 ? "math is sane" : "math is not sane!")
It takes a condition expression, followed by `?`, followed by a then
expression, a `:`, then an else expression. Just like `if`, it evaluates the
condition. If true, it evaluates (and returns) the then expression. Otherwise
it does the else expression.
## The `is` operator
Wren has one last expression form. You can use the `is` keyword like an infix
operator. It performs a type test. The left operand is an object and the right
operand is a class. It evaluates to `true` if the object is an instance of the
class (or one of its subclasses).
:::wren
123 is Num // true
"s" is Num // false
null is String // false
[] is List // true
[] is Sequence // true
## Precedence
When you mix these all together, you need to worry about
*precedence*&mdash;which operators bind more tightly than others&mdash;and
*associativity*&mdash;how a series of the same operator is ordered. Wren mostly
follows C, except that it fixes the bitwise operator mistake. The full
precedence table, from highest to lowest, is:
<table class="precedence">
<tbody>
<tr>
<th>Prec</th>
<th>Operator</th>
<th>Description</th>
<th>Assoc</th>
</tr>
<tr>
<td>1</td>
<td><code>()</code> <code>[]</code> <code>.</code></td>
<td>Grouping, Subscript, Method call</td>
<td>Left</td>
</tr>
<tr>
<td>2</td>
<td><code>-</code> <code>!</code> <code>~</code></td>
<td>Negate, Not, Complement</td>
<td>Right</td>
</tr>
<tr>
<td>3</td>
<td><code>*</code> <code>/</code> <code>%</code></td>
<td>Multiply, Divide, Modulo</td>
<td>Left</td>
</tr>
<tr>
<td>4</td>
<td><code>+</code> <code>-</code></td>
<td>Add, Subtract</td>
<td>Left</td>
</tr>
<tr>
<td>5</td>
<td><code>..</code> <code>...</code></td>
<td>Inclusive range, Exclusive range</td>
<td>Left</td>
</tr>
<tr>
<td>6</td>
<td><code>&lt;&lt;</code> <code>&gt;&gt;</code></td>
<td>Left shift, Right shift</td>
<td>Left</td>
</tr>
<tr>
<td>7</td>
<td><code>&lt;</code> <code>&lt;=</code> <code>&gt;</code> <code>&gt;=</code></td>
<td>Comparison</td>
<td>Left</td>
</tr>
<tr>
<td>8</td>
<td><code>==</code></td>
<td>Equals</td>
<td>Left</td>
</tr>
<tr>
<td>8</td>
<td><code>!=</code></td>
<td>Not equal</td>
<td>Left</td>
</tr>
<tr>
<td>9</td>
<td><code>&amp;</code></td>
<td>Bitwise and</td>
<td>Left</td>
</tr>
<tr>
<td>10</td>
<td><code>^</code></td>
<td>Bitwise xor</td>
<td>Left</td>
</tr>
<tr>
<td>11</td>
<td><code>|</code></td>
<td>Bitwise or</td>
<td>Left</td>
</tr>
<tr>
<td>12</td>
<td><code>is</code></td>
<td>Type test</td>
<td>Left</td>
</tr>
<tr>
<td>13</td>
<td><code>&amp;&amp;</code></td>
<td>Logical and</td>
<td>Left</td>
</tr>
<tr>
<td>14</td>
<td><code>||</code></td>
<td>Logical or</td>
<td>Left</td>
</tr>
<tr>
<td>15</td>
<td><code>?:</code></td>
<td>Conditional</td>
<td>Right</td>
</tr>
<tr>
<td>16</td>
<td><code>=</code></td>
<td>Assign</td>
<td>Right</td>
</tr>
</tbody>
</table>

169
doc/site/fibers.markdown Normal file
View File

@ -0,0 +1,169 @@
^title Fibers
^category types
Fibers are a key part of Wren. They form its execution model, its concurrency
story, and take the place of exceptions in [error
handling](error-handling.html).
They are a bit like threads except they are *cooperatively* scheduled. That
means Wren doesn't pause one fiber and switch to another until you tell it to.
You don't have to worry about context switches at random times and all of the
headaches those cause.
Fibers are managed entirely by Wren, so they don't use OS thread resources, or
require heavyweight context switches. They just need a bit of memory for their
stacks. A fiber will get garbage collected like any other object when not
referenced any more, so you can create them freely.
They are lightweight enough that you can, for example, have a separate fiber
for each entity in a game. Wren can handle thousands of them without any
trouble. For example, when you run Wren in interactive mode, it creates a new
fiber for every line of code you type in.
## Creating fibers
All Wren code runs within the context of a fiber. When you first start a Wren
script, a main fiber is created for you automatically. You can spawn new fibers
using the `Fiber` class's constructor:
:::wren
var fiber = Fiber.new {
System.print("This runs in a separate fiber.")
}
Creating a fiber does not immediately run it. It's just a first class bundle of
code sitting there waiting to be activated, a bit like a
[function](functions.html).
## Invoking fibers
Once you've created a fiber, you can invoke it (which suspends the current
fiber) by calling its `call()` method:
:::wren
fiber.call()
The called fiber will execute its code until it reaches the end of its body or
until it passes control to another fiber. If it reaches the end of its body,
it's considered *done*:
:::wren
var fiber = Fiber.new { System.print("Hi") }
fiber.isDone // false
fiber.call()
fiber.isDone // true
When it finishes, it automatically resumes the fiber that called it. It's a
runtime error to try to call a fiber that is already done.
## Yielding
The main difference between fibers and functions is that a fiber can be
suspended in the middle of its operation and then resumed later. Calling
another fiber is one way to suspend a fiber, but that's more or less the same
as one function calling another.
Things get interesting when a fiber *yields*. A yielded fiber passes control
*back* to the fiber that ran it, but *remembers where it is*. The next time the
fiber is called, it picks up right where it left off and keeps going.
You can make a fiber yield by calling the static `yield()` method on `Fiber`:
:::wren
var fiber = Fiber.new {
System.print("fiber 1")
Fiber.yield()
System.print("fiber 2")
}
System.print("main 1")
fiber.call()
System.print("main 2")
fiber.call()
System.print("main 3")
This program prints:
:::text
main 1
fiber 1
main 2
fiber 2
main 3
Note that even though this program has *concurrency*, it's still
*deterministic*. You can reason precisely about what it's doing and aren't at
the mercy of a thread scheduler playing Russian roulette with your code.
## Passing values
Calling and yielding fibers is used for passing control, but it can also pass
*data*. When you call a fiber, you can optionally pass a value to it. If the
fiber has yielded and is waiting to resume, the value becomes the return value
of the `yield()` call:
:::wren
var fiber = Fiber.new {
var result = Fiber.yield()
System.print(result)
}
fiber.call("discarded")
fiber.call("sent")
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
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
invoke the fiber:
:::wren
var fiber = Fiber.new {
Fiber.yield("sent")
}
System.print(fiber.call())
This also prints "sent".
## Full coroutines
What we've seen so far is very similar to what you can do with languages like
Python and C# that have *generators*. Those let you define a function call that
you can suspend and resume. When using the function, it appears like a sequence
you can iterate over.
Wren's fibers can do that, but they can do much more. Like Lua, they are full
*coroutines*&mdash;they can suspend from anywhere in the callstack. For
example:
:::wren
var fiber = Fiber.new {
(1..10).map {|i|
Fiber.yield(i)
}
}
Here, we're calling `yield()` from within a [function](functions.html) being
passed to the `map()` method. This works fine in Wren because that inner
`yield()` call will suspend the call to `map()` and the function passed to it
as a callback.
## Transferring control
Fibers have one more trick up their sleeves. When you execute a fiber using
`call()`, the fiber tracks which fiber it will return to when it yields. This
lets you build up a chain of fiber calls that will eventually unwind back to
the main fiber when all of the called ones yield or finish.
This is almost always what you want. But if you're doing something really low
level, like writing your own scheduler to manage a pool of fibers, you may not
want to treat them explicitly like a stack.
For rare cases like that, fibers also have a `transfer()` method. This switches
execution immediately to the transferred fiber. The previous one is suspended,
leaving it in whatever state it was in. You can resume the previous fiber by
transferring back to it, or even calling it. If you don't, execution stops when
the last transferred fiber returns.

162
doc/site/functions.markdown Normal file
View File

@ -0,0 +1,162 @@
^title Functions
^category types
No self-respecting language today can get by without functions&mdash;first
class little bundles of code. Since Wren is object-oriented, most of your code
will live in methods on classes, but free-floating functions are still
eminently handy.
Functions are objects like everything else in Wren, instances of the `Fn`
class.
## Block arguments
Most of the time you create a function just to pass it to some method. For
example, if you want to filter a [list](lists.html) by some criteria, you'll
call its `where` method, passing in a function that defines the predicate
you're filtering on.
Since that's the most common usage pattern, Wren's syntax optimizes for that.
Taking a page from Ruby, a function is created by passing a *block argument* to
a method. At its simplest, it looks like this:
:::wren
blondie.callMe {
System.print("This is the body!")
}
Here we're invoking the `callMe` method on `blondie`. We're passing one
argument, a function whose body is the following
[block](syntax.html#blocks)&mdash;everything between that pair of curly braces.
Methods that take a block argument receive it as a normal parameter. `callMe`
could be defined like so:
:::wren
class Blondie {
callMe(fn) {
// Call it...
}
}
A method can take other arguments in addition to the block. They appear before
the block just like a regular argument list. For example:
:::wren
blondie.callMeAt(867, 5309) {
System.print("This is the body!")
}
Of course, you don't *have* to use a block argument to pass a function to a
method. If you already have a function object, you can pass it like a regular
argument:
:::wren
var someFn = // Get a function...
blondie.callMe(someFn)
Block arguments are purely sugar for creating a function and passing it in one
little blob of syntax. There are some times when you want to create a function
but *don't* need to pass it to a method. For that, you can call the `Fn`
class's constructor:
:::wren
var someFn = Fn.new {
System.print("Hi!")
}
As you can see it takes a block argument too! All the constructor does it
return that, so this exists purely as a convenience method for you.
## Calling functions
Once you have a function, how do you invoke it? Like everything in Wren, you do
so by calling a method on it:
:::wren
class Blondie {
callMe(fn) {
fn.call()
}
}
Functions expose a `call()` method that executes the body of the function. This
method is dynamically-dispatched like any other, so you can define your own
"function-like" classes and pass them to methods that expect "real" functions.
:::wren
class FakeFn {
call() {
System.print("I'm feeling functional!")
}
}
blondie.callMe(FakeFn.new())
## Function parameters
Of course, functions aren't very useful if you can't pass values to them. The
functions that we've seen so far take no arguments. To change that, you can
provide a parameter list surrounded by `|` immediately after the opening brace
of the body, like so:
:::wren
blondie.callMe {|first, last|
System.print("Hi, " + first + " " + last + "!")
}
Here we're passing a function to `greet` that takes two parameters, `first` and
`last`. They are passed to the function when it's called:
:::wren
class Blondie {
callMe(fn) {
fn.call("Debbie", "Harry")
}
}
It's an error to call a function with fewer arguments than its parameter list
expects. If you pass too *many* arguments, the extras are ignored.
## Returning values
The body of a function is a [block](syntax.html#blocks). If it is a single
expression&mdash;more precisely if there is no newline after the `{` or
parameter list&mdash;then the function implicitly returns the value of the
expression.
Otherwise, the body returns `null` by default. You can explicitly return a
value using a `return` statement. In other words, these two functions do the
same thing:
:::wren
Fn.new { "return value" }
Fn.new {
return "return value"
}
## Closures
As you expect, functions are closures&mdash;they can access variables defined
outside of their scope. They will hold onto closed-over variables even after
leaving the scope where the function is defined:
:::wren
class Counter {
static create {
var i = 0
return Fn.new { i = i + 1 }
}
}
Here, the `create` method returns the function created on its second line. That
function references a variable `i` declared outside of the function. Even after
the function is returned from `create`, it is still able to read and assign
to`i`:
:::wren
var counter = Counter.create
System.print(counter.call()) // Prints "1".
System.print(counter.call()) // Prints "2".
System.print(counter.call()) // Prints "3".

View File

@ -0,0 +1,109 @@
^title Getting Started
Getting Wren running on your machine is straightforward. Tiny C programs with
few dependencies are nice that way. "Wren" encompasses two separate artifacts:
* **The virtual machine.** This is the core chunk of C that executes Wren
source code. It is just a library, not a standalone application. It's
designed to be [embedded][] in a larger host application. It has no
dependencies beyond the C standard library. You can is use as a static
library, shared library, or simply compile the source into your app.
* **The command line executable.** Wren also ships with a CLI wrapper around
the VM. This gives you a way to run Wren code from the command-line, and
also includes modules for talking to the operating system&mdash;file IO,
networking, stuff like that. It depends on [libuv][] for that
functionality.
[embedded]: embedding-api.html
[libuv]: http://libuv.org/
If you're on a Unix or Mac and you can rock a command line, it's just:
:::sh
$ git clone https://github.com/munificent/wren.git
$ cd wren
$ make
$ ./wren
This builds both the VM and the CLI. It downloads libuv automatically for you.
The release build of the CLI goes right into the repo's top level directory.
Binaries for other configurations are built to `bin/`. Static and shared
libraries for embedding Wren get built in `lib/`.
For Mac users, there is also an XCode project under `util/xcode`. For
Windows brethren, `util/msvc2013` contains a Visual Studio solution. Note
that these may not have the exact same build settings as the makefile. The
makefile is the "official" way to compile Wren.
If you only want to build the VM, you can do:
:::sh
$ make vm
This compiles the VM to static and shared libraries. It does not even download
libuv since it isn't needed.
## Interactive mode
If you just run `wren` without any arguments, it starts the interpreter in
interactive mode. You can type in a line of code, and it immediately executes
it. Here's something to try:
:::wren
System.print("Hello, world!")
Or a little more exciting:
:::wren
for (i in 1..10) System.print("Counting up " + i.toString)
You can exit the interpreter using good old Ctrl-C or Ctrl-D, or just throw
your computer to the ground and storm off.
## Running scripts
The standalone interpreter can also load scripts from files and run them. Just
pass the name of the script to `wren`. Create a file named "my_script.wren" in
your favorite text editor and paste this into it:
:::wren
for (yPixel in 0...24) {
var y = yPixel / 12 - 1
for (xPixel in 0...80) {
var x = xPixel / 30 - 2
var x0 = x
var y0 = y
var iter = 0
while (iter < 11 && x0 * x0 + y0 * y0 <= 4) {
var x1 = (x0 * x0) - (y0 * y0) + x
var y1 = 2 * x0 * y0 + y
x0 = x1
y0 = y1
iter = iter + 1
}
System.write(" .-:;+=xX$& "[iter])
}
System.print("")
}
Now run:
:::sh
$ ./wren my_script.wren
Neat, right? You're a Wren programmer now! The next step is to [read more
docs](syntax.html) and learn your way around the language. If you run into
bugs, or have ideas or questions, any of the following work:
* **Ask on the [Wren mailing list][list].**
* Tell me on twitter at [@munificentbob][twitter].
* [File a ticket][issue] at [the GitHub repo][repo].
* Send a pull request.
* Email me at [`robert@stuffwithstuff.com`](mailto:robert@stuffwithstuff.com).
[list]: https://groups.google.com/forum/#!forum/wren-lang
[twitter]: https://twitter.com/intent/user?screen_name=munificentbob
[issue]: https://github.com/munificent/wren/issues
[repo]: https://github.com/munificent/wren

57
doc/site/index.markdown Normal file
View File

@ -0,0 +1,57 @@
^title Welcome
## Wren is a small, fast, class-based concurrent scripting language
Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in
a familiar, modern [syntax][].
:::wren
System.print("Hello, world!")
class Wren {
flyTo(city) {
System.print("Flying to " + city)
}
}
var adjectives = Fiber.new {
["small", "clean", "fast"].each {|word| Fiber.yield(word) }
}
while (!adjectives.isDone) System.print(adjectives.call())
* **Wren is small.** The VM implementation is under [4,000 semicolons][src].
You can skim the whole thing in an afternoon. It's *small*, but not
*dense*. It is readable and [lovingly-commented][nan].
* **Wren is fast.** A fast single-pass compiler to tight bytecode, and a
compact object representation help Wren [compete with other dynamic
languages][perf].
* **Wren is class-based.** There are lots of scripting languages out there,
but many have unusual or non-existent object models. Wren places
[classes][] front and center.
* **Wren is concurrent.** Lightweight [fibers][] are core to the execution
model and let you organize your program into an army of communicating
coroutines.
* **Wren is a scripting language.** Wren is intended for embedding in
applications. It has no dependencies, a small standard library,
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, [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
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
[perf]: performance.html
[classes]: classes.html
[fibers]: fibers.html
[embedding]: embedding-api.html
[started]: getting-started.html
[browser]: http://ppvk.github.io/wren-nest/
[contribute]: contributing.html

111
doc/site/lists.markdown Normal file
View File

@ -0,0 +1,111 @@
^title Lists
^category types
A list is a compound object that holds a collection of elements identified by
integer index. You can create a list by placing a sequence of comma-separated
expressions inside square brackets:
:::wren
[1, "banana", true]
Here, we've created a list of three elements. Notice that the elements don't
have to be the same type.
## Accessing elements
You can access an element from a list by calling the [subscript
operator](expressions.html#subscript-operators) on it with the index of the
element you want. Like most languages, indexes start at zero:
:::wren
var hirsute = ["sideburns", "porkchops", "'stache", "goatee"]
hirsute[0] // "sideburns".
hirsute[1] // "porkchops".
Negative indices counts backwards from the end:
:::wren
hirsute[-1] // "goatee".
hirsute[-2] // "'stache".
It's a runtime error to pass an index outside of the bounds of the list. If you
don't know what those bounds are, you can find out using count:
:::wren
hirsute.count // 4.
## Slices and ranges
Sometimes you want to copy a chunk of elements from a list. You can do that by
passing a [range](values.html#ranges) to the subscript operator, like so:
:::wren
hirsute[1..2] // ["porkchops", "'stache"].
This returns a new list containing the elements of the original list whose
indices are within the given range. Both inclusive and exclusive ranges work
and do what you expect.
Negative bounds also work like they do when passing a single number, so to copy
a list, you can just do:
:::wren
hirsute[0..-1]
## Adding elements
Lists are *mutable*, meaning their contents can be changed. You can swap out an
existing element in the list using the subscript setter:
:::wren
hirsute[1] = "muttonchops"
System.print(hirsute[1]) // muttonchops.
It's an error to set an element that's out of bounds. To grow a list, you can
use `add` to append a single item to the end:
:::wren
hirsute.add("goatee")
System.print(hirsute.count) // 4.
You can insert a new element at a specific position using `insert`:
:::wren
hirsute.insert(2, "soul patch")
The first argument is the index to insert at, and the second is the value to
insert. All elements following the inserted one will be pushed down to
make room for it.
It's valid to "insert" after the last element in the list, but only *right*
after it. Like other methods, you can use a negative index to count from the
back. Doing so counts back from the size of the list *after* it's grown by one:
:::wren
var letters = ["a", "b", "c"]
letters.insert(3, "d") // OK: inserts at end.
System.print(letters) // ["a", "b", "c", "d"]
letters.insert(-2, "e") // Counts back from size after insert.
System.print(letters) // ["a", "b", "c", "e", "d"]
## Removing elements
The opposite of `insert` is `removeAt`. It removes a single element from a
given position in the list. All following items are shifted up to fill in the
gap:
:::wren
var letters = ["a", "b", "c", "d"]
letters.removeAt(1)
System.print(letters) // ["a", "c", "d"]
The `removeAt` method returns the removed item:
:::wren
System.print(letters.removeAt(1)) // "c"
If you want to remove everything from the list, you can clear it:
:::wren
hirsute.clear()
System.print(hirsute) // []

136
doc/site/maps.markdown Normal file
View File

@ -0,0 +1,136 @@
^title Maps
^category types
A map is an *associative* collection. It holds a set of entries, each of which
maps a *key* to a *value*. The same data structure has a variety of names in
other languages: hash table, dictionary, association, table, etc.
You can create a map by placing a series of comma-separated entries inside
curly braces. Each entry is a key and a value separated by a colon:
:::wren
{
"George": "Harrison",
"John": "Lennon",
"Paul": "McCartney",
"Ringo": "Starr"
}
This creates a map that maps the first names of the Beatles to their last
names. Syntactically, in a map literal, keys can be any literal, a variable
name, or a parenthesized expression. Values can be any expression. Here, we're
using string literals for both keys and values.
*Semantically*, values can be any object, and multiple keys may map to the
same value. Keys have a few limitations. They must be one of the immutable
built-in [value types](values.html) in Wren. That means a number, string,
range, bool, or `null`. You can also use a [class object](classes.html) as a
key.
In addition, even though they aren't strictly immutable, [fibers](fibers.html)
can be used as map keys. This is handy for storing data that's roughly
"thread-local" by using the current fiber as a map key.
The reason for this limitation&mdash;and the reason maps are called "*hash*
tables" in other languages&mdash;is that each key is used to generate a numeric
*hash code*. This lets a map locate the value associated with a key in constant
time, even in very large maps. Since Wren only knows how to hash certain
built-in types, only those can be used as keys.
## Adding entries
You add new key-value pairs to the map by using the [subscript operator][]:
:::wren
var capitals = {}
capitals["Georgia"] = "Atlanta"
capitals["Idaho"] = "Boise"
capitals["Maine"] = "Augusta"
If the key isn't already present, this adds it and associates it with the given
value. If the key is already there, this just replaces its value.
[subscript operator]: expressions.html#subscript-operators
## Looking up values
To find the value associated with some key, again you use your friend the
subscript operator:
:::wren
System.print(capitals["Idaho"]) // "Boise".
If the key is present, this returns its value. Otherwise, it returns `null`. Of
course, `null` itself can also be used as a value, so seeing `null` here
doesn't necessarily mean the key wasn't found.
To tell definitively if a key exists, you can call `containsKey()`:
:::wren
var belief = {"nihilism": null}
System.print(belief["nihilism"]) // "null" though key exists.
System.print(belief["solipsism"]) // Also "null".
System.print(belief.containsKey("nihilism")) // "true".
System.print(belief.containsKey("solipsism")) // "false".
You can see how many entries a map contains using `count`:
:::wren
System.print(capitals.count) // "3".
## Removing entries
To remove an entry from a map, call `remove()` and pass in the key for the
entry you want to delete:
:::wren
capitals.remove("Maine")
System.print(capitals.containsKey("Maine")) // "false".
If the key was found, this returns the value that was associated with it:
:::wren
System.print(capitals.remove("Georgia")) // "Atlanta".
If the key wasn't in the map to begin with, `remove()` just returns `null`.
If you want to remove *everything* from the map, just like with [lists][], you
can just call `clear()`:
:::wren
capitals.clear()
System.print(capitals.count) // "0".
[lists]: lists.html
## Iterating over the contents
The subscript operator works well for finding values when you know the key
you're looking for, but sometimes you want to see everything that's in the map.
For that, map exposes two methods: `keys` and `values`.
The first returns a [Sequence][] that [iterates][] over all of the keys in the
map, and the second returns one that iterates over the values.
[sequence]: core/sequence.html
[iterates]: control-flow.html#the-iterator-protocol
If you want to see all of the key-value pairs in a map, the easiest way is to
iterate over the keys and use each to look up its value:
:::wren
var birds = {
"Arizona": "Cactus wren",
"Hawaii": "Nēnē",
"Ohio": "Northern Cardinal"
}
for (state in birds.keys) {
System.print("The state bird of " + state + " is " + birds[state])
}
This program will print the three states and their birds. However, the *order*
that they are printed isn't defined. Wren makes no promises about what order
keys and values will be iterated in when you use these methods. All it promises
is that every entry will appear exactly once.

285
doc/site/modules.markdown Normal file
View File

@ -0,0 +1,285 @@
^title Modules
^category language
Once you start writing programs that are more than little toys, you quickly run
into two problems:
1. You want to break them down into multiple smaller files to make it easier to
find your way around them.
2. You want to reuse pieces of them across different programs.
To address those, Wren has a simple module system. A file containing Wren code
defines a *module*. A module can use the code defined in another module by
*importing* it. You can break big programs into smaller modules that you
import, and you can reuse code by having multiple programs share the use of a
single module.
Wren does not have a single global scope. Instead, each module has its own
top-level scope independent of all other modules. This means, for example, that
two modules can define a top-level variable with the same name without causing
a name collision. Each module is, well, modular.
## Importing, briefly
When you run Wren and give it a file name to execute, the contents of that file
define the "main" module that execution starts at. To load and execute other
modules, you use an import statement:
:::wren
import "beverages" for Coffee, Tea
This finds a module named "beverages" and executes its source code. Then, it
looks up two top-level variables, `Coffee` and `Tea` in *that* module and
creates new variables in *this* module with their values.
This statement can appear anywhere a variable declaration is allowed, even
inside blocks:
:::wren
if (thirsty) {
import "beverages" for Coffee, Tea
}
If you want to load a module, but not bind any variables from it, you can omit
the `for` clause:
:::wren
import "some_imperative_code"
That's the basic idea. Now let's break it down into each of the steps it
performs:
1. Locate the source code for the module.
2. Execute the imported module's code.
3. Bind new variables in the importing module to values defined in the imported module.
We'll go through each step:
## Locating a module
The first thing you need to do to import a module is actually *find* the code
for it. The import specifies a *name*&mdash;some arbitrary string that is used
to uniquely identify the module. The embedding application controls how that
string is used to locate a blob of source code.
When the host application creates a new Wren VM, it provides a module loader
function:
:::c
WrenConfiguration config;
config.loadModuleFn = loadModule;
// Other configuration...
WrenVM* vm = wrenNewVM(&config);
That function has this signature:
:::c
char* WrenLoadModuleFn(WrenVM* vm, const char* name);
Whenever a module is imported, the VM calls this and passes it the name of the
module. The embedder is expected to return the source code contents of the
module. When you embed Wren in your app, you can handle this however you want:
reach out to the file system, look inside resources bundled into your app,
whatever.
You can return `NULL` from this function to indicate that a module couldn't be
found. When you do this, Wren will report it as a runtime error.
### The command-line loader
The default little command-line VM that comes with Wren has a very simple
lookup process. It appends the module name and ".wren" to the directory where
the main module was loaded and looks for that file. So, let's say you run:
:::bash
$ wren /code/my_program.wren
And that main module has:
:::wren
import "some/module"
Then the command-line VM will try to find `/code/some/module.wren`. By
convention, forward slashes should be used as path separators, even on Windows,
to help ensure your scripts are platform-independent. (Forward slashes are a
valid separator on Windows, but backslashes are not valid on other OSes.)
## Executing the module
Once we have the source code for a module, we need to run it. First, the VM
takes the fiber that is executing the `import` statement in the importing
module and pauses it.
Then it creates a new module object&mdash;a new fresh top-level scope,
basically&mdash;and a new fiber. It executes the new module's code in that
fiber and scope. The module can run whatever imperative code it wants and
define whatever top-level variables it wants.
When the module's code is done being executed and its fiber completes, the
suspended fiber for the importing module is resumed. This suspending and
resuming is recursive. So, if "a" imports "b" which imports "c", both "a" and
"b" will be suspended while "c" is running. When "c" is done, "b" is resumed.
Then, when "b" completes, "a" is resumed.
Think of it like traversing the tree of imports, one node at a time. At any
given point in time, only one module's code is running.
## Binding variables
Once the module is done executing, the last step is to actually *import* some
data from it. Any module can define "top-level" [variables](variables.html).
These are simply variables declared outside of any
[method](classes.html#methods) or [function](functions.html).
These are visible to anything inside the module, but they can also be
*exported* and used by other modules. When Wren executes an import like:
:::wren
import "beverages" for Coffee, Tea
First it runs the "beverages" module. Then it goes through each of the variable
names in the `for` clause. For each one, it looks for a top-level variable with
that name in the imported module. If a variable with that name can't be found
in the imported module, it's a runtime error.
Otherwise, it gets the current value of the variable and defines a new variable
in the importing module with the same name and value. It's worth noting that
the importing module gets its *own* variable whose value is a snapshot of the
value of the imported variable at the time it was imported. If either module
later assigns to that variable, the other won't see it. It's not a "live"
connection.
In practice, most top-level variables are only assigned once anyway, so this
rarely makes a difference.
## Shared imports
Earlier, I described a programs set of modules as a tree. Of course, it's only
a *tree* of modules if there are no *shared imports*. But consider a program
like:
:::wren
// main.wren
import "a"
import "b"
// a.wren
import "shared"
// b.wren
import "shared"
// shared.wren
System.print("Shared!")
Here, "a" and "b" both want to use "shared". If "shared" defines some top-level
state, we only want a single copy of that in memory. To handle this, a module's
code is only executed the *first* time it is loaded. After that, importing the
module again just looks up the previously loaded module.
Internally, Wren maintains a map of every module it has previously loaded. When
a module is imported, Wren looks for it in that map first before it calls out
to the embedder for its source.
In other words, in that list of steps above, there's an implicit zeroth step:
"See if we already loaded the module and reuse it if we did". That means the
above program only prints "Shared!" once.
## Cyclic imports
You can even have cycles in your imports, provided you're a bit careful with
them. The loading process, in detail, is:
1. See if we have already created a module with the given name.
2. If so, use it.
3. Otherwise, create a new module with the name and store it in the module
registry.
4. Create a fiber for it and execute its code.
Note the order of the last two steps. When a module is loaded, it is added to
the registry *before* it is executed. This means if an import for that same
module is reached while the module itself or one of its imports is executing,
it will be found in the registry and the cycle is short-circuited.
For example:
:::wren
// main.wren
import "a"
// a.wren
System.print("start a")
import "b"
System.print("end a")
// b.wren
System.print("start b")
import "a"
System.print("end b")
This program runs successfully and prints:
:::text
start a
start b
end b
end a
Where you have to be careful is binding variables. Consider:
:::wren
// main.wren
import "a"
// a.wren
import "b" for B
var A = "a variable"
// b.wren
import "a" for A
var B = "b variable"
The import of "a" in b.wren will fail here. If you trace the execution, you
get:
1. Execute `import "a"` in "main.wren". That suspends "main.wren".
2. Execute `import "b"` in "a.wren". That suspends "a.wren".
3. Execute `import "a"` in "b.wren". Since "a" is already in the module map,
this does *not* suspend it.
Instead, we look for a variable named `A` in that module. But it hasn't been
defined yet since "a.wren" is still sitting on the `import "b" for B` line
before the declaration. To get this to work, you would need to move the
variable declaration above the import:
:::wren
// main.wren
import "a"
// a.wren
var A = "a variable"
import "b" for B
// b.wren
import "a" for A
var B = "b variable"
Now when we run it, we get:
1. Execute `import "a"` in "main.wren". That suspends "main.wren".
2. Define `A` in "a.wren".
2. Execute `import "b"` in "a.wren". That suspends "a.wren".
3. Execute `import "a"` in "b.wren". Since "a" is already in the module map,
this does *not* suspend it. It looks up `A`, which has already been defined,
and binds it.
4. Define `B` in "b.wren".
5. Complete "b.wren".
6. Look up `B` in "b.wren" and bind it in "a.wren".
7. Resume "a.wren".
This sounds super hairy, but that's because cyclic dependencies are hairy in
general. The key point here is that Wren *can* handle them in the rare cases
where you need them.

View File

@ -0,0 +1,237 @@
^title Performance
^category reference
Even though most benchmarks aren't worth the pixels they're printed on, people
seem to like them, so here's a few:
<h3>Method Call</h3>
<table class="chart">
<tr>
<th>wren</th><td><div class="chart-bar wren" style="width: 11%;">0.15s&nbsp;</div></td>
</tr>
<tr>
<th>luajit (-joff)</th><td><div class="chart-bar" style="width: 17%;">0.23s&nbsp;</div></td>
</tr>
<tr>
<th>ruby</th><td><div class="chart-bar" style="width: 26%;">0.36s&nbsp;</div></td>
</tr>
<tr>
<th>lua</th><td><div class="chart-bar" style="width: 43%;">0.58s&nbsp;</div></td>
</tr>
<tr>
<th>python3</th><td><div class="chart-bar" style="width: 88%;">1.18s&nbsp;</div></td>
</tr>
<tr>
<th>python</th><td><div class="chart-bar" style="width: 100%;">1.33s&nbsp;</div></td>
</tr>
</table>
<h3>DeltaBlue</h3>
<table class="chart">
<tr>
<th>wren</th><td><div class="chart-bar wren" style="width: 27%;">0.13s&nbsp;</div></td>
</tr>
<tr>
<th>python3</th><td><div class="chart-bar" style="width: 94%;">0.44s&nbsp;</div></td>
</tr>
<tr>
<th>python</th><td><div class="chart-bar" style="width: 100%;">0.47s&nbsp;</div></td>
</tr>
</table>
<h3>Binary Trees</h3>
<table class="chart">
<tr>
<th>luajit (-joff)</th><td><div class="chart-bar" style="width: 20%;">0.16s&nbsp;</div></td>
</tr>
<tr>
<th>wren</th><td><div class="chart-bar wren" style="width: 39%;">0.29s&nbsp;</div></td>
</tr>
<tr>
<th>ruby</th><td><div class="chart-bar" style="width: 49%;">0.37s&nbsp;</div></td>
</tr>
<tr>
<th>python3</th><td><div class="chart-bar" style="width: 68%;">0.52s&nbsp;</div></td>
</tr>
<tr>
<th>lua</th><td><div class="chart-bar" style="width: 97%;">0.73s&nbsp;</div></td>
</tr>
<tr>
<th>python</th><td><div class="chart-bar" style="width: 100%;">0.75s&nbsp;</div></td>
</tr>
</table>
<h3>Recursive Fibonacci</h3>
<table class="chart">
<tr>
<th>luajit (-joff)</th><td><div class="chart-bar" style="width: 17%;">0.15s&nbsp;</div></td>
</tr>
<tr>
<th>wren</th><td><div class="chart-bar wren" style="width: 38%;">0.31s&nbsp;</div></td>
</tr>
<tr>
<th>ruby</th><td><div class="chart-bar" style="width: 40%;">0.33s&nbsp;</div></td>
</tr>
<tr>
<th>lua</th><td><div class="chart-bar" style="width: 43%;">0.35s&nbsp;</div></td>
</tr>
<tr>
<th>python3</th><td><div class="chart-bar" style="width: 96%;">0.78s&nbsp;</div></td>
</tr>
<tr>
<th>python</th><td><div class="chart-bar" style="width: 100%;">0.81s&nbsp;</div></td>
</tr>
</table>
**Shorter bars are better.** Each benchmark is run ten times and the best time
is kept. It only measures the time taken to execute the benchmarked code
itself, not interpreter startup.
These were run on my MacBook Pro 2.3 GHz Intel Core i7 with 16 GB of 1,600 MHz
DDR3 RAM. Tested against Lua 5.2.3, LuaJIT 2.0.2, Python 2.7.5, Python 3.3.4,
ruby 2.0.0p247. LuaJIT is run with the JIT *disabled* (i.e. in bytecode
interpreter mode) since I want to support platforms where JIT-compilation is
disallowed. LuaJIT with the JIT enabled is *much* faster than all of the other
languages benchmarked, including Wren, because Mike Pall is a robot from the
future.
The benchmark harness and programs are
[here](https://github.com/munificent/wren/tree/master/test/benchmark).
## Why is Wren fast?
Languages come in four rough performance buckets, from slowest to fastest:
1. Tree-walk interpreters: Ruby 1.8.7 and earlier, Io, that
interpreter you wrote for a class in college.
2. Bytecode interpreters: CPython,
Ruby 1.9 and later, Lua, early JavaScript VMs.
3. JIT compiled dynamically typed languages: Modern JavaScript VMs,
LuaJIT, PyPy, some Lisp/Scheme implementations.
4. Statically typed languages: C, C++, Java, C#, Haskell, etc.
Most languages in the first bucket aren't suitable for production use. (Servers
are one exception, because you can throw more hardware at a slow language
there.) Languages in the second bucket are fast enough for many use cases, even
on client hardware, as the success of the listed languages shows. Languages in
the third bucket are quite fast, but their implementations are breathtakingly
complex, often rivaling that of compilers for statically-typed languages.
Wren is in the second bucket. If you want a simple implementation that's fast
enough for real use, this is the sweet spot. In addition, Wren has a few tricks
up its sleeve:
### A compact value representation
A core piece of a dynamic language implementation is the data structure used
for variables. It needs to be able to store (or reference) a value of any type,
while also being as compact as possible. Wren uses a technique called *[NaN
tagging][]* for this.
[nan tagging]: http://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations
All values are stored internally in Wren as small, eight-byte double-precision
floats. Since that is also Wren's number type, in order to do arithmetic, no
conversion is needed before the "raw" number can be accessed: a value holding a
number *is* a valid double. This keeps arithmetic fast.
To store values of other types, it turns out there's a ton of unused bits in a
NaN double. You can stuff a pointer for heap-allocated objects, with room left
over for special values like `true`, `false`, and `null`. This means numbers,
bools, and null are unboxed. It also means an entire value is only eight bytes,
the native word size on 64-bit machines. Smaller = faster when you take into
account CPU caching and the cost of passing values around.
### Fixed object layout
Most dynamic languages treat objects as loose bags of named properties. You can
freely add and remove properties from an object after you've created it.
Languages like Lua and JavaScript don't even have a well-defined concept of a
"type" of object.
Wren is strictly class-based. Every object is an instance of a class. Classes
in turn have a well-defined declarative syntax, and cannot be imperatively
modified. In addition, fields in Wren are private to the class&mdash;they can
only be accessed from methods defined directly on that class.
Put all of that together and it means you can determine at *compile* time
exactly how many fields an object has and what they are. In other languages,
when you create an object, you allocate some initial memory for it, but that
may have to be reallocated multiple times as fields are added and the object
grows. Wren just does a single allocation up front for exactly the right number
of fields.
Likewise, when you access a field in other languages, the interpreter has to
look it up by name in a hash table in the object, and then maybe walk its
inheritance chain if it can't find it. It must do this every time since fields
may be added freely. In Wren, field access is just accessing a slot in the
instance by an offset known at compile time: it's just adding a few pointers.
### Copy-down inheritance
When you call a method on an object, the method must be located. It could be
defined directly on the object's class, or it may be inheriting it from some
superclass. This means that in the worst case, you may have to walk the
inheritance chain to find it.
Advanced implementations do very smart things to optimize this, but it's made
more difficult by the mutable nature of the underlying language: if you can add
new methods to existing classes freely or change the inheritance hierarchy, the
lookup for a given method may actually change over time. You have to check for
that which costs CPU cycles.
Wren's inheritance hierarchy is static and fixed at class definition time. This
means that we can copy down all inherited methods in the subclass when it's
created since we know those will never change. Method dispatch then just
requires locating the method in the class of the receiver.
### Computed gotos
On compilers that support it, Wren's core bytecode interpreter loop uses
something called [*computed gotos*][goto]. The hot core of a bytecode
interpreter is effectively a giant `switch` on the instruction being executed.
[goto]: http://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables/
Doing that using an actual `switch` confounds the CPU's [branch
predictor][]&mdash;there is basically a single branch point for the entire
interpreter. That quickly saturates the predictor and it just gets confused and
fails to predict anything, which leads to more CPU stalls and pipeline flushes.
[branch predictor]: http://en.wikipedia.org/wiki/Branch_predictor
Using computed gotos gives you a separate branch point at the end of each
instruction. Each gets its own branch prediction, which often succeeds since
some instruction pairs are more common than others. In my rough testing, this
makes a 5-10% performance difference.
### A single-pass compiler
Compile time is a relatively small component of a language's performance: code
only has to be compiled once but a given line of code may be run many times.
However, fast compilation helps with *startup* speed&mdash;the time it takes to
get anything up and running. For that, Wren's compiler is quite fast.
It's modeled after Lua's compiler. Instead of tokenizing and then parsing to
create a bunch of AST structures which are then consumed and deallocated by
later phases, it emits code directly during parsing. This means it does minimal
memory allocation during a parse and has very little overhead.
## Why don't other languages do this?
Most of Wren's performance comes from language design decisions. While it's
dynamically *typed* and *dispatched*, classes are relatively statically
*defined*. That makes a lot of things much easier. Other languages have a much
more mutable object model, and cannot change that without breaking lots of
existing code.
Wren's closest sibling, by far, is Lua. Lua is more dynamic than Wren which
makes its job harder. Lua also tries very hard to be compatible across a wide
range of hardware and compilers. If you have a C89 compiler for it, odds are
very good that you can run Lua on it.
Wren cares about compatibility, but it requires C99 or C++98 and IEEE double
precision floats. That may exclude some edge case hardware, but makes things
like NaN tagging, computed gotos, and some other tricks possible.
<script src="script.js"></script>

171
doc/site/qa.markdown Normal file
View File

@ -0,0 +1,171 @@
^title Q & A
^category reference
## Why did you create Wren?
Other creative endeavors aren't immediately met with existential crises, but
for some reason programmers don't seem to like new languages. Here's the niche
I'm trying to fill:
There are a few scripting languages used for embedding in applications. Lua is
the main one. TCL used to be. There's also Guile, increasingly JavaScript, and
some applications embed Python. I'm an ex-game developer, so when I think
"scripting", I tend to think "game scripting".
Lua is nice: it's small, simple, and fast. But&mdash;and I don't mean this as a
criticism&mdash;it's also weird if you're used to languages like C++ and Java.
The syntax is different. The semantics, especially the object model are
unusual. Anyone can get used to 1-based indexing, but things like metatables
really show that objects were bolted onto Lua after the fact.
I think there's room for a language as simple as Lua, but that feels natural to
someone with an OOP background. Wren is my attempt at that.
## Why classes?
Thanks to JavaScript's popularity, lots of people are discovering prototypes
right now, and the paradigm is experiencing a popularity boom. I think
prototypes are interesting, but after [several years playing with them][finch],
I concluded (like many people on the original Self project that invented
prototypes) that classes are more usable.
[finch]: http://finch.stuffwithstuff.com/
Here's an example of that kind of object-oriented programming in Lua:
:::lua
Account = {}
Account.__index = Account
function Account.create(balance)
local acnt = {} -- our new object
setmetatable(acnt,Account) -- make Account handle lookup
acnt.balance = balance -- initialize our object
return acnt
end
function Account:withdraw(amount)
self.balance = self.balance - amount
end
-- create and use an Account
acc = Account.create(1000)
acc:withdraw(100)
Here's the same example in Wren:
:::wren
class Account {
this new(balance) { _balance = balance }
withdraw(amount) { _balance = _balance - amount }
}
// create and use an Account
var acc = Account.new(1000)
acc.withdraw(100)
Classes have a reputation for complexity because most of the widely used
languages with them are quite complex: C++, Java, C#, Ruby, and Python. I hope
to show with Wren that it is those languages that are complex, and not classes
themselves.
Smalltalk, the language that inspired most of those languages, is famously
simple. Its syntax [fits on an index card][card]. My aim is to keep Wren that
minimal while still having the expressive power of [classes](classes.html).
[card]: http://www.jarober.com/blog/blogView?showComments=true&title=Readability+is+Key&entry=3506312690
## Why compile to bytecode?
The [performance page](performance.html) has more details, but the short answer
is that bytecode is a nice trade-off between performance and simplicity. Also:
* Many devices like iPhones and game consoles don't allow executing code
generated at runtime, which rules out just-in-time compilation.
* I think [fibers](fibers.html) are a really powerful tool, and implementing
them is straightforward in a bytecode VM that doesn't use the native stack.
## Why is the VM stack-based instead of register-based?
Bytecode VMs come in two flavors. Stack-based VMs have short (usually one-byte)
instructions whose operands are implicitly understood to be at the top of the
stack. That means you often have a couple of instructions to push some stuff on
the stack and then an instruction to do something.
Register-based VMs have big instructions (usually 32 bits) that contain both an
opcode and a couple of numbers indicating where in the stack the operands can
be found. This is cool because it means, that, for example, this Lua statement:
:::lua
a = b + c
Can be a single bytecode instruction. In a stack-based language, it would be
four&mdash;push `b`, push `c`, add, store `a`. (Though note that in both cases
you've got 32 total bits of code.)
Lua used to be stack-based and switched to register-based and got a speed
boost. Why not use registers for Wren?
I've implemented a [register-based VM
before](http://finch.stuffwithstuff.com/). I think it's a cool model, but I
don't think it would bring much benefit for Wren. It's more effort to compile,
and I'm trying to keep Wren's implementation as simple as possible.
In return for that complexity, you can generate fewer instructions. However, I
don't think Wren would be able to take advantage of that. Wren doesn't
currently have any dedicated instructions for arithmetic. Operators are just
regular method calls and can call user-defined procedures.
The calling convention for methods requires all of their parameters to be at
the top of the caller's stack so that they can become bottom of the callee's
stack frame window. To call `+` in Wren, we still have to push the arguments on
top of the stack. Likewise, the method calling convention places the return
value where the first argument was, so we'd have to move it back down to the
destination slot after the call.
It may be worth having dedicated instructions for arithmetic that special case
the built-in types before falling back to user-defined operator methods (which
I assume is what Lua does since they added operator overloading late in the
language's development). If that happens, it may be possible to switch to
register-based.
But I'm not convinced it would be an actual performance win. A lot of details
of the language affect whether a register-based VM is better. For example,
assignments are statements in Lua but expressions in Wren, which would make
them harder to compile to efficient register-based code.
## What about your other languages?
This is a strange question if you don't happen to know [who I am][me]. In the
past, I've hacked on and blogged about a couple of other hobby languages like
[Finch][] and [Magpie][].
[me]: http://journal.stuffwithstuff.com
[magpie]: http://magpie-lang.org/
I started Finch to learn more about implementing an interpreter and also about
the prototype paradigm. I learned a ton about both. Critically, I learned that
I really prefer classes over prototypes. I started retrofitting classes into
Finch but realized it was too big of a change, and thus Wren was born.
Wren is a replacement for Finch to me. I gave it a new name mainly so that I
can keep Finch around in case other people want to take it and do something
with it. I don't have any intention to work on it anymore.
Magpie is a trickier one. I really like the ideas behind Magpie. It's the
general-purpose language I wish I had much of the time. I love pattern matching
and multiple dispatch. I like how it integrates the event-based IO of [libuv][]
with the simplicity of fibers.
[libuv]: https://github.com/joyent/libuv
But it's also a much more challenging project. As a general-purpose language,
there's a ton of library work to do before Magpie is useful for anything. It
has some unresolved GC issues. And I'm frankly not skilled enough right now to
implement multiple dispatch efficiently.
Meanwhile, since I started working on Magpie, [Julia](http://julialang.org/)
appeared and [Dylan](http://opendylan.org/) *re*appeared. I created Magpie
partially to carry the torch of multiple dispatch, but others are starting to
spread that light now.

456
doc/site/style.scss Normal file
View File

@ -0,0 +1,456 @@
$header: "Sanchez", helvetica, arial, sans-serif;
$subheader: "Lato", helvetica, arial, sans-serif;
$body: "Source Sans Pro", georgia, serif;
$code: "Source Code Pro", Menlo, Monaco, Consolas, monospace;
$dark: hsl(210, 10%, 25%);
$darker: hsl(210, 20%, 10%);
$light: hsl(0, 0%, 100%);
$gray-10: mix($dark, $light, 10%);
$gray-20: mix($dark, $light, 20%);
$gray-30: mix($dark, $light, 30%);
$gray-40: mix($dark, $light, 40%);
$gray-50: mix($dark, $light, 50%);
$gray-60: mix($dark, $light, 60%);
$gray-80: mix($dark, $light, 80%);
$text: mix($light, #000, 20%);
$code-color: hsl(210, 20%, 40%);
$code-bg: hsl(210, 20%, 98%);
$link: hsl(200, 60%, 50%);
$link-hover: hsl(210, 100%, 80%);
$link-dark: hsl(210, 60%, 20%);
$link-glow: hsla(210, 100%, 50%, 0.4);
$core-link: hsl(150, 70%, 40%);
$core-link-hover: hsl(130, 70%, 70%);
$core-link-dark: hsl(160, 60%, 25%);
$core-link-glow: hsla(130, 90%, 50%, 0.4);
* {
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body, code, h1, h2, h3, p, pre {
margin: 0;
padding: 0;
}
body {
background: $light;
color: $text;
font: 16px/25px $body;
}
.page {
margin: 0 auto;
width: 800px;
// Clear contents.
&:after {
content: "";
display: table;
clear: both;
}
}
.main-column {
position: relative;
width: 560px;
}
header {
text-shadow: 0 1px 1px $darker;
.page {
height: 120px;
}
background: $dark;
border-bottom: solid 1px $darker;
h1 {
position: absolute;
left: 0;
top: 63px;
padding: 0;
font: 400 48px $header;
letter-spacing: 2px;
}
h2 {
position: absolute;
right: 0;
top: 72px;
padding: 0;
font: 500 13px $subheader;
text-transform: uppercase;
letter-spacing: 2px;
color: $gray-50;
}
a {
color: $gray-20;
}
a:hover {
color: $link-hover;
text-shadow: 0 0 6px $link-glow;
}
}
nav {
float: right;
width: 160px;
padding-top: 110px;
h2 {
color: $gray-30;
font: 500 11px $subheader;
text-transform: uppercase;
letter-spacing: 2px;
margin: 0;
}
ul {
padding: 0;
margin: 6px 0 20px 0;
}
li {
font: 16px $body;
color: $gray-30;
list-style-type: none;
margin: 0 0 4px 0;
}
}
h1 {
padding-top: 30px;
font: 500 36px/60px $header;
color: $link;
}
h2 {
font: 500 24px $header;
margin: 24px 0 0 0;
color: $link;
}
h3 {
font: 20px $body;
margin: 24px 0 0 0;
color: $link;
}
a {
color: $link;
text-decoration: none;
transition: color 0.2s, text-shadow 0.2s;
outline: none;
}
main {
@extend .main-column;
padding-top: 12px;
float:left;
}
a:hover {
color: $link-dark;
}
.header-anchor {
color: $light;
}
h2:hover > .header-anchor,
h3:hover > .header-anchor {
color: $gray-10;
}
h2:hover > .header-anchor:hover,
h3:hover > .header-anchor:hover {
color: $link-dark;
}
p, li {
margin: 10px 0;
}
p + p {
margin-top: 20px;
}
code, pre {
color: $code-color;
font: 13px $code;
background: $code-bg;
border-radius: 2px;
border: solid 1px hsl(200, 20%, 95%);
border-bottom: solid 1px hsl(200, 20%, 90%);
}
code {
padding: 1px 2px;
white-space: nowrap;
}
pre {
margin: 10px 0;
line-height: 20px;
padding: 10px;
// Scroll horizontally if not wide enough.
overflow: auto;
}
footer {
margin-top: 40px;
padding: 20px 0 40px 0;
font: 14px $body;
background: $dark;
color: $gray-20;
border-top: solid 1px $darker;
text-align: center;
text-shadow: 0 1px 1px $darker;
a {
color: $link-hover;
}
a:hover {
color: $link;
}
}
// link hsl(200, 60%, 50%);
// hsl(210, 80%, 60%);
// Syntax highlighting.
.codehilite pre {
// Comments.
span.c1, span.cm { color: mix($code-color, $code-bg, 60%); }
// Keywords.
span.k, span.kd, span.kc, span.nb { color: hsl(200, 60%, 50%); }
// Names.
span.vg { color: hsl(180, 70%, 35%); }
span.vi { color: hsl(90, 80%, 35%); }
span.vc { color: hsl(130, 60%, 40%); }
// Numbers.
span.m, span.mi, span.mf { color: hsl(30, 80%, 45%); }// hsl(90, 80%, 35%)
// Strings.
span.s, span.s2 { color: hsl(40, 80%, 45%); }
span.se { color: hsl(45, 80%, 50%); }
// Operators and punctuation.
span.o { color: hsl(200, 40%, 50%); }
span.p { color: mix($code-color, $code-bg, 80%); }
// Preprocessor directives.
span.cp { color: hsl(270, 40%, 60%); }
}
// Have a different primary color for the core library docs.
body.core {
header {
a {
color: $gray-20;
}
a:hover {
color: $core-link-hover;
text-shadow: 0 0 6px $core-link-glow;
}
}
a {
color: $core-link;
}
a:hover {
color: $core-link-dark;
}
.header-anchor {
color: $light;
}
main {
h1, h2, h3 {
color: $core-link;
}
h2:hover > .header-anchor:hover,
h3:hover > .header-anchor:hover {
color: $core-link-dark;
}
}
footer {
a {
color: $core-link-hover;
}
a:hover {
color: $core-link;
}
}
}
table {
width: 100%;
border-collapse: collapse;
tr {
margin: 0;
padding: 0;
vertical-align: top;
}
th, td {
font-size: 14px;
line-height: 20px;
text-align: left;
}
}
// Bar charts on the performance page.
table.chart {
margin: 4px 0 0 0;
padding: 5px 0 5px 25px;
td, th {
line-height: 14px;
margin: 0;
padding: 1px 0;
}
th {
font-size: 14px;
width: 100px;
}
.chart-bar {
display: inline-block;
font: 13px $body;
color: $light;
background: $link;
border-bottom: solid 1px $link-dark;
text-align: right;
border-radius: 2px;
}
.chart-bar.wren {
background: mix($link, $link-dark, 30%);
border-bottom: solid 1px $link-dark;
}
}
// Precedence table on expressions page.
table.precedence {
th {
font: 500 11px $subheader;
text-transform: uppercase;
letter-spacing: 1px;
color: $gray-60;
padding: 6px 0;
border-bottom: solid 1px $gray-10;
}
td {
padding: 3px 0;
border-bottom: solid 1px $gray-10;
}
}
@media only screen and (max-width: 839px) {
// 36 pixel columns.
.page { width: 720px; }
nav { width: 144px; }
.main-column { width: 504px; }
}
@media only screen and (max-width: 759px) {
// 32 pixel columns.
.page { width: 640px; }
nav { width: 128px; }
.main-column { width: 448px; }
}
@media only screen and (max-width: 679px) {
// 28 pixel columns.
.page { width: 560px; }
nav { width: 112px; }
.main-column { width: 392px; }
header h2 {
font-size: 12px;
letter-spacing: 1px;
}
}
@media only screen and (max-width: 639px) {
.page { width: 100%; }
nav {
float: none;
width: 100%;
padding: 10px 10px;
margin: 0;
background: $gray-10;
text-align: center;
section {
display: inline-block;
vertical-align: top;
text-align: left;
width: 30%;
}
}
.main-column {
padding: 0 20px;
width: 100%;
}
header {
h1 {
position: relative;
top: 10px;
left: 0;
text-align: center;
}
h2 {
position: relative;
top: 0;
right: 0;
text-align: center;
font-size: 13px;
letter-spacing: 2px;
}
}
main {
float: none;
width: 100%;
}
pre {
font-size: 13px;
}
footer {
padding: 20px 20px 40px 20px;
}
}

126
doc/site/syntax.markdown Normal file
View File

@ -0,0 +1,126 @@
^title Syntax
^category language
Wren's syntax is designed to be familiar to people coming from C-like languages
while being a bit simpler and more streamlined.
Scripts are stored in plain text files with a `.wren` file extension. Wren does
not compile ahead of time: programs are run directly from source, from top to
bottom like a typical scripting language. (Internally, programs are compiled to
bytecode for [efficiency][], but that's an implementation detail.)
[efficiency]: performance.html
## Comments
Line comments start with `//` and end at the end of the line:
:::wren
// This is a comment.
Block comments start with `/*` and end with `*/`. They can span multiple lines:
:::wren
/* This
is
a
multi-line
comment. */
Unlike C, block comments can nest in Wren:
:::wren
/* This is /* a nested */ comment. */
This is handy because it lets you easily comment out an entire block of code,
even if the code already contains block comments.
## Reserved words
Some people like to see all of the reserved words in a programming language in
one lump. If you're one of those folks, here you go:
:::wren
break class construct else false for foreign if import
in is null return static super this true var while
## Identifiers
Naming rules are similar to other programming languages. Identifiers start with
a letter or underscore and may contain letters, digits, and underscores. Case
is sensitive.
:::wren
hi
camelCase
PascalCase
_under_score
abc123
ALL_CAPS
Identifiers that start with underscore (`_`) are special in Wren. They are used
to indicate [fields](classes.html#fields) in classes.
## Newlines
Newlines (`\n`) are meaningful in Wren. They are used to separate statements:
:::wren
// Two statements:
System.print("hi") // Newline.
System.print("bye")
Sometimes, though, a statement doesn't fit on a single line and jamming a
newline in the middle would trip it up. To handle that, Wren has a very simple
rule: It ignores a newline following any token that can't end a statement.
:::wren
System.print( // Newline here is ignored.
"hi")
In practice, this means you can put each statement on its own line and wrap
them across lines as needed without too much trouble.
## Blocks
Wren uses curly braces to define *blocks*. You can use a block anywhere a
statement is allowed, like in [control flow](control-flow.html) statements.
[Method](classes.html#methods) and [function](functions.html) bodies are also
blocks. For example, here we have a block for the then case, and a single
statement for the else:
:::wren
if (happy && knowIt) {
hands.clap
} else System.print("sad")
Blocks have two similar but not identical forms. Typically, blocks contain a
series of statements like:
:::wren
{
System.print("one")
System.print("two")
System.print("three")
}
Blocks of this form when used for method and function bodies automatically
return `null` after the block has completed. If you want to return a different
value, you need an explicit `return` statement.
However, it's pretty common to have a method or function that just evaluates
and returns the result of a single expression. For that, Wren has a more
compact notation:
:::wren
{ "single expression" }
If there is no newline after the `{` (or after the parameter list in a
[function](functions.html)), then the block may only contain a single
expression, and it automatically returns the result of it. It's exactly the
same as doing:
:::wren
{
return "single expression"
}

View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>{title} Wren</title>
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="core">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav>
<ul>
<li><a href="./">Core Library</a></li>
</ul>
<section>
<h2>core classes</h2>
<ul>
<li><a href="bool.html">Bool</a></li>
<li><a href="class.html">Class</a></li>
<li><a href="fiber.html">Fiber</a></li>
<li><a href="fn.html">Fn</a></li>
<li><a href="list.html">List</a></li>
<li><a href="map.html">Map</a></li>
<li><a href="null.html">Null</a></li>
<li><a href="num.html">Num</a></li>
<li><a href="object.html">Object</a></li>
<li><a href="range.html">Range</a></li>
<li><a href="sequence.html">Sequence</a></li>
<li><a href="string.html">String</a></li>
<li><a href="system.html">System</a></li>
</ul>
</section>
</nav>
<main>
<h1>{title}</h1>
{html}
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives <a href="https://github.com/munificent/wren">on GitHub</a> &mdash; Made with &#x2764; by <a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and <a href="https://github.com/munificent/wren/blob/master/AUTHORS">friends</a>.</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

73
doc/site/template.html Normal file
View File

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>{title} Wren</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
</ul>
<section>
<h2>language</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="expressions.html">Expressions</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modules.html">Modules</a></li>
</ul>
</section>
<section>
<h2>types</h2>
<ul>
<li><a href="values.html">Values</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="fibers.html">Fibers</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="core">Core Library</a></li>
<li><a href="embedding-api.html">Embedding API</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="community.html">Community</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<main>
<h1>{title}</h1>
{html}
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives <a href="https://github.com/munificent/wren">on GitHub</a> &mdash; Made with &#x2764; by <a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and <a href="https://github.com/munificent/wren/blob/master/AUTHORS">friends</a>.</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

104
doc/site/values.markdown Normal file
View File

@ -0,0 +1,104 @@
^title Values
^category types
Values are the built-in object types that all other objects are composed of.
They can be created through *literals*, expressions that evaluate to a value.
All values are *immutable*&mdash;once created, they do not change. The number
`3` is always the number `3`. The string `"frozen"` can never have its
character array modified in place.
## Booleans
A boolean value represents truth or falsehood. There are two boolean literals,
`true` and `false`. Their class is [Bool](core/bool.html).
## Numbers
Like other scripting languages, Wren has a single numeric type:
double-precision floating point. Number literals look like you expect coming
from other languages:
:::wren
0
1234
-5678
3.14159
1.0
-12.34
Numbers are instances of the [Num](core/num.html) class.
## Strings
A string is an array of bytes. Typically, they store characters encoded in
UTF-8, but you can put any byte values in there, even zero or invalid UTF-8
sequences. (You might have some trouble *printing* the latter to your terminal,
though.)
String literals are surrounded in double quotes:
:::wren
"hi there"
A handful of escape characters are supported:
:::wren
"\0" // The NUL byte: 0.
"\"" // A double quote character.
"\\" // A backslash.
"\a" // Alarm beep. (Who uses this?)
"\b" // Backspace.
"\f" // Formfeed.
"\n" // Newline.
"\r" // Carriage return.
"\t" // Tab.
"\v" // Vertical tab.
A `\u` followed by four hex digits can be used to specify a Unicode code point:
:::wren
System.print("\u0041\u0b83\u00DE") // "AஃÞ"
A `\x` followed by two hex digits specifies a single unencoded byte:
:::wren
System.print("\x48\x69\x2e") // "Hi."
Strings are instances of class [String](core/string.html).
## Ranges
A range is a little object that represents a consecutive range of numbers.
They don't have their own dedicated literal syntax. Instead, the number class
implements the `..` and `...` [operators](expressions.html#operators) to create
them:
:::wren
3..8
This creates a range from three to eight, including eight itself. If you want a
half-inclusive range, use `...`:
:::wren
4...6
This creates a range from four to six *not* including six itself. Ranges are
commonly used for [iterating](control-flow.html#for-statements) over a
sequences of numbers, but are useful in other places too. You can pass them to
a [list](lists.html)'s subscript operator to return a subset of the list, for
example:
:::wren
var list = ["a", "b", "c", "d", "e"]
var slice = list[1..3]
System.print(slice) // ["b", "c", "d"]
Their class is [Range](core/range.html).
## Null
Wren has a special value `null`, which is the only instance of the class
[Null](core/null.html). (Note the difference in case.) It functions a bit like
`void` in some languages: it indicates the absence of a value. If you call a
method that doesn't return anything and get its returned value, you get `null`
back.

View File

@ -0,0 +1,70 @@
^title Variables
^category language
Variables are named slots for storing values. You define a new variable in Wren
using a `var` statement, like so:
:::wren
var a = 1 + 2
This creates a new variable `a` in the current scope and initializes it with
the result of the expression following the `=`. Once a variable has been
defined, it can be accessed by name as you would expect.
:::wren
var animal = "Slow Loris"
System.print(animal) // Prints "Slow Loris".
## Scope
Wren has true block scope: a variable exists from the point where it is defined
until the end of the [block](syntax.html#blocks) where that definition appears.
:::wren
{
System.print(a) // ERROR! a doesn't exist yet.
var a = 123
System.print(a) // "123"
}
System.print(a) // ERROR! a doesn't exist anymore.
Variables defined at the top level of a script are *top-level* and are visible
to the [module](modules.html) system. All other variables are *local*.
Declaring a variable in an inner scope with the same name as an outer one is
called *shadowing* and is not an error (although it's not something you likely
intend to do much).
:::wren
var a = "outer"
{
var a = "inner"
System.print(a) // Prints "inner".
}
System.print(a) // Prints "outer".
Declaring a variable with the same name in the *same* scope *is* an error.
:::wren
var a = "hi"
var a = "again" // ERROR!
## Assignment
After a variable has been declared, you can assign to it using `=`:
:::wren
var a = 123
a = 234
An assignment walks up the scope stack to find where the named variable is
declared. It's an error to assign to a variable that isn't defined. Wren
doesn't roll with implicit variable definition.
When used in a larger expression, an assignment expression evaluates to the
assigned value.
:::wren
var a = "before"
System.print(a = "after") // Prints "after".
**TODO: Top-level names.**

View File

@ -1,203 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Calling C from Wren &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="embedding">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>embedding</h2>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><h2>embedding</h2></td>
<td><h2>?</h2></td>
<td><h2>?</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Calling C from Wren</h1>
<p>When we are ensconced within the world of Wren, the external C world is
&ldquo;foreign&rdquo; to us. There are two reasons we might want to bring some foreign
flavor into our VM:</p>
<ul>
<li>We want to execute code written in C.</li>
<li>We want to store raw C data.</li>
</ul>
<p>Since Wren is object-oriented, behavior lives in methods, so for the former we
have <strong>foreign methods</strong>. Likewise, data lives in objects, so for the latter, we
define <strong>foreign classes</strong>. This page is about the first, foreign methods. The
<a href="/embedding/storing-c-data.html">next page</a> covers foreign classes.</p>
<p>A foreign method looks to Wren like a regular method. It is defined on a Wren
class, it has a name and signature, and calls to it are dynamically dispatched.
The only difference is that the <em>body</em> of the method is written in C.</p>
<p>A foreign method is declared in Wren like so:</p>
<pre class="snippet">
class Math {
foreign static add(a, b)
}
</pre>
<p>The <code>foreign</code> keyword tells Wren that the method <code>add()</code> is declared on <code>Math</code>,
but implemented in C. Both static and instance methods can be foreign.</p>
<h2>Binding Foreign Methods <a href="#binding-foreign-methods" name="binding-foreign-methods" class="header-anchor">#</a></h2>
<p>When you call a foreign method, Wren needs to figure out which C function to
execute. This process is called <em>binding</em>. Binding is performed on-demand by the
VM. When a class that declares a foreign method is executed &ndash; when the <code>class</code>
statement itself is evaluated &ndash; the VM asks the host application for the C
function that should be used for the foreign method.</p>
<p>It does this through the <code>bindForeignMethodFn</code> callback you give it when you
first <a href="configuring-the-vm.html">configure the VM</a>. This callback isn&rsquo;t the foreign method itself.
It&rsquo;s the binding function your app uses to <em>look up</em> foreign methods.</p>
<p>Its signature is:</p>
<pre class="snippet" data-lang="c">
WrenForeignMethodFn bindForeignMethodFn(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature);
</pre>
<p>Every time a foreign method is first declared, the VM invokes this callback. It
passes in the module containing the class declaration, the name of the class
containing the method, the method&rsquo;s signature, and whether or not it&rsquo;s a static
method. In the above example, it would pass something like:</p>
<pre class="snippet" data-lang="c">
bindForeignMethodFn(vm, "main", "Math", true, "add(_,_)");
</pre>
<p>When you configure the VM, you give it a C callback that looks up the
appropriate function for the given foreign method and returns a pointer to it.
Something like:</p>
<pre class="snippet" data-lang="c">
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature)
{
if (strcmp(module, "main") == 0)
{
if (strcmp(className, "Math") == 0)
{
if (isStatic && strcmp(signature, "add(_,_)") == 0)
{
return mathAdd; // C function for Math.add(_,_).
}
// Other foreign methods on Math...
}
// Other classes in main...
}
// Other modules...
}
</pre>
<p>This implementation is pretty tedious, but you get the idea. Feel free to do
something more clever here in your host application.</p>
<p>The important part is that it returns a pointer to a C function to use for that
foreign method. Wren does this binding step <em>once</em> when the class definition is
first executed. It then keeps the function pointer you return and associates it
with that method. This way, <em>calls</em> to the foreign method are fast.</p>
<h2>Implementing a Foreign Method <a href="#implementing-a-foreign-method" name="implementing-a-foreign-method" class="header-anchor">#</a></h2>
<p>All C functions for foreign methods have the same signature:</p>
<pre class="snippet" data-lang="c">
void foreignMethod(WrenVM* vm);
</pre>
<p>Arguments passed from Wren are not passed as C arguments, and the method&rsquo;s
return value is not a C return value. Instead &ndash; you guessed it &ndash; we go through
the <a href="/embedding/slots-and-handles.html">slot array</a>.</p>
<p>When a foreign method is called from Wren, the VM sets up the slot array with
the receiver and arguments to the call. As in calling Wren from C, the receiver
object is in slot zero, and arguments are in consecutive slots after that.</p>
<p>You use the slot API to read those arguments, and then perform whatever work you
want to in C. If you want the foreign method to return a value, place it in slot
zero. Like so:</p>
<pre class="snippet" data-lang="c">
void mathAdd(WrenVM* vm)
{
double a = wrenGetSlotDouble(vm, 1);
double b = wrenGetSlotDouble(vm, 2);
wrenSetSlotDouble(vm, 0, a + b);
}
</pre>
<p>While your foreign method is executing, the VM is completely suspended. No other
fibers run until your foreign method returns. You should <em>not</em> try to resume the
VM from within a foreign method by calling <code>wrenCall()</code> or <code>wrenInterpret()</code>.
The VM is not re-entrant.</p>
<p>This covers foreign behavior, but what about foreign <em>state</em>? For that, we need
a foreign <em>class</em>&hellip;</p>
<p><a class="right" href="storing-c-data.html">Storing C Data &rarr;</a>
<a href="calling-wren-from-c.html">&larr; Calling Wren from C</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,237 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Calling Wren from C &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="embedding">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>embedding</h2>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><h2>embedding</h2></td>
<td><h2>?</h2></td>
<td><h2>?</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Calling Wren from C</h1>
<p>From C, we can tell Wren to do stuff by calling <code>wrenInterpret()</code>, but that&rsquo;s
not always the ideal way to drive the VM. First of all, it&rsquo;s slow. It has to
parse and compile the string of source code you give it. Wren has a pretty fast
compiler, but that&rsquo;s still a good bit of work.</p>
<p>It&rsquo;s also not an effective way to communicate. You can&rsquo;t pass arguments to
Wren&mdash;at least, not without doing something nasty like converting them to
literals in a string of source code&mdash;and you can&rsquo;t get a result value back.</p>
<p><code>wrenInterpret()</code> is great for loading code into the VM, but it&rsquo;s not the best
way to execute code that&rsquo;s already been loaded. What we want to do is invoke
some already compiled chunk of code. Since Wren is an object-oriented language,
&ldquo;chunk of code&rdquo; means a <a href="../method-calls.html">method</a>, not a <a href="../functions.html">function</a>.</p>
<p>The C API for doing this is <code>wrenCall()</code>. In order to invoke a Wren method from
C, we need a few things:</p>
<ul>
<li>
<p><strong>The method to call.</strong> Wren is dynamically typed, so this means we&rsquo;ll look it
up by name. Further, since Wren supports overloading by arity, we actually
need its entire <a href="../method-calls.html#signature">signature</a>.</p>
</li>
<li>
<p><strong>The receiver object to invoke the method on.</strong> The receiver&rsquo;s class
determines which method is actually called.</p>
</li>
<li>
<p><strong>The arguments to pass to the method.</strong></p>
</li>
</ul>
<p>We&rsquo;ll tackle these one at a time.</p>
<h3>Getting a Method Handle <a href="#getting-a-method-handle" name="getting-a-method-handle" class="header-anchor">#</a></h3>
<p>When you run a chunk of Wren code like this:</p>
<pre class="snippet">
object.someMethod(1, 2, 3)
</pre>
<p>At runtime, the VM has to look up the class of <code>object</code> and find a method there
whose signature is <code>someMethod(_,_,_)</code>. This sounds like it&rsquo;s doing some string
manipulation&mdash;at the very least hashing the signature&mdash;every time a
method is called. That&rsquo;s how many dynamic languages work.</p>
<p>But, as you can imagine, that&rsquo;s pretty slow. So, instead, Wren does as much of
that work at compile time as it can. When it&rsquo;s compiling the above code to
bytecode, it takes that method signature a converts it to a <em>method symbol</em>, a
number that uniquely identifes that method. That&rsquo;s the only part of the process
that requires treating a signature as a string.</p>
<p>At runtime, the VM just looks for the method <em>symbol</em> in the receiver&rsquo;s class&rsquo;s
method table. In fact, the way it&rsquo;s implemented today, the symbol is simply the
array index into the table. That&rsquo;s <a href="../performance.html">why method calls are so fast</a> in Wren.</p>
<p>It would be a shame if calling a method from C didn&rsquo;t have that same speed
benefit. To achieve that, we split the process of calling a method into two
steps. First, we create a handle that represents a &ldquo;compiled&rdquo; method signature:</p>
<pre class="snippet" data-lang="c">
WrenHandle* wrenMakeCallHandle(WrenVM* vm, const char* signature);
</pre>
<p>That takes a method signature as a string and gives you back an opaque handle
that represents the compiled method symbol. Now you have a <em>reusable</em> handle
that can be used to very quickly call a certain method given a receiver and some
arguments.</p>
<p>This is just a regular WrenHandle, which means you can hold onto it as long as
you like. Typically, you&rsquo;d call this once outside of your application&rsquo;s
performance critical loops and reuse it as long as you need. It is us up to you
to release it when you no longer need it by calling <code>wrenReleaseHandle()</code>.</p>
<h2>Setting Up a Receiver <a href="#setting-up-a-receiver" name="setting-up-a-receiver" class="header-anchor">#</a></h2>
<p>OK, we have a method, but who are we calling it on? We need a receiver, and as
you can probably guess after reading the <a href="slots-and-handles.html">last section</a>, we give that to Wren
by storing it in a slot. In particular, <strong>the receiver for a method call goes in
slot zero.</strong></p>
<p>Any object you store in that slot can be used as a receiver. You could even call
<code>+</code> on a number by storing a number in there if you felt like it.</p>
<p>Needing a receiver to call some Wren code from C might feel strange. C is
procedural, so it&rsquo;s natural to want to just invoke a bare <em>function</em> from Wren,
but Wren isn&rsquo;t procedural. Instead, if you want to define some executable
operation that isn&rsquo;t logically tied to a specific object, the natural way is to
define a static method on an appropriate class.</p>
<p>For example, say we&rsquo;re making a game engine. From C, we want to tell the game
engine to update all of the entities each frame. We&rsquo;ll keep track of the list of
entities within Wren, so from C, there&rsquo;s no obvious object to call <code>update(_)</code>
on. Instead, we&rsquo;ll just make it a static method:</p>
<pre class="snippet">
class GameEngine {
static update(elapsedTime) {
// ...
}
}
</pre>
<p>Often, when you call a Wren method from C, you&rsquo;ll be calling a static method.
But, even then, you need a receiver. Now, though, the receiver is the <em>class
itself</em>. Classes are first class objects in Wren, and when you define a named
class, you&rsquo;re really declaring a variable with the class&rsquo;s name and storing a
reference to the class object in it.</p>
<p>Assuming you declared that class at the top level, the C API <a href="slots-and-handles.html#looking-up-variables">gives you a way to
look it up</a>. We can get a handle to the above class like so:</p>
<pre class="snippet" data-lang="c">
// Load the class into slot 0.
wrenEnsureSlots(vm, 1);
wrenGetVariable(vm, "main", "GameEngine", 0);
</pre>
<p>We could do this every time we call <code>update()</code>, but, again, that&rsquo;s kind of slow
because we&rsquo;re looking up &ldquo;GameEngine&rdquo; by name each time. A faster solution is to
create a handle to the class once and use it each time:</p>
<pre class="snippet" data-lang="c">
// Load the class into slot 0.
wrenEnsureSlots(vm, 1);
wrenGetVariable(vm, "main", "GameEngine", 0);
WrenHandle* gameEngineClass = wrenGetSlotHandle(vm, 0);
</pre>
<p>Now, each time we want to call a method on GameEngine, we store that value back
in slot zero:</p>
<pre class="snippet" data-lang="c">
wrenSetSlotHandle(vm, 0, gameEngineClass);
</pre>
<p>Just like we hoisted <code>wrenMakeCallHandle()</code> out of our performance critical
loop, we can hoist the call to <code>wrenGetVariable()</code> out. Of course, if your code
isn&rsquo;t performance critical, you don&rsquo;t have to do this.</p>
<h2>Passing Arguments <a href="#passing-arguments" name="passing-arguments" class="header-anchor">#</a></h2>
<p>We&rsquo;ve got a receiver in slot zero now, next we need to pass in any other
arguments. In our GameEngine example, that&rsquo;s just the elapsed time. Method
arguments go in consecutive slots after the receiver. So the elapsed time goes
into slot one. You can use any of the slot functions to set this up. For the
example, it&rsquo;s just:</p>
<pre class="snippet" data-lang="c">
wrenSetSlotDouble(vm, 1, elapsedTime);
</pre>
<h2>Calling the Method <a href="#calling-the-method" name="calling-the-method" class="header-anchor">#</a></h2>
<p>We have all of the data in place, so all that&rsquo;s left is to pull the trigger and
tell the VM to start running some code:</p>
<pre class="snippet" data-lang="c">
WrenInterpretResult wrenCall(WrenVM* vm, WrenHandle* method);
</pre>
<p>It takes the method handle we created using <code>wrenMakeCallHandle()</code>. Now Wren
starts running code. It looks up the method on the receiver, executes it and
keeps running until either the method returns or a fiber <a href="../modules/core/fiber.html#fiber.suspend()">suspends</a>.</p>
<p><code>wrenCall()</code> returns the same WrenInterpretResult enum as <code>wrenInterpret()</code> to
tell you if the method completed successfully or a runtime error occurred.
(<code>wrenCall()</code> never returns <code>WREN_ERROR_COMPILE</code> since it doesn&rsquo;t compile
anything.)</p>
<h2>Getting the Return Value <a href="#getting-the-return-value" name="getting-the-return-value" class="header-anchor">#</a></h2>
<p>When <code>wrenCall()</code> returns, it leaves the slot array in place. In slot zero, you
can find the method&rsquo;s return value, which you can access using any of the slot
reading functions. If you don&rsquo;t need the return value, you can ignore it.</p>
<p>This is how you drive Wren from C, but how do you put control in Wren&rsquo;s hands?
For that, you&rsquo;ll need the next section&hellip;</p>
<p><a class="right" href="calling-c-from-wren.html">Calling C From Wren &rarr;</a>
<a href="slots-and-handles.html">&larr; Slots and Handles</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,272 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Configuring the VM &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="embedding">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>embedding</h2>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><h2>embedding</h2></td>
<td><h2>?</h2></td>
<td><h2>?</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Configuring the VM</h1>
<p>When you create a Wren VM, you tweak it by passing in a pointer to a
WrenConfiguration structure. Since Wren has no global state, you can configure
each VM differently if your application happens to run multiple.</p>
<p>The struct looks like:</p>
<pre class="snippet" data-lang="c">
typedef struct
{
WrenReallocateFn reallocateFn;
WrenLoadModuleFn loadModuleFn;
WrenBindForeignMethodFn bindForeignMethodFn;
WrenBindForeignClassFn bindForeignClassFn;
WrenWriteFn writeFn;
WrenErrorFn errorFn;
size_t initialHeapSize;
size_t minHeapSize;
int heapGrowthPercent;
} WrenConfiguration;
</pre>
<p>Most fields have useful defaults, which you can (and should) initialize by
calling:</p>
<pre class="snippet" data-lang="c">
wrenInitConfiguration(&configuration);
</pre>
<p>Calling this ensures that your VM doesn&rsquo;t get uninitialized configuration when
new fields are added to WrenConfiguration. Here is what each field does, roughly
categorized:</p>
<h2>Binding <a href="#binding" name="binding" class="header-anchor">#</a></h2>
<p>The VM is isolated from the outside world. These callbacks let the VM request
access to imported code and foreign functionality.</p>
<h3><strong><code>loadModuleFn</code></strong> <a href="#loadmodulefn" name="loadmodulefn" class="header-anchor">#</a></h3>
<p>This is the callback Wren uses to load an imported module. The VM itself does
not know how to talk to the file system, so when an <code>import</code> statement is
executed, it relies on the host application to locate and read the source code
for a module.</p>
<p>The signature of this function is:</p>
<pre class="snippet" data-lang="c">
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name)
</pre>
<p>When a module is imported, Wren calls this and passes in the module&rsquo;s name. The
host should return the source code for that module in a <code>WrenLoadModuleResult</code> struct.</p>
<pre class="snippet" data-lang="c">
WrenLoadModuleResult myLoadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
result.source = getSourceForModule(name);
return result;
}
</pre>
<p>The module loader is only be called once for any given module name. Wren caches
the result internally so subsequent imports of the same module use the
previously loaded code.</p>
<p>If your host application isn&rsquo;t able to load a module with some name, it should
make sure the <code>source</code> value is <code>NULL</code> when returned. Wren will then report that as a runtime error.</p>
<p>If you don&rsquo;t use any <code>import</code> statements, you can leave the <code>loadModuleFn</code> field in
the configuration set to <code>NULL</code> (the default).</p>
<p>Additionally, the <code>WrenLoadModuleResult</code> allows us to add a callback for when Wren is
done with the <code>source</code>, so we can free the memory if needed.</p>
<pre class="snippet" data-lang="c">
static void loadModuleComplete(WrenVM* vm,
const char* module,
WrenLoadModuleResult result)
{
if(result.source) {
//for example, if we used malloc to allocate
//our source string, we use free to release it.
free((void*)result.source);
}
}
WrenLoadModuleResult myLoadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
result.onComplete = loadModuleComplete;
result.source = getSourceForModule(name);
return result;
}
</pre>
<h3><strong><code>bindForeignMethodFn</code></strong> <a href="#bindforeignmethodfn" name="bindforeignmethodfn" class="header-anchor">#</a></h3>
<p>The callback Wren uses to find a foreign method and bind it to a class. See
<a href="/embedding/calling-c-from-wren.html">this page</a> for details. If your application defines no foreign
methods, you can leave this <code>NULL</code>.</p>
<h3><strong><code>bindForeignClassFn</code></strong> <a href="#bindforeignclassfn" name="bindforeignclassfn" class="header-anchor">#</a></h3>
<p>The callback Wren uses to find a foreign class and get its foreign methods. See
<a href="/embedding/storing-c-data.html">this page</a> for details. If your application defines no foreign
classes, you can leave this <code>NULL</code>.</p>
<h2>Diagnostics <a href="#diagnostics" name="diagnostics" class="header-anchor">#</a></h2>
<p>These let you wire up some minimal output so you can tell if your code is doing
what you expect.</p>
<h3><strong><code>writeFn</code></strong> <a href="#writefn" name="writefn" class="header-anchor">#</a></h3>
<p>This is the callback Wren uses to output text when <code>System.print()</code> or the other
related functions are called. This is the minimal connection the VM has with the
outside world and lets you do rudimentary &ldquo;printf debugging&rdquo;. Its signature is:</p>
<pre class="snippet" data-lang="c">
void write(WrenVM* vm, const char* text)
</pre>
<p>Wren does <em>not</em> have a default implementation for this. It&rsquo;s up to you to wire
it up to <code>printf()</code> or some other way to show the text. If you leave it <code>NULL</code>,
calls to <code>System.print()</code> and others silently do nothing.</p>
<h3><strong><code>errorFn</code></strong> <a href="#errorfn" name="errorfn" class="header-anchor">#</a></h3>
<p>Wren uses this callback to report compile time and runtime errors. Its signature
is:</p>
<pre class="snippet" data-lang="c">
void error(
WrenVM* vm,
WrenErrorType type,
const char* module,
int line,
const char* message)
</pre>
<p>The <code>type</code> parameter is one of:</p>
<pre class="snippet" data-lang="c">
typedef enum
{
// A syntax or resolution error detected at compile time.
WREN_ERROR_COMPILE,
// The error message for a runtime error.
WREN_ERROR_RUNTIME,
// One entry of a runtime error's stack trace.
WREN_ERROR_STACK_TRACE
} WrenErrorType;
</pre>
<p>When a compile error occurs, <code>errorFn</code> is called once with type
<code>WREN_ERROR_COMPILE</code>, the name of the module and line where the error occurs,
and the error message.</p>
<p>Runtime errors include stack traces. To handle this, Wren first calls <code>errorFn</code>
with <code>WREN_ERROR_RUNTIME</code>, no module or line, and the runtime error&rsquo;s message.
After that, it calls <code>errorFn</code> again using type <code>WREN_ERROR_STACK_TRACE</code>, once
for each line in the stack trace. Each of those calls has the module and line
where the method or function is defined and <code>message</code> is the name of the method
or function.</p>
<p>If you leave this <code>NULL</code>, Wren does not report any errors.</p>
<h2>Memory Management <a href="#memory-management" name="memory-management" class="header-anchor">#</a></h2>
<p>These fields control how the VM allocates and manages memory.</p>
<h3><strong><code>reallocateFn</code></strong> <a href="#reallocatefn" name="reallocatefn" class="header-anchor">#</a></h3>
<p>This lets you provide a custom memory allocation function. Its signature is:</p>
<pre class="snippet" data-lang="c">
void* reallocate(void* memory, size_t newSize, void* userData)
</pre>
<p>Wren uses this one function to allocate, grow, shrink, and deallocate memory.
When called, <code>memory</code> is the existing pointer to the block of memory if an
allocation is being changed or freed. If Wren is requesting new memory, then
<code>memory</code> is <code>NULL</code>.</p>
<p><code>newSize</code> is the number of bytes of memory being requested. If memory is being
freed, this is zero. Your callback should allocate the proper amount of memory
and return it.</p>
<p>If you don&rsquo;t provide a custom allocator, the VM uses a default one that relies
on <code>realloc</code> and <code>free</code>.</p>
<h3><strong><code>initialHeapSize</code></strong> <a href="#initialheapsize" name="initialheapsize" class="header-anchor">#</a></h3>
<p>This defines the total number of bytes of memory the VM will allocate before
triggering the first garbage collection. Setting this to a smaller number
reduces the amount of memory Wren will have allocated at one time, but causes it
to collect garbage more frequently.</p>
<p>If you set this to zero, Wren uses a default size of 10MB.</p>
<h3><strong><code>minHeapSize</code></strong> <a href="#minheapsize" name="minheapsize" class="header-anchor">#</a></h3>
<p>After a garbage collection occurs, the threshold for the <em>next</em> collection is
determined based on the number of bytes remaining in use. This allows Wren to
grow or shrink its memory usage automatically based on how much memory is
actually needed.</p>
<p>This can be used to ensure that the heap does not get <em>too</em> small, which can
in turn lead to a large number of collections afterwards as the heap grows
back to a usable size.</p>
<p>If zero, this defaults to 1MB.</p>
<h3><strong><code>heapGrowthPercent</code></strong> <a href="#heapgrowthpercent" name="heapgrowthpercent" class="header-anchor">#</a></h3>
<p>Wren tunes the rate of garbage collection based on how much memory is still in
use after a collection. This number controls that. It determines the amount of
additional memory Wren will use after a collection, as a percentage of the
current heap size.</p>
<p>For example, say that this is 50. After a garbage collection, there are 400
bytes of memory still in use. That means the next collection will be triggered
after a total of 600 bytes are allocated (including the 400 already in use.)</p>
<p>Setting this to a smaller number wastes less memory, but triggers more
frequent garbage collections.</p>
<p>If set to zero, the VM uses a default of 50.</p>
<p><a href="storing-c-data.html">&larr; Storing C Data</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,315 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Embedding &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="embedding">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>embedding</h2>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><h2>embedding</h2></td>
<td><h2>?</h2></td>
<td><h2>?</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Embedding</h1>
<p>Wren is designed to be a scripting language that lives inside a host
application, so the embedding API is as important as any of its language
features. Designing this API well requires satisfying several constraints:</p>
<ol>
<li>
<p><strong>Wren is dynamically typed, but C is not.</strong> A variable can hold a value of
any type in Wren, but that&rsquo;s definitely not the case in C unless you define
some sort of variant type, which ultimately just kicks the problem down the
road. Eventually, we have to move data across the boundary between statically and dynamically typed code.</p>
</li>
<li>
<p><strong>Wren uses garbage collection, but C manages memory manually.</strong> GC adds a
few constraints on the API. The VM must be able to find every Wren object
that is still usable, even if that object is being referenced from native C
code. Otherwise, Wren could free an object that&rsquo;s still in use.</p>
<p>Also, we ideally don&rsquo;t want to let native C code see a bare pointer to a
chunk of memory managed by Wren. Many garbage collection strategies involve
<a href="https://en.wikipedia.org/wiki/Tracing_garbage_collection#Copying_vs._mark-and-sweep_vs._mark-and-don.27t-sweep">moving objects</a> in memory. If we allow C code to point directly to an
object, that pointer will be left dangling when the object moves. Wren&rsquo;s GC
doesn&rsquo;t move objects today, but we would like to keep that option for the
future.</p>
</li>
<li>
<p><strong>The embedding API needs to be fast.</strong> Users may add layers of abstraction
on top of the API to make it more pleasant to work with, but the base API
defines the <em>maximum</em> performance you can get out of the system. It&rsquo;s the
bottom of the stack, so there&rsquo;s no way for a user to optimize around it if
it&rsquo;s too slow. There is no lower level alternative.</p>
</li>
<li>
<p><strong>We want the API to be pleasant to use.</strong> This is the last constraint
because it&rsquo;s the softest. Of course, we want a beautiful, usable API. But we
really <em>need</em> to handle the above, so we&rsquo;re willing to make things a bit more
of a chore to reach the first three goals.</p>
</li>
</ol>
<p>Fortunately, we aren&rsquo;t the first people to tackle this. If you&rsquo;re familiar with
<a href="https://www.lua.org/pil/24.html">Lua&rsquo;s C API</a>, you&rsquo;ll find Wren&rsquo;s similar.</p>
<h3>Performance and safety <a href="#performance-and-safety" name="performance-and-safety" class="header-anchor">#</a></h3>
<p>When code is safely snuggled within the confines of the VM, it&rsquo;s pretty safe.
Method calls are dynamically checked and generate runtime errors which can be
caught and handled. The stack grows if it gets close to overflowing. In general,
when you&rsquo;re within Wren code, it tries very hard to avoid crashing and burning.</p>
<p>This is why you use a high level language after all&mdash;it&rsquo;s safer and more
productive than C. C, meanwhile, really assumes you know what you&rsquo;re doing. You
can cast pointers in invalid ways, misinterpret bits, use memory after freeing
it, etc. What you get in return is blazing performance. Many of the reasons C is
fast are because it takes all the governors and guardrails off.</p>
<p>Wren&rsquo;s embedding API defines the border between those worlds, and takes on some
of the characteristics of C. When you call any of the embedding API functions,
it assumes you are calling them correctly. If you invoke a Wren method from C
that expects three arguments, it trusts that you gave it three arguments.</p>
<p>In debug builds, Wren has assertions to check as many things as it can, but in
release builds, Wren expects you to do the right thing. This means you need to
take care when using the embedding API, just like you do in all C code you
write. In return, you get an API that is quite fast.</p>
<h2>Including Wren <a href="#including-wren" name="including-wren" class="header-anchor">#</a></h2>
<p>There are two (well, three) ways to get the Wren VM into your program:</p>
<ol>
<li>
<p><strong>Link to the static or dynamic library.</strong> When you <a href="../getting-started.html">build Wren</a>, it
generates both shared and static libraries in <code>lib</code> that you can link to.</p>
</li>
<li>
<p><strong>Include the source directly in your application.</strong> If you want to include
the source directly in your program, you don&rsquo;t need to run any build steps.
Just add the source files in <code>src/vm</code> to your project. They should compile
cleanly as C99 or C++98 or anything later.</p>
</li>
</ol>
<p>In either case, you also want to add <code>src/include</code> to your include path so you
can find the <a href="https://github.com/wren-lang/wren/blob/main/src/include/wren.h">public header for Wren</a>:</p>
<pre class="snippet" data-lang="c">
#include "wren.h"
</pre>
<p>Wren depends only on the C standard library, so you don&rsquo;t usually need to link
to anything else. On some platforms (at least BSD and Linux) some of the math
functions in <code>math.h</code> are implemented in a separate library, <a href="https://en.wikipedia.org/wiki/C_mathematical_functions#libm">libm</a>, that you
have to explicitly link to.</p>
<p>If your program is in C++ but you are linking to the Wren library compiled as C,
this header handles the differences in calling conventions between C and C++:</p>
<pre class="snippet" data-lang="c">
#include "wren.hpp"
</pre>
<h2>Creating a Wren VM <a href="#creating-a-wren-vm" name="creating-a-wren-vm" class="header-anchor">#</a></h2>
<p>Once you&rsquo;ve integrated the code into your executable, you need to create a
virtual machine. To do that, you create a <code>WrenConfiguration</code> object and
initialize it.</p>
<pre class="snippet" data-lang="c">
WrenConfiguration config;
wrenInitConfiguration(&config);
</pre>
<p>This gives you a basic configuration that has reasonable defaults for
everything. We&rsquo;ll <a href="configuring-the-vm.html">learn more</a> about what you can configure later,
but for now we&rsquo;ll just add the <code>writeFn</code>, so that we can print text.</p>
<p>First we need a function that will do something with the output
that Wren sends us from <code>System.print</code> (or <code>System.write</code>). <em>Note that it doesn&rsquo;t
include a newline in the output.</em></p>
<pre class="snippet" data-lang="c">
void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
</pre>
<p>And then, we update the configuration to point to it.</p>
<pre class="snippet" data-lang="c">
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
</pre>
<p>With this ready, you can create the VM:</p>
<pre class="snippet" data-lang="c">
WrenVM* vm = wrenNewVM(&config);
</pre>
<p>This allocates memory for a new VM and initializes it. The Wren C implementation
has no global state, so every single bit of data Wren uses is bundled up inside
a WrenVM. You can have multiple Wren VMs running independently of each other
without any problems, even concurrently on different threads.</p>
<p><code>wrenNewVM()</code> stores its own copy of the configuration, so after calling it, you
can discard the WrenConfiguration struct you filled in. Now you have a live
VM, waiting to run some code!</p>
<h2>Executing Wren code <a href="#executing-wren-code" name="executing-wren-code" class="header-anchor">#</a></h2>
<p>You execute a string of Wren source code like so:</p>
<pre class="snippet" data-lang="c">
WrenInterpretResult result = wrenInterpret(
vm,
"my_module",
"System.print(\"I am running in a VM!\")");
</pre>
<p>The string is a series of one or more statements separated by newlines. Wren
copies the string, so you can free it after calling this. When you call
<code>wrenInterpret()</code>, Wren first compiles your source to bytecode. If an error
occurs, it returns immediately with <code>WREN_RESULT_COMPILE_ERROR</code>.</p>
<p>Otherwise, Wren spins up a new <a href="../concurrency.html">fiber</a> and executes the code in that. Your
code can in turn spawn whatever other fibers it wants. It keeps running fibers
until they all complete or one <a href="../modules/core/fiber.html#fiber.suspend()">suspends</a>.</p>
<p>If a <a href="../error-handling.html">runtime error</a> occurs (and another fiber doesn&rsquo;t handle it), Wren aborts
fibers all the way back to the main one and returns <code>WREN_RESULT_RUNTIME_ERROR</code>.
Otherwise, when the last fiber successfully returns, it returns
<code>WREN_RESULT_SUCCESS</code>.</p>
<p>All code passed to <code>wrenInterpret()</code> runs in a special &ldquo;main&rdquo; module. That way,
top-level names defined in one call can be accessed in later ones. It&rsquo;s similar
to a REPL session.</p>
<h2>Shutting down a VM <a href="#shutting-down-a-vm" name="shutting-down-a-vm" class="header-anchor">#</a></h2>
<p>Once the party is over and you&rsquo;re ready to end your relationship with a VM, you
need to free any memory it allocated. You do that like so:</p>
<pre class="snippet" data-lang="c">
wrenFreeVM(vm);
</pre>
<p>After calling that, you obviously cannot use the <code>WrenVM*</code> you passed to it
again. It&rsquo;s dead.</p>
<p>Note that Wren will yell at you if you still have any live <a href="slots-and-handles.html#handles">WrenHandle</a>
objects when you call this. This makes sure you haven&rsquo;t lost track of any of
them (which leaks memory) and you don&rsquo;t try to use any of them after the VM has
been freed.</p>
<h2>A complete example <a href="#a-complete-example" name="a-complete-example" class="header-anchor">#</a></h2>
<p>Below is a complete example of the above.
You can find this file in the <a href="https://github.com/wren-lang/wren/blob/main/example/embedding/main.c">example</a> folder.</p>
<pre class="snippet" data-lang="c">
//For more details, visit https://wren.io/embedding/
#include <stdio.h>
#include "wren.h"
static void writeFn(WrenVM* vm, const char* text)
{
printf("%s", text);
}
void errorFn(WrenVM* vm, WrenErrorType errorType,
const char* module, const int line,
const char* msg)
{
switch (errorType)
{
case WREN_ERROR_COMPILE:
{
printf("[%s line %d] [Error] %s\n", module, line, msg);
} break;
case WREN_ERROR_STACK_TRACE:
{
printf("[%s line %d] in %s\n", module, line, msg);
} break;
case WREN_ERROR_RUNTIME:
{
printf("[Runtime Error] %s\n", msg);
} break;
}
}
int main()
{
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* script = "System.print(\"I am running in a VM!\")";
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
{ printf("Compile Error!\n"); } break;
case WREN_RESULT_RUNTIME_ERROR:
{ printf("Runtime Error!\n"); } break;
case WREN_RESULT_SUCCESS:
{ printf("Success!\n"); } break;
}
wrenFreeVM(vm);
}
</pre>
<p>Next, we&rsquo;ll learn to make that VM do useful stuff&hellip;</p>
<p><a class="right" href="slots-and-handles.html">Slots and Handles &rarr;</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,310 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Slots and Handles &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="embedding">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>embedding</h2>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><h2>embedding</h2></td>
<td><h2>?</h2></td>
<td><h2>?</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Slots and Handles</h1>
<p>With <code>wrenInterpret()</code>, we can execute code, but that code can&rsquo;t do anything
particularly interesting. By default, the VM is isolated from the rest of the
world, so pretty much all it can do is turn your laptop into a lap warmer.</p>
<p>To make our Wren code <em>useful</em>, the VM needs to communicate with the outside
world. Wren uses a single unified set of functions for passing data into and out
of the VM. These functions are based on two fundamental concepts: <strong>slots</strong> and
<strong>handles</strong>.</p>
<h2>The Slot Array <a href="#the-slot-array" name="the-slot-array" class="header-anchor">#</a></h2>
<p>When you want to send data to Wren, read data from it, or generally monkey
around with Wren objects from C, you do so by going through an array of slots.
Think of it as a shared message board that both the VM and your C code leave
notes on for the other side to process.</p>
<p>The array is zero-based, and each slot can hold a value of any type. It is
dynamically sized, but it&rsquo;s your responsibility to ensure there are enough slots
<em>before</em> you use them. You do this by calling:</p>
<pre class="snippet" data-lang="c">
wrenEnsureSlots(WrenVM* vm, int slotCount);
</pre>
<p>This grows the slot array if needed to ensure that many slots are available. If
it&rsquo;s already big enough, this does nothing. You&rsquo;ll typically call this once
before populating the slots with data that you want to send to Wren.</p>
<pre class="snippet" data-lang="c">
wrenEnsureSlots(vm, 4);
// Can now use slots 0 through 3, inclusive.
</pre>
<p>After you ensure an array of slots, you can only rely on them being there until
you pass control back to Wren. That includes calling <code>wrenCall()</code> or
<code>wrenInterpret()</code>, or returning from a <a href="calling-c-from-wren.html">foreign method</a>.</p>
<p>If you read or write from a slot that you haven&rsquo;t ensured is valid, Wren makes
no guarantees about what will happen. I&rsquo;ve heard rumors of smoke and feathers
flying out of a user&rsquo;s computer.</p>
<p>If you want to see how big the slot array is, use:</p>
<pre class="snippet" data-lang="c">
int wrenGetSlotCount(WrenVM* vm);
</pre>
<p>It returns the number of slots in the array. Note that this may be higher than
the size you&rsquo;ve ensured. Wren reuses the memory for this array when possible,
so you may get one bigger than you need if it happened to be laying around.</p>
<p>When Wren <a href="calling-c-from-wren.html">calls your C code</a> and passes data to you, it ensures there are
enough slots for the objects it is sending you.</p>
<h3>Writing slots <a href="#writing-slots" name="writing-slots" class="header-anchor">#</a></h3>
<p>Once you have some slots, you store data in them using a number of functions all
named <code>wrenSetSlot&lt;type&gt;()</code> where <code>&lt;type&gt;</code> is the kind of data. We&rsquo;ll start with
the simple ones:</p>
<pre class="snippet" data-lang="c">
void wrenSetSlotBool(WrenVM* vm, int slot, bool value);
void wrenSetSlotDouble(WrenVM* vm, int slot, double value);
void wrenSetSlotNull(WrenVM* vm, int slot);
</pre>
<p>Each of these takes a primitive C value and converts it to the corresponding
<a href="../values.html">Wren value</a>. (Since Wren&rsquo;s <a href="../values.html#numbers">native number type</a> <em>is</em> a double, there&rsquo;s not
really much <em>conversion</em> going on, but you get the idea.)</p>
<p>You can also pass string data to Wren:</p>
<pre class="snippet" data-lang="c">
void wrenSetSlotBytes(WrenVM* vm, int slot,
const char* bytes, size_t length);
void wrenSetSlotString(WrenVM* vm, int slot,
const char* text);
</pre>
<p>Both of these copy the bytes into a new <a href="../values.html#strings">String</a> object managed by Wren&rsquo;s
garbage collector, so you can free your copy of it after you call this. The
difference between the two is that <code>wrenSetSlotBytes()</code> takes an explicit
length. Since Wren strings may contain arbitrary byte values, including the null
byte, this lets you pass those in. It&rsquo;s also a little faster to use this for
regular strings if you happen to know the length. The latter calculates the
length of the string using <code>strlen()</code>.</p>
<h3>Reading slots <a href="#reading-slots" name="reading-slots" class="header-anchor">#</a></h3>
<p>You can, of course, also pull data out of slots. Here are the simple ones:</p>
<pre class="snippet" data-lang="c">
bool wrenGetSlotBool(WrenVM* vm, int slot);
double wrenGetSlotDouble(WrenVM* vm, int slot);
</pre>
<p>These take a Wren value of the corresponding type and convert it to its raw C
representation. For strings, we have:</p>
<pre class="snippet" data-lang="c">
const char* wrenGetSlotString(WrenVM* vm, int slot);
const char* wrenGetSlotBytes(WrenVM* vm, int slot,
int* length);
</pre>
<p>These return a pointer to the first byte of the string. If you want to know the
length, the latter stores it in the variable pointed to by <code>length</code>. Both of
these return a direct pointer to the bytes managed by Wren. You should not hold
on to this pointer for long. Wren does not promise that it won&rsquo;t move or free
the data.</p>
<p>With these functions, you are going from dynamically typed Wren data to
statically typed C. It&rsquo;s up to <em>you</em> to ensure that you read a value as the
correct type. If you read a number from a slot that currently holds a string,
you&rsquo;re gonna have a bad time.</p>
<p>Fortunately, you usually know what type of data you have in a slot. If not, you
can ask:</p>
<pre class="snippet" data-lang="c">
WrenType wrenGetSlotType(WrenVM* vm, int slot);
</pre>
<p>This returns an enum defining what type of value is in the slot. It only covers
the primitive values that are supported by the C API. Things like ranges and
instances of classes come back as <code>WREN_TYPE_UNKNOWN</code>. If you want to move that
kind of data between Wren and C, you&rsquo;ll have to pull the object apart into
simple primitive values first or use a <a href="storing-c-data.html">foreign class</a>.</p>
<h3>Looking up variables <a href="#looking-up-variables" name="looking-up-variables" class="header-anchor">#</a></h3>
<p>There are a few other utility functions that move data into and out of slots.
Here&rsquo;s the first:</p>
<pre class="snippet" data-lang="c">
void wrenGetVariable(WrenVM* vm, const char* module,
const char* name, int slot);
</pre>
<p>This looks up a top level variable with the given name in the module with the
given name and stores its value in the given slot. Note that classes are just
objects stored in variables too, so you can use this to look up a class by its
name. Handy for calling static methods on it.</p>
<p>Like any method that works with strings, this one is a bit slow. It has to hash
the name and look it up in the module&rsquo;s string table. You might want to avoid
calling this in the middle of a hot loop where performance is critical. Instead,
it&rsquo;s faster to look up the variable once outside the loop and store a reference
to the object using a <a href="#handles">handle</a>.</p>
<h3>Working with lists <a href="#working-with-lists" name="working-with-lists" class="header-anchor">#</a></h3>
<p>The slot array is fine for moving a fixed number of objects between Wren and
C, but sometimes you need to shuttle a larger or dynamically-sized ball of
stuff. <a href="../lists.html">List objects</a> work well for that, so the C API lets you work
with them directly.</p>
<p>You can create a new empty list from C using:</p>
<pre class="snippet" data-lang="c">
void wrenSetSlotNewList(WrenVM* vm, int slot);
</pre>
<p>It stores the resulting list in the given slot. If you have a list in a
slot&mdash;either one you created from C or from Wren&mdash;you can add elements
to it using:</p>
<pre class="snippet" data-lang="c">
void wrenInsertInList(WrenVM* vm, int listSlot, int index,
int elementSlot);
</pre>
<p>That&rsquo;s a lot of int parameters:</p>
<ul>
<li>
<p><code>listSlot</code> is the slot where the list object is stored. That&rsquo;s the list you&rsquo;ll
be modifying. If you created the list from C, it will be the slot you passed
to <code>wrenSetSlotNewList()</code>.</p>
</li>
<li>
<p><code>index</code> is the index within the list where you want to insert the element.
Just like from within Wren, you can use a negative number to count back from
the end, so <code>-1</code> appends to the list.</p>
</li>
<li>
<p><code>elementSlot</code> identifies the slot where the value you want to insert in the
list can be found.</p>
</li>
</ul>
<p>This API means getting a value from C into a list is a two step operation. First
you move the value into a slot, then you take it from the slot and insert it in
the list. This is kind of tedious, but it lets us use the same set of functions
for moving values into slots of each primitive type. Otherwise, we&rsquo;d need
<code>wrenInsertInListDouble()</code>, <code>wrenInsertInListBool()</code>, etc.</p>
<h2>Handles <a href="#handles" name="handles" class="header-anchor">#</a></h2>
<p>Slots are pretty good for shuttling primitive data between C and Wren, but they
have two limitations:</p>
<ol>
<li>
<p><strong>They are short-lived.</strong> As soon as you execute some more Wren code, the
slot array is invalidated. You can&rsquo;t use a slot to persistently keep track
of some object.</p>
</li>
<li>
<p><strong>They only support primitive types.</strong> A slot can hold a value of any type,
but the C API we&rsquo;ve seen so far doesn&rsquo;t let you <em>do</em> anything with values
that aren&rsquo;t simple primitive ones. If you want to grab a reference to,
say, an instance of some class, how do you do it?</p>
</li>
</ol>
<p>To address those, we have handles. A handle wraps a reference to an object of
any kind&mdash;strings, numbers, instances of classes, collections, whatever.
You create a handle using this:</p>
<pre class="snippet" data-lang="c">
WrenHandle* wrenGetSlotHandle(WrenVM* vm, int slot);
</pre>
<p>This takes the object stored in the given slot, creates a new WrenHandle to wrap
it, and returns a pointer to it back to you. You can send that wrapped object
back to Wren by calling:</p>
<pre class="snippet" data-lang="c">
void wrenSetSlotHandle(WrenVM* vm, int slot, WrenHandle* handle);
</pre>
<p>Note that this doesn&rsquo;t invalidate your WrenHandle. You can still keep using it.</p>
<h3>Retaining and releasing handles <a href="#retaining-and-releasing-handles" name="retaining-and-releasing-handles" class="header-anchor">#</a></h3>
<p>A handle is an opaque wrapper around an object of any type, but just as
important, it&rsquo;s a <em>persistent</em> one. When Wren gives you a pointer to a
WrenHandle, it guarantees that that pointer remains valid. You can keep it
around as long as you want. Even if a garbage collection occurs, Wren will
ensure the handle and the object it wraps are kept safely in memory.</p>
<p>Internally, Wren keeps a list of all of the WrenHandles that have been created.
That way, during garbage collection, it can find them all and make sure their
objects aren&rsquo;t freed. But what if you don&rsquo;t want it to be kept around any more?
Since C relies on manual memory management, WrenHandle does too. When you are
done with one, you must explicitly release it by calling:</p>
<pre class="snippet" data-lang="c">
void wrenReleaseHandle(WrenVM* vm, WrenHandle* handle);
</pre>
<p>This does not immediately delete the wrapped object&mdash;after all, there may
be other references to the same object in the program. It just invalidates the
WrenHandle wrapper itself. After you call this, you cannot use that pointer
again.</p>
<p>You must release every WrenHandle you&rsquo;ve created before shutting down the VM.
Wren warns you if you don&rsquo;t, since it implies you&rsquo;ve probably leaked a resource
somewhere.</p>
<p>Now we know how to pass values between Wren and C, but we don&rsquo;t know how to
actually <em>do</em> anything with them. Next, we&rsquo;ll learn how to use slots to pass
parameters to a Wren method from C&hellip;</p>
<p><a class="right" href="calling-wren-from-c.html">Calling Wren from C &rarr;</a>
<a href="index.html">&larr; Introduction</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,421 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Storing C Data &ndash; Wren</title>
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top" class="embedding">
<header>
<div class="page">
<div class="main-column">
<h1><a href="../">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="../"><img src="../wren.svg" class="logo"></a>
<ul>
<li><a href="../">Back to Wren</a></li>
</ul>
<section>
<h2>embedding</h2>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><h2>embedding</h2></td>
<td><h2>?</h2></td>
<td><h2>?</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="./">Introduction</a></li>
<li><a href="slots-and-handles.html">Slots and Handles</a></li>
<li><a href="calling-wren-from-c.html">Calling Wren from C</a></li>
<li><a href="calling-c-from-wren.html">Calling C from Wren</a></li>
<li><a href="storing-c-data.html">Storing C Data</a></li>
<li><a href="configuring-the-vm.html">Configuring the VM</a></li>
</ul>
</td>
<td>
<ul>
</ul>
</td>
<td>
<ul>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>Storing C Data</h1>
<p>An embedded language often needs to work with native data. You may want a
pointer to some memory managed in the C heap, or maybe you want to store a chunk
of data more efficiently than Wren&rsquo;s dynamism allows. You may want a Wren object
that represents a native resource like a file handle or database connection.</p>
<p>For those cases, you can define a <strong>foreign class</strong>, a chimera whose state is
half Wren and half C. It is a real Wren class with a name, constructor, and
methods. You can define methods on it written in Wren, or <a href="calling-c-from-wren.html">foreign methods</a>
written in C. It produces real Wren objects that you can pass around, do <code>is</code>
checks on, etc. But it also wraps a blob of raw memory that is opaque to Wren
but accessible from C.</p>
<h2>Defining a Foreign Class <a href="#defining-a-foreign-class" name="defining-a-foreign-class" class="header-anchor">#</a></h2>
<p>You define one like so:</p>
<pre class="snippet">
foreign class Point {
// ...
}
</pre>
<p>The <code>foreign</code> keyword tells Wren to loop in the host application when it
constructs instances of the class. The host tells Wren how many bytes of extra
memory the foreign instance should contain and in return, Wren gives the host
the opportunity to initialize that data.</p>
<p>To talk to the host app, Wren needs a C function it can call when it constructs
an instance of the foreign class. This function is found through a binding
process similar to <a href="calling-c-from-wren.html#binding-foreign-methods">how foreign methods are bound</a>. When you <a href="configuring-the-vm.html">configure
the VM</a>, you set the <code>bindForeignClassFn</code> field in WrenConfiguration to point
to a C callback you define. Its signature must be:</p>
<pre class="snippet" data-lang="c">
WrenForeignClassMethods bindForeignClass(
WrenVM* vm, const char* module, const char* className);
</pre>
<p>Wren invokes this callback once when a foreign class declaration is executed.
Wren passes in the name of the module containing the foreign class, and the name
of the class being declared. The host&rsquo;s responsibility is to return one of these
structs:</p>
<pre class="snippet" data-lang="c">
typedef struct
{
WrenForeignMethodFn allocate;
WrenFinalizerFn finalize;
} WrenForeignClassMethods;
</pre>
<p>It&rsquo;s a pair of function pointers. The first, <code>allocate</code>, is called by Wren
whenever an instance of the foreign class is created. (We&rsquo;ll get to the optional
<code>finalize</code> callback later.) The allocation callback has the same signature as a
foreign method:</p>
<pre class="snippet" data-lang="c">
void allocate(WrenVM* vm);
</pre>
<h2>Initializing an Instance <a href="#initializing-an-instance" name="initializing-an-instance" class="header-anchor">#</a></h2>
<p>When you create an instance of a foreign class by calling one its
<a href="../classes.html#constructors">constructors</a>, Wren invokes the <code>allocate</code> callback you gave it when binding
the foreign class. Your primary responsibility in that callback is to tell Wren
how many bytes of raw memory you need. You do that by calling:</p>
<pre class="snippet" data-lang="c">
void* wrenSetSlotNewForeign(WrenVM* vm,
int slot, int classSlot, size_t size);
</pre>
<p>Like other <a href="slots-and-handles.html">slot manipulation functions</a>, it both reads from and writes to
the slot array. It has a few parameters to make it more general purpose since it
can also be used in other foreign methods:</p>
<ul>
<li>
<p>The <code>slot</code> parameter is the destination slot where the new foreign object
should be placed. When you&rsquo;re calling this in a foreign class&rsquo;s allocate
callback, this should be 0.</p>
</li>
<li>
<p>The <code>classSlot</code> parameter is the slot where the foreign class being
constructed can be found. When the VM calls an allocate callback for a
foreign class, the class itself is already in slot 0, so you&rsquo;ll pass 0 for
this too.</p>
</li>
<li>
<p>Finally, the <code>size</code> parameter is the interesting one. Here, you pass in the
number of extra raw bytes of data you want the foreign instance to store.
This is the memory you get to play with from C.</p>
</li>
</ul>
<p>So, for example, if you wanted to create a foreign instance that contains eight
bytes of C data, you&rsquo;d call:</p>
<pre class="snippet" data-lang="c">
void* data = wrenSetSlotNewForeign(vm, 0, 0, 8);
</pre>
<p>The value returned by <code>wrenSetSlotNewForeign()</code> is the raw pointer to the
requested bytes. You can cast that to whatever C type makes sense (as long as it
fits within the requested number of bytes) and initialize it as you see fit.</p>
<p>Any parameters passed to the constructor are also available in subsequent slots
in the slot array. That way you can initialize the foreign data based on values
passed to the constructor from Wren.</p>
<p>After the allocate callback returns, the class&rsquo;s constructor in Wren is run and
execution proceeds like normal. From here on out, within Wren, it appears you
have a normal instance of a class. It just happens to have some extra bytes
hiding inside it that can be accessed from foreign methods.</p>
<h2>Accessing Foreign Data <a href="#accessing-foreign-data" name="accessing-foreign-data" class="header-anchor">#</a></h2>
<p>Typically, the way you make use of the data stored in an instance of a foreign
class is through other foreign methods. Those are usually defined on the same
foreign class, but can be defined on other classes as well. Wren doesn&rsquo;t care.</p>
<p>Once you have a foreign instance in a slot, you can access the raw bytes it
stores by calling:</p>
<pre class="snippet" data-lang="c">
void* wrenGetSlotForeign(WrenVM* vm, int slot);
</pre>
<p>You pass in the slot index containing the foreign object and it gives you back a
pointer to the raw memory the object wraps. As usual, the C API doesn&rsquo;t do any
type or bounds checking, so it&rsquo;s on you to make sure the object in that slot
actually <em>is</em> an instance of a foreign class and contains as much memory as you
access.</p>
<p>Given that void pointer, you can now freely read and modify the data it points
to. They&rsquo;re your bits, Wren just holds them for you.</p>
<h2>Freeing Resources <a href="#freeing-resources" name="freeing-resources" class="header-anchor">#</a></h2>
<p>If your foreign instances are just holding memory and you&rsquo;re OK with Wren&rsquo;s
garbage collector managing the lifetime of that memory, then you&rsquo;re done. Wren
will keep the bytes around as long as there is still a reference to them. When
the instance is no longer reachable, eventually the garbage collector will do
its thing and free the memory.</p>
<p>But, often, your foreign data refers to some resource whose lifetime needs to
be explicitly managed. For example, if you have a foreign object that wraps an
open file handle, you need to ensure that handle doesn&rsquo;t get left open when the
GC frees the foreign instance.</p>
<p>Of course, you can (and usually should) add a method on your foreign class, like
<code>close()</code> so the user can explicitly release the resource managed by the object.
But if they forget to do that and the object is no longer reachable, you want to
make sure the resource isn&rsquo;t leaked.</p>
<p>To that end, you can also provide a <em>finalizer</em> function when binding the
foreign class. That&rsquo;s the other callback in the WrenForeignClassMethods struct.
If you provide that callback, then Wren will invoke it when an instance of your
foreign class is about to be freed by the garbage collector. This gives you one
last chance to clean up the object&rsquo;s resources.</p>
<p>Because this is called during the middle of a garbage collection, you do not
have unfettered access to the VM. It&rsquo;s not like a normal foreign method where
you can monkey around with slots and other stuff. Doing that while the GC is
running could leave Wren in a weird state.</p>
<p>Instead, the finalize callback&rsquo;s signature is only:</p>
<pre class="snippet" data-lang="c">
void finalize(void* data);
</pre>
<p>Wren gives you the pointer to your foreign function&rsquo;s memory, and that&rsquo;s it. The
<em>only</em> thing you should do inside a finalizer is release any external resources
referenced by that memory.</p>
<h2>A Full Example <a href="#a-full-example" name="a-full-example" class="header-anchor">#</a></h2>
<p>That&rsquo;s a lot to take in, so let&rsquo;s walk through a full example of a foreign class
with a finalizer and a couple of methods. We&rsquo;ll do a File class that wraps the
C standard file API.</p>
<p>In Wren, the class we want looks like this:</p>
<pre class="snippet">
foreign class File {
construct create(path) {}
foreign write(text)
foreign close()
}
</pre>
<p>So you can create a new file given a path. Once you have one, you can write to
it and then explicitly close it if you want. We also need to make sure the file
gets closed if the user forgets to and the GC cleans up the object.</p>
<h3>Setting up the VM <a href="#setting-up-the-vm" name="setting-up-the-vm" class="header-anchor">#</a></h3>
<p>Over in the host, first we&rsquo;ll set up the VM:</p>
<pre class="snippet" data-lang="c">
#include "wren.h"
int main(int argc, const char* argv[])
{
WrenConfiguration config;
wrenInitConfiguration(&config);
config.bindForeignClassFn = bindForeignClass;
config.bindForeignMethodFn = bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
wrenInterpret(vm, "my_module", "some code...");
return 0;
}
</pre>
<h3>Binding the foreign class <a href="#binding-the-foreign-class" name="binding-the-foreign-class" class="header-anchor">#</a></h3>
<p>We give the VM two callbacks. The first is for wiring up the foreign class
itself:</p>
<pre class="snippet" data-lang="c">
WrenForeignClassMethods bindForeignClass(
WrenVM* vm, const char* module, const char* className)
{
WrenForeignClassMethods methods;
if (strcmp(className, "File") == 0)
{
methods.allocate = fileAllocate;
methods.finalize = fileFinalize;
}
else
{
// Unknown class.
methods.allocate = NULL;
methods.finalize = NULL;
}
return methods;
}
</pre>
<p>When our binding callback is invoked for the File class, we return the allocate
and finalize functions the VM should call. Allocation looks like:</p>
<pre class="snippet" data-lang="c">
#include &lt;stdio.h>
#include "wren.h"
void fileAllocate(WrenVM* vm)
{
FILE** file = (FILE**)wrenSetSlotNewForeign(vm,
0, 0, sizeof(FILE*));
const char* path = wrenGetSlotString(vm, 1);
*file = fopen(path, "w");
}
</pre>
<p>First we create the instance by calling <code>wrenSetSlotNewForeign()</code>. We tell it to
add enough extra bytes to store a <code>FILE*</code> in it, which is C&rsquo;s representation of
a file handle. We&rsquo;re given back a pointer to the bytes. Since the file handle is
itself a pointer, we end up with a double indirection, hence the <code>FILE**</code>. In
most cases, you&rsquo;ll just have a single <code>*</code>.</p>
<p>We also pull the file path from the slot array. Then we tell C to create a new
file at that path. That gives us back a new file handle &ndash; a <code>FILE*</code> &ndash; and we
store that back into the foreign instance using <code>*file</code>. Now we have a foreign
object that wraps an open file handle.</p>
<p>The finalizer simply casts the foreign instance&rsquo;s data back to the proper type
and closes the file:</p>
<pre class="snippet" data-lang="c">
void fileFinalize(void* data)
{
closeFile((FILE**) data);
}
</pre>
<p>It uses this little utility function:</p>
<pre class="snippet" data-lang="c">
static void closeFile(FILE** file)
{
// Already closed.
if (*file == NULL) return;
fclose(*file);
*file = NULL;
}
</pre>
<p>This closes the file (if it&rsquo;s not already closed) and also nulls out the file
handle so that we don&rsquo;t try to use the file after it&rsquo;s been closed.</p>
<h3>Binding the foreign methods <a href="#binding-the-foreign-methods" name="binding-the-foreign-methods" class="header-anchor">#</a></h3>
<p>That&rsquo;s the foreign <em>class</em> part. Now we have a couple of foreign <em>methods</em> to
handle. The host tells the VM how to find them by giving Wren a pointer to this
function:</p>
<pre class="snippet" data-lang="c">
WrenForeignMethodFn bindForeignMethod(WrenVM* vm, const char* module,
const char* className, bool isStatic, const char* signature)
{
if (strcmp(className, "File") == 0)
{
if (!isStatic && strcmp(signature, "write(_)") == 0)
{
return fileWrite;
}
if (!isStatic && strcmp(signature, "close()") == 0)
{
return fileClose;
}
}
// Unknown method.
return NULL;
}
</pre>
<p>When Wren calls this, we look at the class and method name to figure out which
method it&rsquo;s binding, and then return a pointer to the appropriate function. The
foreign method for writing to the file is:</p>
<pre class="snippet" data-lang="c">
void fileWrite(WrenVM* vm)
{
FILE** file = (FILE**)wrenGetSlotForeign(vm, 0);
// Make sure the file is still open.
if (*file == NULL)
{
wrenSetSlotString(vm, 0, "Cannot write to a closed file.");
wrenAbortFiber(vm, 0);
return;
}
const char* text = wrenGetSlotString(vm, 1);
fwrite(text, sizeof(char), strlen(text), *file);
}
</pre>
<p>We use <code>wrenGetSlotForeign()</code> to pull the foreign data out of the slot array.
Since this method is called on the file itself, the foreign object is in slot
zero. We take the resulting pointer and cast it to a pointer of the proper type.
Again, because our foreign data is <em>itself</em> a pointer, we get a pointer to a
pointer.</p>
<p>We do a little sanity checking to make sure the user isn&rsquo;t writing to a file
they already closed. If not, we call <code>fwrite()</code> to write to the file.</p>
<p>The other method is <code>close()</code> to let them explicitly close the file:</p>
<pre class="snippet" data-lang="c">
void fileClose(WrenVM* vm)
{
FILE** file = (FILE**)wrenGetSlotForeign(vm, 0);
closeFile(file);
}
</pre>
<p>It uses the same helper we defined above. And that&rsquo;s it, a complete foreign
class with a finalizer and a couple of foreign methods. In Wren, you can use it
like so:</p>
<pre class="snippet">
var file = File.create("some/path.txt")
file.write("some text")
file.close()
</pre>
<p>Pretty neat, right? The resulting class looks and feels like a normal Wren
class, but it has the functionality and much of the performance of native C
code.</p>
<p><a class="right" href="configuring-the-vm.html">Configuring the VM &rarr;</a>
<a href="calling-c-from-wren.html">&larr; Calling C from Wren</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,264 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Error Handling &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Error Handling</h2>
<p>Errors come in a few fun flavors.</p>
<h2>Syntax errors <a href="#syntax-errors" name="syntax-errors" class="header-anchor">#</a></h2>
<p>The first errors you&rsquo;re likely to run into are syntax errors. These include
simple bugs where your code doesn&rsquo;t follow the language&rsquo;s grammar, like:</p>
<pre class="snippet">
1 + * 2
</pre>
<p>Wren detects these errors as soon as it tries to read your code. When it hits
one, you get a friendly error message, like:</p>
<pre><code>[main line 1] Error on '*': Unexpected token for expression.
</code></pre>
<p>Some slightly more &ldquo;semantic&rdquo; errors fall into this bucket too. Things like
using a variable that hasn&rsquo;t been defined, or declaring two variables with the
same name in the same scope. So if you do:</p>
<pre class="snippet">
var a = "once"
var a = "twice"
</pre>
<p>Wren tells you:</p>
<pre><code>[main line 2] Error on 'a': Top-level variable is already defined.
</code></pre>
<p>Note that it does this before it executes <em>any</em> code. Unlike some other
scripting languages, Wren tries to help you find your errors as soon as
possible when it can.</p>
<p>If it starts running your code, you can be sure you don&rsquo;t have any errors
related to syntax or variable scope.</p>
<h2>Runtime errors <a href="#runtime-errors" name="runtime-errors" class="header-anchor">#</a></h2>
<p>Alas, just fixing all of the &ldquo;compile-time&rdquo; errors doesn&rsquo;t mean your code does
what you want. Your program may still have errors that can&rsquo;t be detected
statically. Since they can&rsquo;t be found until your code is run, they&rsquo;re called
&ldquo;runtime&rdquo; errors.</p>
<p>Most runtime errors come from the VM itself. They arise from code trying to
perform an operation that the VM can&rsquo;t do. The most common error is a &ldquo;method
not found&rdquo; one. If you call a method on an object and its class (and all of its
superclasses) don&rsquo;t define that method, there&rsquo;s nothing Wren can do:</p>
<pre class="snippet">
class Foo {
construct new() {}
}
var foo = Foo.new()
foo.someRandomMethod
</pre>
<p>If you run this, Wren will print:</p>
<pre><code>Foo does not implement method 'someRandomMethod'.
</code></pre>
<p>Then it stops executing code. Unlike some other languages, Wren doesn&rsquo;t keep
plugging away after a runtime error has occurred. A runtime error implies
there&rsquo;s a bug in your code and it wants to draw your attention to it. To help
you out, it prints a stack trace showing where in the code the error occurred,
and all of the method calls that led to it.</p>
<p>Another common runtime error is passing an argument of the wrong type to a
method. For example, lists are indexed using a number. If you try to pass some
other type, it&rsquo;s an error:</p>
<pre class="snippet">
var list = ["a", "b", "c"]
list["1"]
</pre>
<p>This exits with:</p>
<pre><code>Subscript must be a number or a range.
[main line 2] in (script)
</code></pre>
<p>These are the two most common kinds of runtime errors, but there are others.
Stuff like out of bounds errors on lists, calling a function with the wrong
number of arguments, etc.</p>
<h2>Handling runtime errors <a href="#handling-runtime-errors" name="handling-runtime-errors" class="header-anchor">#</a></h2>
<p>Most of the time, runtime errors indicate a bug in your code and the best
solution is to fix the bug. However, sometimes it&rsquo;s useful to be able to handle
them at, uh, runtime.</p>
<p>To keep the language simpler, Wren does not have exception handling. Instead, it
takes advantage of <a href="concurrency.html">fibers</a> for handling errors. When a runtime error occurs,
the current fiber is aborted. Normally, Wren will also abort any fibers that
invoked that one, all the way to the main fiber, and then exit the VM.</p>
<p>However, you can run a fiber using the <code>try</code> method. If a runtime error occurs
in the called fiber, the error is captured and the <code>try</code> method returns the
error message as a string.</p>
<p>For example, if you run this program:</p>
<pre class="snippet">
var fiber = Fiber.new {
123.badMethod
}
var error = fiber.try()
System.print("Caught error: " + error)
</pre>
<p>It prints:</p>
<pre><code>Caught error: Num does not implement method 'badMethod'.
</code></pre>
<p>The called fiber can no longer be used, but any other fibers can proceed as
usual. When a fiber has been aborted because of a runtime error, you can also
get the error from the fiber object. Continuing the above example:</p>
<pre class="snippet">
System.print(fiber.error)
</pre>
<p>This also prints:</p>
<pre><code>Num does not implement method 'badMethod'.
</code></pre>
<p>If you have a chain of fiber calls and a runtime error occurs, it will walk the
chain looking for a <code>try</code> call, so this can also be used to capture runtime
errors generated in fibers that are invoked by the one you called <code>try</code> on.</p>
<h2>Creating runtime errors <a href="#creating-runtime-errors" name="creating-runtime-errors" class="header-anchor">#</a></h2>
<p>Most runtime errors come from within the Wren VM, but you may want to be able
to cause your own runtime errors to occur. This can be done by calling the
<code>abort()</code> static method on <code>Fiber</code>:</p>
<pre class="snippet">
Fiber.abort("Something bad happened")
</pre>
<p>You must pass in an error message, and it must be a string.</p>
<p>If the provided message is <code>null</code>, no runtime error is raised.</p>
<h2>Failures <a href="#failures" name="failures" class="header-anchor">#</a></h2>
<p>The last flavor of errors is the highest-level one. All of the above errors
indicate <em>bugs</em>&mdash;places where the code itself is incorrect. But some
errors indicate that the code simply couldn&rsquo;t accomplish its task for
unforeseeable reasons. We&rsquo;ll call these &ldquo;failures&rdquo;.</p>
<p>Consider a program that reads in a string of input from the user and parses it
to a number. Many strings are not valid numbers, so this parsing can fail. The
only way the program could prevent that failure is by validating the string
before its parsed, but validating that a string is a number is pretty much the
same thing as parsing it.</p>
<p>For cases like this where failure can occur and the program <em>will</em> want to
handle it, fibers and <code>try()</code> are too coarse-grained to work with. Instead,
these operations will indicate failure by <em>returning</em> some sort of error
indication.</p>
<p>For example, a method for parsing a number could return a number on success and
<code>null</code> to indicate parsing failed. Since Wren is dynamically typed, it&rsquo;s easy
and natural for a method to return different types of values.</p>
<p><br><hr>
<a class="right" href="modularity.html">Modularity &rarr;</a>
<a href="concurrency.html">&larr; Concurrency</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

1
example/hello.wren Normal file
View File

@ -0,0 +1 @@
System.print("Hello, world!")

View File

@ -0,0 +1,4 @@
class Cthulu {
construct new() {}
message { "Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn" }
}

View File

@ -0,0 +1,8 @@
import "cthulu" for Cthulu
class Lovecraft {
construct new() {}
say() { Cthulu.new().message }
}
System.print(Lovecraft.new().say())

36
example/mandelbrot.wren Normal file
View File

@ -0,0 +1,36 @@
var yMin = -0.2
var yMax = 0.1
var xMin = -1.5
var xMax = -1.1
for (yPixel in 0...24) {
var y = (yPixel / 24) * (yMax - yMin) + yMin
for (xPixel in 0...80) {
var x = (xPixel / 79) * (xMax - xMin) + xMin
var pixel = " "
var x0 = x
var y0 = y
for (iter in 0...80) {
var x1 = (x0 * x0) - (y0 * y0)
var y1 = 2 * x0 * y0
// Add the seed.
x1 = x1 + x
y1 = y1 + y
x0 = x1
y0 = y1
// Stop if the point escaped.
var d = (x0 * x0) + (y0 * y0)
if (d > 4) {
pixel = " .:;+=xX$&"[(iter / 8).floor]
break
}
}
System.write(pixel)
}
System.print()
}

187
example/syntax.wren Normal file
View File

@ -0,0 +1,187 @@
// This file provides examples of syntactic constructs in wren, which is mainly
// interesting for testing syntax highlighters.
// This is a comment.
/* This is /* a nested */ comment. */
// Class definition with a toplevel name.
class SyntaxExample {
// Constructor
construct new() {
// Top-level name `IO`
System.print("I am a constructor!")
// Method calls
variables
fields()
// Block arguments
fields { block }
fields {|a, b| block }
fields(argument) { block }
fields(argument) {|a, b| block }
// Static method call
SyntaxExample.fields(1)
}
// Constructor with arguments
construct constructor(a, b) {
print(a, b)
field = a
}
// Method without arguments
variables {
// Valid local variable names.
var hi
var camelCase
var PascalCase
var abc123
var ALL_CAPS
}
// Method with empty argument list
fields() {
// Fields
_under_score = 1
_field = 2
}
// Static method with single argument
static fields(a) {
// Static field
__a = a
}
// Setter
field=(value) { _field = value }
// Method with arguments
print(a, b) { System.print(a + b) }
// Operators
+(other) { "infix + " + other }
-(other) { "infix - " + other }
*(other) { "infix * " + other }
/(other) { "infix / " + other }
%(other) { "infix \% " + other }
<(other) { "infix < " + other }
>(other) { "infix > " + other }
<=(other) { "infix <= " + other }
>=(other) { "infix >= " + other }
==(other) { "infix == " + other }
!=(other) { "infix != " + other }
&(other) { "infix & " + other }
|(other) { "infix | " + other }
! { "prefix !" }
~ { "prefix ~" }
- { "prefix -" }
}
// `class`, `is`
class ReservedWords is SyntaxExample {
reserved {
// `super`, `true`, `false`
super(true, false)
// `this`
this.foo
}
foo {
// `var`
var n = 27
// `while`, `if`, `else`
while (n != 1) if (n % 2 == 0) n = n / 2 else n = 3 * n + 1
// `for`, `in`
for (beatle in ["george", "john", "paul", "ringo"]) {
System.print(beatle)
// `break`
break
}
// `return`, `null`
return null
}
imports {
// `import`
import "hello"
// `import`, `for`
import "set" for Set
}
// `foreign`, `static`
// foreign static bar
// foreign baz(string)
// (Remove lines above to make this file compile)
}
class Literals is SyntaxExample {
booleans { true || false }
numbers {
0
1234
-5678
3.14159
1.0
-12.34
0xdeadbeef
0x1234567890ABCDEF
}
strings {
"hi there"
// Escapes:
"\0" // The NUL byte: 0.
"\"" // A double quote character.
"\\" // A backslash.
"\a" // Alarm beep. (Who uses this?)
"\b" // Backspace.
"\f" // Formfeed.
"\n" // Newline.
"\r" // Carriage return.
"\t" // Tab.
"\v" // Vertical tab.
// Unicode code points
System.print("\u0041fgdg\u0b83\u00DE") // "AஃÞ"
// Unencoded bytes
System.print("\x48\x69\x2e") // "Hi."
}
ranges {
3..8 // inclusive
4...6 // half-inclusive
}
nothing { null }
lists {
var list = [1, "banana", true]
list[0] = 5
list[1..2]
}
maps {
var stringMap = {
"George": "Harrison",
"John": "Lennon",
"Paul": "McCartney",
"Ringo": "Starr"
}
var a = 1
var weirdMap = {
true: 1,
false: 0,
null: -1,
"str": "abc",
(1..5): 10,
a: 2,
_a: 3,
__a: 4
}
}
}

View File

@ -1,332 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Functions &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Functions</h2>
<p>Like many languages today, functions in Wren are little bundles of code
you can store in a variable, or pass as an argument to a method. </p>
<p>Notice there&rsquo;s a difference between <em>function</em> and <em>method</em>.</p>
<p>Since Wren is object-oriented, most of your code will live in methods on
classes, but free-floating functions are still eminently handy. </p>
<p>Functions are objects like everything else in Wren, instances of the <code>Fn</code>
class.</p>
<h2>Creating a function <a href="#creating-a-function" name="creating-a-function" class="header-anchor">#</a></h2>
<p>To create a function, we call <code>Fn.new</code>, which takes a block to execute.
To call the function, we use <code>.call()</code> on the function instance.</p>
<pre class="snippet">
var sayHello = Fn.new { System.print("hello") }
sayHello.call() //> hello
</pre>
<p>Note that we&rsquo;ll see a shorthand syntax for creating a function below.</p>
<h2>Function parameters <a href="#function-parameters" name="function-parameters" class="header-anchor">#</a></h2>
<p>Of course, functions aren&rsquo;t very useful if you can&rsquo;t pass values to them. The
function above takes no arguments. To change that, you can provide a parameter
list surrounded by <code>|</code> immediately after the opening brace of the body.</p>
<p>To pass arguments to the function, pass them to the <code>call</code> method:</p>
<pre class="snippet">
var sayMessage = Fn.new {|recipient, message|
System.print("message for %(recipient): %(message)")
}
sayMessage.call("Bob", "Good day!")
</pre>
<p>It&rsquo;s an error to call a function with fewer arguments than its parameter list
expects. If you pass too <em>many</em> arguments, the extras are ignored.</p>
<h2>Returning values <a href="#returning-values" name="returning-values" class="header-anchor">#</a></h2>
<p>The body of a function is a <a href="syntax.html#blocks">block</a>. If it is a single
expression&mdash;more precisely if there is no newline after the <code>{</code> or
parameter list&mdash;then the function implicitly returns the value of the
expression.</p>
<p>Otherwise, the body returns <code>null</code> by default. You can explicitly return a
value using a <code>return</code> statement. In other words, these two functions do the
same thing:</p>
<pre class="snippet">
Fn.new { "return value" }
Fn.new {
return "return value"
}
</pre>
<p>The return value is handed back to you when using <code>call</code>:</p>
<pre class="snippet">
var fn = Fn.new { "some value" }
var result = fn.call()
System.print(result) //> some value
</pre>
<h2>Closures <a href="#closures" name="closures" class="header-anchor">#</a></h2>
<p>As you expect, functions are closures&mdash;they can access variables defined
outside of their scope. They will hold onto closed-over variables even after
leaving the scope where the function is defined:</p>
<pre class="snippet">
class Counter {
static create() {
var i = 0
return Fn.new { i = i + 1 }
}
}
</pre>
<p>Here, the <code>create</code> method returns the function created on its second line. That
function references a variable <code>i</code> declared outside of the function. Even after
the function is returned from <code>create</code>, it is still able to read and assign
to<code>i</code>:</p>
<pre class="snippet">
var counter = Counter.create()
System.print(counter.call()) //> 1
System.print(counter.call()) //> 2
System.print(counter.call()) //> 3
</pre>
<h2>Callable classes <a href="#callable-classes" name="callable-classes" class="header-anchor">#</a></h2>
<p>Because <code>Fn</code> is a class, and responds to <code>call()</code>, any class can respond to
<code>call()</code> and be used in place of a function. This is particularly handy when
the function is passed to a method to be called, like a callback or event.</p>
<pre class="snippet">
class Callable {
construct new() {}
call(name, version) {
System.print("called %(name) with version %(version)")
}
}
var fn = Callable.new()
fn.call("wren", "0.4.0")
</pre>
<h2>Block arguments <a href="#block-arguments" name="block-arguments" class="header-anchor">#</a></h2>
<p>Very frequently, functions are passed to methods to be called. There are
countless examples of this in Wren, like <a href="lists.html">list</a> can be filtered
using a method <code>where</code> which accepts a function:</p>
<pre class="snippet">
var list = [1, 2, 3, 4, 5]
var filtered = list.where(Fn.new {|value| value > 3 })
System.print(filtered.toList) //> [4, 5]
</pre>
<p>This syntax is a bit less fun to read and write, so Wren implements the
<em>block argument</em> concept. When a function is being passed to a method,
and is the last argument to the method, it can use a shorter syntax:
<em>just the block part</em>.</p>
<p>Let&rsquo;s use a block argument for <code>list.where</code>, it&rsquo;s the last (only) argument:</p>
<pre class="snippet">
var list = [1, 2, 3, 4, 5]
var filtered = list.where {|value| value > 3 }
System.print(filtered.toList) //> [4, 5]
</pre>
<p>We&rsquo;ve seen this before in a previous page using <code>map</code> and <code>where</code>:</p>
<pre class="snippet">
numbers.map {|n| n * 2 }.where {|n| n < 100 }
</pre>
<h2>Block argument example <a href="#block-argument-example" name="block-argument-example" class="header-anchor">#</a></h2>
<p>Let&rsquo;s look at a complete example, so we can see both ends.</p>
<p>Here&rsquo;s a fictional class for something that will call a function
when a click event is sent to it. It allows us to pass just a
function and assume the left mouse button, or to pass a button and a function.</p>
<pre class="snippet">
class Clickable {
construct new() {
_fn = null
_button = 0
}
onClick(fn) {
_fn = fn
}
onClick(button, fn) {
_button = button
_fn = fn
}
fireEvent(button) {
if(_fn && button == _button) {
_fn.call(button)
}
}
}
</pre>
<p>Now that we&rsquo;ve got the clickable class, let&rsquo;s use it.
We&rsquo;ll start by using the method that accepts just a function
because we&rsquo;re fine with it just being the default left mouse button.</p>
<pre class="snippet">
var link = Clickable.new()
link.onClick {|button|
System.print("I was clicked by button %(button)")
}
// send a left mouse click
// normally this would happen from elsewhere
link.fireEvent(0) //> I was clicked by button 0
</pre>
<p>Now let&rsquo;s try with the extra button argument:</p>
<pre class="snippet">
var contextMenu = Clickable.new()
contextMenu.onClick(1) {|button|
System.print("I was right-clicked")
}
link.fireEvent(0) //> (nothing happened)
link.fireEvent(1) //> I was right-clicked
</pre>
<p>Notice that we still pass the other arguments normally,
it&rsquo;s only the last argument that is special.</p>
<p><strong>Just a regular function</strong> </p>
<p>Block arguments are purely syntax sugar for creating a function and passing it
in one little blob of syntax. These two are equivalent:</p>
<pre class="snippet">
onClick(Fn.new { System.print("clicked") })
onClick { System.print("clicked") }
</pre>
<p>And this is just as valid:</p>
<pre class="snippet">
var onEvent = Fn.new {|button|
System.print("clicked by button %(button)")
}
onClick(onEvent)
onClick(1, onEvent)
</pre>
<p><strong>Fn.new</strong> <br />
As you may have noticed by now, <code>Fn</code> accepts a block argument for the <code>Fn.new</code>.
All the constructor does is return that argument right back to you!</p>
<p><br><hr>
<a class="right" href="classes.html">Classes &rarr;</a>
<a href="variables.html">&larr; Variables</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,190 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Getting Started &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Getting Started</h2>
<h2>Trying out the language <a href="#trying-out-the-language" name="trying-out-the-language" class="header-anchor">#</a></h2>
<p>If you&rsquo;d like to try Wren, you have a few options.</p>
<ul>
<li><strong>In your browser.</strong> You can try Wren <strong><a href="./try/">right here</a></strong>!</li>
<li><strong>On your computer.</strong> The <a href="cli">Wren CLI</a> project is a downloadable executable
to run scripts with access to file io and more. See the <a href="cli">Wren CLI docs</a>.</li>
<li><strong>Embedded in your code.</strong> See how to <a href="#embed-the-vm">build and embed Wren</a> below. <br />
And then read the <a href="embedding">embedding guide</a>!</li>
</ul>
<p>Once you have somewhere to explore, it&rsquo;s time to <a href="syntax.html">learn the
language</a>.</p>
<hr />
<h2>Embed the VM <a href="#embed-the-vm" name="embed-the-vm" class="header-anchor">#</a></h2>
<p><strong>The Wren Virtual Machine</strong> is the core of the language that executes Wren
source code. It is just a library, not a standalone application. It&rsquo;s
designed to be <a href="embedding">embedded</a> in a larger host application.</p>
<p>It has no dependencies beyond the C standard library.
You can use it as a static library, shared library, or simply compile the source into your app.</p>
<h3>Building Wren <a href="#building-wren" name="building-wren" class="header-anchor">#</a></h3>
<p>To build the Wren library, we look inside the <code>projects/</code> folder.
In here you&rsquo;ll find ready to go projects for <code>Visual Studio</code>, <code>XCode</code> and tools like <code>make</code>.</p>
<ul>
<li><strong>Windows</strong> Open <code>wren.sln</code> inside <code>projects/vs2019/</code> (or <code>vs2017</code>), hit build.</li>
<li><strong>Mac</strong> Open <code>wren.xcworkspace</code> inside <code>projects/xcode/</code>, hit build.</li>
<li><strong>Linux</strong> Run <code>make</code> inside of <code>projects/make/</code>.</li>
</ul>
<p>In each case, <strong>there will be library files generated into the root <code>lib/</code> folder</strong>. <br />
These are what you&rsquo;ll link into your project, based on your needs.</p>
<ul>
<li><strong>Static Linking</strong> <code>wren.lib</code> on Windows, <code>libwren.a</code> elsewhere.</li>
<li><strong>Dynamic Linking</strong> <code>wren.dll</code> on Windows, <code>libwren.so</code> on Linux, and <code>libwren.dylib</code> on Mac.</li>
</ul>
<p><small>
Note that the default build will also generate <code>wren_test</code> inside of <code>bin/</code>, <br />
a binary that is used to run the language tests. It can execute simple scripts.
</small></p>
<p><strong>Other platforms</strong> <br />
If your platform isn&rsquo;t explicitly supported,
it is recommended that you include the Wren source
in your project for a portable experience.</p>
<h3>Including the code in your project <a href="#including-the-code-in-your-project" name="including-the-code-in-your-project" class="header-anchor">#</a></h3>
<p><strong>all source files</strong> <br />
The alternative to building via the provided projects is to include the wren source code in your project.
Since it has no dependencies this is simple, all the code in <code>src/</code> comes along. There&rsquo;s a readme in <code>src/</code> for details.</p>
<p><strong>&lsquo;amalgamated&rsquo; build</strong> <br />
If you want an even simpler way, there&rsquo;s an &lsquo;amalgamated&rsquo; build (often called <code>blob</code>, or <code>unity</code> builds.).
This is <em>all of the wren source code in one file</em>.</p>
<p>This file can be generated by running <code>python3 util/generate_amalgamation.py &gt; build/wren.c</code>,
which saves the generated output in <code>build/wren.c</code>.</p>
<p>Include <code>build/wren.c</code> and <code>src/include/wren.h</code> in your project code and you&rsquo;re good to go.
<small>Ideally later we can automate generating this and include it in the repo.</small></p>
<hr />
<p>If you run into bugs, or have ideas or questions, any of
the following work:</p>
<ul>
<li>Join the <a href="https://discord.gg/Kx6PxSX">discord community</a>.</li>
<li>Ask on the <a href="https://groups.google.com/forum/#!forum/wren-lang">Wren mailing list</a> (which is pretty quiet).</li>
<li>Tell us on twitter at <a href="https://twitter.com/intent/user?screen_name=munificentbob">@munificentbob</a> or <a href="https://twitter.com/intent/user?screen_name=ruby0x1">@ruby0x1</a>.</li>
<li><a href="https://github.com/wren-lang/wren/issues">File a ticket</a> at <a href="https://github.com/wren-lang/wren">the GitHub repo</a>.</li>
<li>The CLI also has <a href="https://github.com/wren-lang/wren-cli/issues">tickets</a> and a <a href="https://github.com/wren-lang/wren-cli">GitHub repo</a> too.</li>
<li>Pull requests are welcome.</li>
</ul>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,180 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title> &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2></h2>
<h2>Wren is a small, fast, class-based concurrent scripting language <a href="#wren-is-a-small,-fast,-class-based-concurrent-scripting-language" name="wren-is-a-small,-fast,-class-based-concurrent-scripting-language" class="header-anchor">#</a></h2>
<hr />
<p>Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in
a familiar, modern <a href="syntax.html">syntax</a>.</p>
<pre class="snippet">
System.print("Hello, world!")
class Wren {
flyTo(city) {
System.print("Flying to %(city)")
}
}
var adjectives = Fiber.new {
["small", "clean", "fast"].each {|word| Fiber.yield(word) }
}
while (!adjectives.isDone) System.print(adjectives.call())
</pre>
<ul>
<li>
<p><strong>Wren is small.</strong> The VM implementation is under <a href="https://github.com/wren-lang/wren/tree/main/src">4,000 semicolons</a>.
You can skim the whole thing in an afternoon. It&rsquo;s <em>small</em>, but not
<em>dense</em>. It is readable and <a href="https://github.com/wren-lang/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433">lovingly-commented</a>.</p>
</li>
<li>
<p><strong>Wren is fast.</strong> A fast single-pass compiler to tight bytecode, and a
compact object representation help Wren <a href="performance.html">compete with other dynamic
languages</a>.</p>
</li>
<li>
<p><strong>Wren is class-based.</strong> There are lots of scripting languages out there,
but many have unusual or non-existent object models. Wren places
<a href="classes.html">classes</a> front and center.</p>
</li>
<li>
<p><strong>Wren is concurrent.</strong> Lightweight <a href="concurrency.html">fibers</a> are core to the execution
model and let you organize your program into a flock of communicating
coroutines.</p>
</li>
<li>
<p><strong>Wren is a scripting language.</strong> Wren is intended for embedding in
applications. It has no dependencies, a small standard library,
and <a href="embedding">an easy-to-use C API</a>. It compiles cleanly as C99, C++98
or anything later.</p>
</li>
</ul>
<hr />
<p>You can try it <a href="try">in your browser</a>! <br />
If you like the sound of this, <a href="getting-started.html">let&rsquo;s get started</a>. <br />
Excited? You&rsquo;re also welcome to <a href="contributing.html">get involved</a>!</p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,251 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Lists &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Lists</h2>
<p>A list is a compound object that holds a collection of elements identified by
integer index. You can create a list by placing a sequence of comma-separated
expressions inside square brackets:</p>
<pre class="snippet">
[1, "banana", true]
</pre>
<p>Here, we&rsquo;ve created a list of three elements. Notice that the elements don&rsquo;t
have to be the same type.</p>
<h2>Accessing elements <a href="#accessing-elements" name="accessing-elements" class="header-anchor">#</a></h2>
<p>You can access an element from a list by calling the <a href="method-calls.html#subscripts">subscript
operator</a> on it with the index of the
element you want. Like most languages, indexes start at zero:</p>
<pre class="snippet">
var trees = ["cedar", "birch", "oak", "willow"]
System.print(trees[0]) //> cedar
System.print(trees[1]) //> birch
</pre>
<p>Negative indices counts backwards from the end:</p>
<pre class="snippet">
System.print(trees[-1]) //> willow
System.print(trees[-2]) //> oak
</pre>
<p>It&rsquo;s a runtime error to pass an index outside of the bounds of the list. If you
don&rsquo;t know what those bounds are, you can find out using count:</p>
<pre class="snippet">
System.print(trees.count) //> 4
</pre>
<h2>Slices and ranges <a href="#slices-and-ranges" name="slices-and-ranges" class="header-anchor">#</a></h2>
<p>Sometimes you want to copy a chunk of elements from a list. You can do that by
passing a <a href="values.html#ranges">range</a> to the subscript operator, like so:</p>
<pre class="snippet">
System.print(trees[1..2]) //> [birch, oak]
</pre>
<p>This returns a new list containing the elements of the original list whose
indices are within the given range. Both inclusive and exclusive ranges work
and do what you expect.</p>
<p>Negative bounds also work like they do when passing a single number, so to copy
a list, you can just do:</p>
<pre class="snippet">
trees[0..-1]
</pre>
<h2>Adding elements <a href="#adding-elements" name="adding-elements" class="header-anchor">#</a></h2>
<p>Lists are <em>mutable</em>, meaning their contents can be changed. You can swap out an
existing element in the list using the subscript setter:</p>
<pre class="snippet">
trees[1] = "spruce"
System.print(trees[1]) //> spruce
</pre>
<p>It&rsquo;s an error to set an element that&rsquo;s out of bounds. To grow a list, you can
use <code>add</code> to append a single item to the end:</p>
<pre class="snippet">
trees.add("maple")
System.print(trees.count) //> 5
</pre>
<p>You can insert a new element at a specific position using <code>insert</code>:</p>
<pre class="snippet">
trees.insert(2, "hickory")
</pre>
<p>The first argument is the index to insert at, and the second is the value to
insert. All elements following the inserted one will be pushed down to
make room for it.</p>
<p>It&rsquo;s valid to &ldquo;insert&rdquo; after the last element in the list, but only <em>right</em>
after it. Like other methods, you can use a negative index to count from the
back. Doing so counts back from the size of the list <em>after</em> it&rsquo;s grown by one:</p>
<pre class="snippet">
var letters = ["a", "b", "c"]
letters.insert(3, "d") // OK: inserts at end.
System.print(letters) //> [a, b, c, d]
letters.insert(-2, "e") // Counts back from size after insert.
System.print(letters) //> [a, b, c, e, d]
</pre>
<h2>Adding lists together <a href="#adding-lists-together" name="adding-lists-together" class="header-anchor">#</a></h2>
<p>Lists have the ability to be added together via the <code>+</code> operator. This is often known as concatenation.</p>
<pre class="snippet">
var letters = ["a", "b", "c"]
var other = ["d", "e", "f"]
var combined = letters + other
System.print(combined) //> [a, b, c, d, e, f]
</pre>
<h2>Removing elements <a href="#removing-elements" name="removing-elements" class="header-anchor">#</a></h2>
<p>The opposite of <code>insert</code> is <code>removeAt</code>. It removes a single element from a
given position in the list. </p>
<p>To remove a specific <em>value</em> instead, use <code>remove</code>. The first value that
matches using regular equality will be removed.</p>
<p>In both cases, all following items are shifted up to fill in the gap.</p>
<pre class="snippet">
var letters = ["a", "b", "c", "d"]
letters.removeAt(1)
System.print(letters) //> [a, c, d]
letters.remove("a")
System.print(letters) //> [c, d]
</pre>
<p>Both the <code>remove</code> and <code>removeAt</code> method return the removed item:</p>
<pre class="snippet">
System.print(letters.removeAt(1)) //> c
</pre>
<p>If <code>remove</code> couldn&rsquo;t find the value in the list, it returns null:</p>
<pre class="snippet">
System.print(letters.remove("not found")) //> null
</pre>
<p>If you want to remove everything from the list, you can clear it:</p>
<pre class="snippet">
trees.clear()
System.print(trees) //> []
</pre>
<p><br><hr>
<a class="right" href="maps.html">Maps &rarr;</a>
<a href="values.html">&larr; Values</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

89
lzstring.min.js vendored
View File

@ -1,89 +0,0 @@
// Minified from https://github.com/microsoft/TypeScript-Website/blob/e9d8f66f6b8be2dda06737d3686dcb795749dff2/packages/sandbox/src/vendor/lzstring.min.js
// Original license reproduced below:
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//
var LZString=(function(){function o(o,r){if(!t[o]){t[o]={}
for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}
return t[o][r]}
var r=String.fromCharCode,n='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',e='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$',t={},i={compressToBase64:function(o){if(null==o)return''
var r=i._compress(o,6,function(o){return n.charAt(o)})
switch(r.length%4){default:case 0:return r
case 1:return r+'==='
case 2:return r+'=='
case 3:return r+'='}},decompressFromBase64:function(r){return null==r?'':''==r?null:i._decompress(r.length,32,function(e){return o(n,r.charAt(e))})},compressToUTF16:function(o){return null==o?'':i._compress(o,15,function(o){return r(o+32)})+' '},decompressFromUTF16:function(o){return null==o?'':''==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compressToUint8Array:function(o){for(var r=i.compress(o),n=new Uint8Array(2*r.length),e=0,t=r.length;t>e;e++){var s=r.charCodeAt(e);(n[2*e]=s>>>8),(n[2*e+1]=s%256)}
return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o)
for(var n=new Array(o.length / 2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1]
var s=[]
return(n.forEach(function(o){s.push(r(o))}),i.decompress(s.join('')))},compressToEncodedURIComponent:function(o){return null==o?'':i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?'':''==r?null:((r=r.replace(/ /g,'+')),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return''
var e,t,i,s={},p={},u='',c='',a='',l=2,f=3,h=2,d=[],m=0,v=0
for(i=0;i<o.length;i+=1)
if(((u=o.charAt(i)),Object.prototype.hasOwnProperty.call(s,u)||((s[u]=f++),(p[u]=!0)),(c=a+u),Object.prototype.hasOwnProperty.call(s,c)))
a=c
else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)(m<<=1),v==r-1?((v=0),d.push(n(m)),(m=0)):v++
for(t=a.charCodeAt(0),e=0;8>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}else{for(t=1,e=0;h>e;e++)
(m=(m<<1)|t),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t=0)
for(t=a.charCodeAt(0),e=0;16>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}
l--,0==l&&((l=Math.pow(2,h)),h++),delete p[a]}else
for(t=s[a],e=0;h>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)
l--,0==l&&((l=Math.pow(2,h)),h++),(s[c]=f++),(a=String(u))}
if(''!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)(m<<=1),v==r-1?((v=0),d.push(n(m)),(m=0)):v++
for(t=a.charCodeAt(0),e=0;8>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}else{for(t=1,e=0;h>e;e++)
(m=(m<<1)|t),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t=0)
for(t=a.charCodeAt(0),e=0;16>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}
l--,0==l&&((l=Math.pow(2,h)),h++),delete p[a]}else
for(t=s[a],e=0;h>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)
l--,0==l&&((l=Math.pow(2,h)),h++)}
for(t=2,e=0;h>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)
for(;;){if(((m<<=1),v==r-1)){d.push(n(m))
break}
v++}
return d.join('')},decompress:function(o){return null==o?'':''==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v='',w=[],A={val:e(0),position:n,index:1}
for(i=0;3>i;i+=1)f[i]=i
for(p=0,c=Math.pow(2,2),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
switch((t=p)){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
l=r(p)
break
case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
l=r(p)
break
case 2:return''}
for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return''
for(p=0,c=Math.pow(2,m),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
switch((l=p)){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1);(f[d++]=r(p)),(l=d-1),h--
break
case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1);(f[d++]=r(p)),(l=d-1),h--
break
case 2:return w.join('')}
if((0==h&&((h=Math.pow(2,m)),m++),f[l]))v=f[l]
else{if(l!==d)return null
v=s+s.charAt(0)}
w.push(v),(f[d++]=s+v.charAt(0)),h--,(s=v),0==h&&((h=Math.pow(2,m)),m++)}},}
return i})();'function'==typeof define&&define.amd?define(function(){return LZString}):'undefined'!=typeof module&&null!=module&&(module.exports=LZString)

257
maps.html
View File

@ -1,257 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Maps &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Maps</h2>
<p>A map is an <em>associative</em> collection. It holds a set of entries, each of which
maps a <em>key</em> to a <em>value</em>. The same data structure has a variety of names in
other languages: hash table, dictionary, association, table, etc.</p>
<p>You can create a map by placing a series of comma-separated entries inside
curly braces. Each entry is a key and a value separated by a colon:</p>
<pre class="snippet">
{
"maple": "Sugar Maple (Acer Saccharum)",
"larch": "Alpine Larch (Larix Lyallii)",
"oak": "Red Oak (Quercus Rubra)",
"fir": "Fraser Fir (Abies Fraseri)"
}
</pre>
<p>This creates a map that associates a type of tree (key) to a specific
tree within that family (value). Syntactically, in a map literal, keys
can be any literal, a variable name, or a parenthesized expression.
Values can be any expression. Here, we&rsquo;re using string literals for both keys
and values.</p>
<p><em>Semantically</em>, values can be any object, and multiple keys may map to the same
value. </p>
<p>Keys have a few limitations. They must be one of the immutable built-in
<a href="values.html">value types</a> in Wren. That means a number, string, range, bool, or <code>null</code>.
You can also use a <a href="classes.html">class object</a> as a key (not an instance of that class,
the actual class itself).</p>
<p>The reason for this limitation&mdash;and the reason maps are called &ldquo;<em>hash</em>
tables&rdquo; in other languages&mdash;is that each key is used to generate a numeric
<em>hash code</em>. This lets a map locate the value associated with a key in constant
time, even in very large maps. Since Wren only knows how to hash certain
built-in types, only those can be used as keys.</p>
<h2>Adding entries <a href="#adding-entries" name="adding-entries" class="header-anchor">#</a></h2>
<p>You add new key-value pairs to the map using the <a href="method-calls.html#subscripts">subscript operator</a>:</p>
<pre class="snippet">
var capitals = {}
capitals["Georgia"] = "Atlanta"
capitals["Idaho"] = "Boise"
capitals["Maine"] = "Augusta"
</pre>
<p>If the key isn&rsquo;t already present, this adds it and associates it with the given
value. If the key is already there, this just replaces its value.</p>
<h2>Looking up values <a href="#looking-up-values" name="looking-up-values" class="header-anchor">#</a></h2>
<p>To find the value associated with some key, again you use your friend the
subscript operator:</p>
<pre class="snippet">
System.print(capitals["Idaho"]) //> Boise
</pre>
<p>If the key is present, this returns its value. Otherwise, it returns <code>null</code>. Of
course, <code>null</code> itself can also be used as a value, so seeing <code>null</code> here
doesn&rsquo;t necessarily mean the key wasn&rsquo;t found.</p>
<p>To tell definitively if a key exists, you can call <code>containsKey()</code>:</p>
<pre class="snippet">
var capitals = {"Georgia": null}
System.print(capitals["Georgia"]) //> null (though key exists)
System.print(capitals["Idaho"]) //> null
System.print(capitals.containsKey("Georgia")) //> true
System.print(capitals.containsKey("Idaho")) //> false
</pre>
<p>You can see how many entries a map contains using <code>count</code>:</p>
<pre class="snippet">
System.print(capitals.count) //> 3
</pre>
<h2>Removing entries <a href="#removing-entries" name="removing-entries" class="header-anchor">#</a></h2>
<p>To remove an entry from a map, call <code>remove()</code> and pass in the key for the
entry you want to delete:</p>
<pre class="snippet">
capitals.remove("Maine")
System.print(capitals.containsKey("Maine")) //> false
</pre>
<p>If the key was found, this returns the value that was associated with it:</p>
<pre class="snippet">
System.print(capitals.remove("Georgia")) //> Atlanta
</pre>
<p>If the key wasn&rsquo;t in the map to begin with, <code>remove()</code> just returns <code>null</code>.</p>
<p>If you want to remove <em>everything</em> from the map, like with <a href="lists.html">lists</a>, you call
<code>clear()</code>:</p>
<pre class="snippet">
capitals.clear()
System.print(capitals.count) //> 0
</pre>
<h2>Iterating over the contents <a href="#iterating-over-the-contents" name="iterating-over-the-contents" class="header-anchor">#</a></h2>
<p>The subscript operator works well for finding values when you know the key
you&rsquo;re looking for, but sometimes you want to see everything that&rsquo;s in the map.
You can use a regular for loop to iterate the contents, and map exposes two
additional methods to access the contents: <code>keys</code> and <code>values</code>. </p>
<p>The <code>keys</code> method on a map returns a <a href="modules/core/sequence.html">Sequence</a> that <a href="control-flow.html#the-iterator-protocol">iterates</a> over all of
the keys in the map, and the <code>values</code> method returns one that iterates over the values.</p>
<p>Regardless of how you iterate, the <em>order</em> that things are iterated in
isn&rsquo;t defined. Wren makes no promises about what order keys and values are
iterated. All it promises is that every entry will appear exactly once.</p>
<p><strong>Iterating with for(entry in map)</strong> <br />
When you iterate a map with <code>for</code>, you&rsquo;ll be handed an <em>entry</em>, which contains
a <code>key</code> and a <code>value</code> field. That gives you the info for each element in the map.</p>
<pre class="snippet">
var birds = {
"Arizona": "Cactus wren",
"Hawaii": "Nēnē",
"Ohio": "Northern Cardinal"
}
for (bird in birds) {
System.print("The state bird of %(bird.key) is %(bird.value)")
}
</pre>
<p><strong>Iterating using the keys</strong> </p>
<p>You can also iterate over the keys and use each to look up its value:</p>
<pre class="snippet">
var birds = {
"Arizona": "Cactus wren",
"Hawaii": "Nēnē",
"Ohio": "Northern Cardinal"
}
for (state in birds.keys) {
System.print("The state bird of %(state) is " + birds[state])
}
</pre>
<p><br><hr>
<a class="right" href="method-calls.html">Method Calls &rarr;</a>
<a href="lists.html">&larr; Lists</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

View File

@ -1,288 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Method Calls &ndash; Wren</title>
<script type="application/javascript" src="prism.js" data-manual></script>
<script type="application/javascript" src="codejar.js"></script>
<script type="application/javascript" src="wren.js"></script>
<link rel="stylesheet" type="text/css" href="prism.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav class="big">
<a href="./"><img src="./wren.svg" class="logo"></a>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="blog">Blog</a></li>
<li><a href="try">Try it!</a></li>
</ul>
<section>
<h2>guides</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</section>
<section>
<h2>API docs</h2>
<ul>
<li><a href="modules">Modules</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<div><a href="getting-started.html">Getting Started</a></div>
<div><a href="contributing.html">Contributing</a></div>
<div><a href="blog">Blog</a></div>
<div><a href="try">Try it!</a></div>
</tr>
<tr>
<td colspan="2"><h2>guides</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modularity.html">Modularity</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h2>Method Calls</h2>
<p>Wren is deeply object oriented, so most code consists of invoking methods on
objects, usually something like this:</p>
<pre class="snippet">
System.print("Heyoo!") //> Heyoo!
</pre>
<p>You have a <em>receiver</em> expression (here <code>System</code>) followed by a <code>.</code>, then a name
(<code>print</code>) and an argument list in parentheses (<code>("Heyoo!")</code>). Multiple arguments
are separated by commas:</p>
<pre class="snippet">
list.insert(3, "item")
</pre>
<p>The argument list can also be empty:</p>
<pre class="snippet">
list.clear()
</pre>
<p>The VM executes a method call like so:</p>
<ol>
<li>Evaluate the receiver and arguments from left to right.</li>
<li>Look up the method on the receiver&rsquo;s <a href="classes.html">class</a>.</li>
<li>Invoke it, passing in the argument values.</li>
</ol>
<h2>Signature <a href="#signature" name="signature" class="header-anchor">#</a></h2>
<p>Unlike most other dynamically-typed languages, in Wren a class can have multiple
methods with the same <em>name</em>, as long as they have different <em>signatures</em>. The
signature includes the method&rsquo;s name along with the number of arguments it
takes. In technical terms, this means you can <em>overload by arity</em>.</p>
<p>For example, the <a href="modules/random/random.html">Random</a> class has two methods for getting a random integer.
One takes a minimum and maximum value and returns a value in that range. The
other only takes a maximum value and uses 0 as the minimum:</p>
<pre class="snippet">
var random = Random.new()
random.int(3, 10)
random.int(4)
</pre>
<p>In a language like Python or JavaScript, these would both call a single <code>int()</code>
method, which has some kind of &ldquo;optional&rdquo; parameter. The body of the method
figures out how many arguments were passed and uses control flow to handle the
two different behaviors. That means first parameter represents &ldquo;max unless
another parameter was passed, in which case it&rsquo;s min&rdquo;. </p>
<p>This type of &lsquo;variadic&rsquo; code isn&rsquo;t ideal, so Wren doesn&rsquo;t encourage it.</p>
<p>In Wren, these are calls to two entirely separate methods, <code>int(_,_)</code> and
<code>int(_)</code>. This makes it easier to define &ldquo;overloads&rdquo; like this since you don&rsquo;t
need optional parameters or any kind of control flow to handle the different
cases.</p>
<p>It&rsquo;s also faster to execute. Since we know how many arguments are passed at
compile time, we can compile this to directly call the right method and avoid
any &ldquo;if I got two arguments do this&hellip;&rdquo; runtime work.</p>
<h2>Getters <a href="#getters" name="getters" class="header-anchor">#</a></h2>
<p>Some methods exist to expose a stored or computed property of an object. These
are <em>getters</em> and have no parentheses:</p>
<pre class="snippet">
"string".count //> 6
(1..10).min //> 1
1.23.sin //> 0.9424888019317
[1, 2, 3].isEmpty //> false
</pre>
<p>A getter is <em>not</em> the same as a method with an empty argument list. The <code>()</code> is
part of the signature, so <code>count</code> and <code>count()</code> have different signatures.
Unlike Ruby&rsquo;s optional parentheses, Wren wants to make sure you call a getter
like a getter and a <code>()</code> method like a <code>()</code> method. These don&rsquo;t work:</p>
<pre class="snippet">
"string".count()
[1, 2, 3].clear
</pre>
<p>If you&rsquo;re defining some member that doesn&rsquo;t need any parameters, you need to
decide if it should be a getter or a method with an empty <code>()</code> parameter list.
The general guidelines are:</p>
<ul>
<li>If it modifies the object or has some other side effect, make it a method:</li>
</ul>
<pre class="snippet">
list.clear()
</pre>
<ul>
<li>If the method supports multiple arities, make the zero-parameter case a <code>()</code>
method to be consistent with the other versions:</li>
</ul>
<pre class="snippet">
Fiber.yield()
Fiber.yield("value")
</pre>
<ul>
<li>Otherwise, it can probably be a getter.</li>
</ul>
<h2>Setters <a href="#setters" name="setters" class="header-anchor">#</a></h2>
<p>A getter lets an object expose a public &ldquo;property&rdquo; that you can <em>read</em>.
Likewise, a <em>setter</em> lets you write to a property:</p>
<pre class="snippet">
person.height = 74 // Grew up!
</pre>
<p>Despite the <code>=</code>, this is just another syntax for a method call. From the
language&rsquo;s perspective, the above line is just a call to the <code>height=(_)</code>
method on <code>person</code>, passing in <code>74</code>.</p>
<p>Since the <code>=(_)</code> is in the setter&rsquo;s signature, an object can have both a getter
and setter with the same name without a collision. Defining both lets you
provide a read/write property.</p>
<h2>Operators <a href="#operators" name="operators" class="header-anchor">#</a></h2>
<p>Wren has most of the same operators you know and love with the same precedence
and associativity. We have three prefix operators:</p>
<pre class="snippet">
! ~ -
</pre>
<p>They are just method calls on their operand without any other arguments. An
expression like <code>!possible</code> means &ldquo;call the <code>!</code> method on <code>possible</code>&rdquo;.</p>
<p>We also have a slew of infix operators&mdash;they have operands on both sides.
They are:</p>
<pre class="snippet">
* / % + - .. ... << >> < <= > >= == != & ^ | is
</pre>
<p>Like prefix operators, they are all funny ways of writing method calls. The left
operand is the receiver, and the right operand gets passed to it. So <code>a + b</code> is
semantically interpreted as &ldquo;invoke the <code>+(_)</code> method on <code>a</code>, passing it <code>b</code>&rdquo;.</p>
<p>Note that <code>-</code> is both a prefix and an infix operator. Since they have different
signatures (<code>-</code> and <code>-(_)</code>), there&rsquo;s no ambiguity between them.</p>
<p>Most of these are probably familiar already. The <code>..</code> and <code>...</code> operators are
&ldquo;range&rdquo; operators. The number type implements those to create <a href="values.html#ranges">range</a>
objects, but they are method calls like other operators.</p>
<p>The <code>is</code> keyword is a &ldquo;type test&rdquo; operator. The base <a href="modules/core/object.html">Object</a> class implements
it to tell if an object is an instance of a given class. You&rsquo;ll rarely need to,
but you can override <code>is</code> in your own classes. That can be useful for things
like mocks or proxies where you want an object to masquerade as a certain class.</p>
<h2>Subscripts <a href="#subscripts" name="subscripts" class="header-anchor">#</a></h2>
<p>Another familiar syntax from math is <em>subscripting</em> using square brackets
(<code>[]</code>). It&rsquo;s handy for working with collection-like objects. For example:</p>
<pre class="snippet">
list[0] // Get the first item in a list.
map["key"] // Get the value associated with "key".
</pre>
<p>You know the refrain by now. In Wren, these are method calls. In the above
examples, the signature is <code>[_]</code>. Subscript operators may also take multiple
arguments, which is useful for things like multi-dimensional arrays:</p>
<pre class="snippet">
matrix[3, 5]
</pre>
<p>These examples are subscript &ldquo;getters&rdquo;, and there are also
corresponding <em>subscript setters</em>:</p>
<pre class="snippet">
list[0] = "item"
map["key"] = "value"
</pre>
<p>These are equivalent to method calls whose signature is <code>[_]=(_)</code> and whose
arguments are both the subscript (or subscripts) and the value on the right-hand
side.</p>
<p><br><hr>
<a class="right" href="control-flow.html">Control Flow &rarr;</a>
<a href="maps.html">&larr; Maps</a></p>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives
<a href="https://github.com/wren-lang/wren">on GitHub</a>
&mdash; Made with &#x2764; by
<a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and
<a href="https://github.com/wren-lang/wren/blob/main/AUTHORS">friends</a>.
</p>
<div class="main-column">
</div>
</footer>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More