From 5cac3af2f218f2b0f19245d7f5a013fa123bf4ba Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Thu, 19 Oct 2017 07:05:45 -0700 Subject: [PATCH] Fresh docs! --- classes.html | 74 ++--- community.html | 152 ---------- concurrency.html | 20 +- contributing.html | 27 +- control-flow.html | 37 +-- core-library.html | 321 --------------------- core/bool.html | 68 ----- core/class.html | 77 ----- core/fiber.html | 169 ----------- core/fn.html | 92 ------ core/index.html | 77 ----- core/list.html | 133 --------- core/map.html | 96 ------- core/null.html | 62 ---- core/num.html | 155 ---------- core/object.html | 78 ----- core/range.html | 72 ----- core/sequence.html | 178 ------------ core/string.html | 197 ------------- core/system.html | 88 ------ embedding-api.html | 218 -------------- embedding/calling-c-from-wren.html | 196 +++++++++++++ embedding/calling-wren-from-c.html | 230 +++++++++++++++ embedding/configuring-the-vm.html | 234 +++++++++++++++ embedding/index.html | 226 +++++++++++++++ embedding/slots-and-handles.html | 303 ++++++++++++++++++++ embedding/storing-c-data.html | 413 ++++++++++++++++++++++++++ error-handling.html | 33 +-- expressions.html | 414 --------------------------- fibers.html | 217 -------------- functions.html | 30 +- getting-started.html | 22 +- index.html | 8 +- lists.html | 30 +- maps.html | 25 +- method-calls.html | 32 +-- modularity.html | 30 +- modules.html | 330 --------------------- modules/core/bool.html | 2 +- modules/core/class.html | 6 +- modules/core/fiber.html | 74 +++-- modules/core/fn.html | 7 +- modules/core/list.html | 22 +- modules/core/map.html | 2 +- modules/core/null.html | 2 +- modules/core/num.html | 34 ++- modules/core/object.html | 2 +- modules/core/range.html | 12 +- modules/core/sequence.html | 29 +- modules/core/string.html | 41 ++- modules/core/system.html | 6 +- modules/index.html | 6 +- modules/io/directory.html | 2 + modules/io/file-flags.html | 2 + modules/io/file.html | 22 +- modules/io/index.html | 3 + modules/io/stat.html | 2 + modules/io/stdin.html | 23 ++ modules/io/stdout.html | 89 ++++++ modules/{process => os}/index.html | 18 +- modules/os/platform.html | 96 +++++++ modules/{process => os}/process.html | 20 +- modules/random/random.html | 18 +- performance.html | 7 +- qa.html | 25 +- style.css | 51 ++-- style.css.map | 2 +- syntax.html | 38 ++- values.html | 28 +- variables.html | 18 +- 70 files changed, 2315 insertions(+), 3558 deletions(-) delete mode 100644 community.html delete mode 100644 core-library.html delete mode 100644 core/bool.html delete mode 100644 core/class.html delete mode 100644 core/fiber.html delete mode 100644 core/fn.html delete mode 100644 core/index.html delete mode 100644 core/list.html delete mode 100644 core/map.html delete mode 100644 core/null.html delete mode 100644 core/num.html delete mode 100644 core/object.html delete mode 100644 core/range.html delete mode 100644 core/sequence.html delete mode 100644 core/string.html delete mode 100644 core/system.html delete mode 100644 embedding-api.html create mode 100644 embedding/calling-c-from-wren.html create mode 100644 embedding/calling-wren-from-c.html create mode 100644 embedding/configuring-the-vm.html create mode 100644 embedding/index.html create mode 100644 embedding/slots-and-handles.html create mode 100644 embedding/storing-c-data.html delete mode 100644 expressions.html delete mode 100644 fibers.html delete mode 100644 modules.html create mode 100644 modules/io/stdout.html rename modules/{process => os}/index.html (78%) create mode 100644 modules/os/platform.html rename modules/{process => os}/process.html (70%) diff --git a/classes.html b/classes.html index 26868e33..a2b99344 100644 --- a/classes.html +++ b/classes.html @@ -45,7 +45,7 @@

reference

@@ -85,7 +85,7 @@ @@ -104,14 +104,14 @@ class supports the same methods. State is defined in fields, whose valu stored in each instance.

Defining a class #

Classes are created using the class keyword, unsurprisingly:

-
class Unicorn {}
+
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.

-
class Unicorn { 
+
class Unicorn { 
   prance() { 
     System.print("The unicorn prances in a fancy manner!") 
   } 
@@ -121,7 +121,7 @@ stored in each instance. 

This defines a prance() method that takes no arguments. To add parameters, put their names inside the parentheses:

-
class Unicorn { 
+
class Unicorn { 
   prance(where, when) { 
     System.print("The unicorn prances in " + where + " at " + when) 
   } 
@@ -131,7 +131,7 @@ their names inside the parentheses: 

Since the number of parameters is part of a method’s signature a class can define multiple methods with the same name:

-
class Unicorn { 
+
class Unicorn { 
   prance() { 
     System.print("The unicorn prances in a fancy manner!") 
   }
@@ -155,7 +155,7 @@ different methods that you implement separately. 

different syntaxes for methods. Your classes can define all of them.

Getters #

A getter leaves off the parameter list and the parentheses:

-
class Unicorn { 
+
class Unicorn { 
   isFancy { true } // Unicorns are always fancy.
 }
 
@@ -163,7 +163,7 @@ different syntaxes for methods. Your classes can define all of them.

Setters #

A setter has = after the name, followed by a single parenthesized parameter:

-
class Unicorn { 
+
class Unicorn { 
   rider=(value) { 
     System.print("I am being ridden by " + value) 
   } 
@@ -175,7 +175,7 @@ different syntaxes for methods. Your classes can define all of them. 

whatever makes your heart flutter.

Operators #

Prefix operators, like getters, have no parameter list:

-
class Unicorn { 
+
class Unicorn { 
   - { 
     System.print("Negating a unicorn is weird") 
   } 
@@ -185,7 +185,7 @@ whatever makes your heart flutter. 

Infix operators, like setters, have a single parenthesized parameter for the right-hand operand:

-
class Unicorn { 
+
class Unicorn { 
   -(other) { 
     System.print("Subtracting " + other + " from a unicorn is weird") 
   } 
@@ -195,7 +195,7 @@ right-hand operand: 

A subscript operator puts the parameters inside square brackets and can have more than one:

-
class Unicorn { 
+
class Unicorn { 
   [index] { 
     System.print("Unicorns are not lists!") 
   }
@@ -211,7 +211,7 @@ more than one: 

parameter list.

As the name implies, a subscript setter looks like a combination of a subscript operator and a setter:

-
class Unicorn { 
+
class Unicorn { 
   [index]=(value) { 
     System.print("You can't stuff " + value + " into me at " + index) 
   } 
@@ -220,11 +220,12 @@ operator and a setter: 

Method Scope #

-

Up to this point, “scope” has been used to talk exclusively about variables. In a procedural language like C, or a functional one like Scheme, +

Up to this point, “scope” has been used to talk exclusively about +variables. In a procedural language like C, or a functional one like Scheme, that’s the only kind of scope there is. But object-oriented languages like Wren introduce another kind of scope: object scope. It contains the methods that are available on an object. When you write:

-
unicorn.isFancy
+
unicorn.isFancy
 
@@ -236,7 +237,7 @@ object to the left of the period is the object you want to look up the method on

Things get more interesting when you’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 this.

-
class Unicorn { 
+
class Unicorn { 
   name { "Francis" }
 
   printName() { 
@@ -262,7 +263,7 @@ because it makes a distinction between methods and functions.) 

tedious and verbose, which is why some languages don’t require it. You can do a “self send” by calling a method (or getter or setter) without any explicit receiver:

-
class Unicorn { 
+
class Unicorn { 
   name { "Francis" }
 
   printName() { 
@@ -274,7 +275,7 @@ receiver: 

Code like this gets tricky when there is also a variable outside of the class with the same name. Consider:

-
var name = "variable"
+
var name = "variable"
 
 class Unicorn { 
   name { "Francis" }
@@ -306,7 +307,7 @@ lowercase in Wren. Class names are capitalized. 

of the class, it’s usually the name of some other class. This rule makes that work.

Here’s an example that shows all three cases:

-
var shadowed = "surrounding" 
+
var shadowed = "surrounding" 
 var lowercase = "surrounding" 
 var Capitalized = "surrounding"
 
@@ -332,7 +333,7 @@ work. 

Our unicorns can prance around, but we don’t actually have any unicorns to do it. To create instances of a class, we need a constructor. You define one like so:

-
class Unicorn { 
+
class Unicorn { 
   construct new(name, color) { 
     System.print("My name is " + name + " and I am " + color + ".") 
   } 
@@ -344,13 +345,13 @@ like so: 

name. In Wren, all constructors have names. The word “new” isn’t special to Wren, it’s just a common constructor name.

To make a unicorn now, we call the constructor method on the class itself:

-
var fred = Unicorn.new("Fred", "palomino")
+
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:

-
class Unicorn { 
+
class Unicorn { 
   construct brown(name) { 
     System.print("My name is " + name + " and I am brown.") 
   } 
@@ -370,7 +371,7 @@ overloaded by arity. A constructor must be a n
 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:

-
Unicorn.brown("Dave")
+
Unicorn.brown("Dave")
 
@@ -382,7 +383,7 @@ constructors, etc.

Fields #

All state stored in instances is stored in fields. Each field has a name that starts with an underscore.

-
class Rectangle { 
+
class Rectangle { 
   area { _width * _height }
 
   // Other stuff...
@@ -407,7 +408,7 @@ accessed from within methods defined on the object’s class. You cannot eve
 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:

-
class Rectangle { 
+
class Rectangle { 
   width { _width } 
   height { _height }
 
@@ -417,7 +418,7 @@ getter to expose it: 

To allow outside code to modify the field, you’ll also need to provide setters:

-
class Rectangle { 
+
class Rectangle { 
   width=(value) { _width = value } 
   height=(value) { _height = value } 
 }
@@ -434,7 +435,7 @@ to or even should define getters or setters for most of your object’s fiel
 

A name that starts with two underscores is a static field. They work similar to fields except the data is stored on the class itself, and not the instance. They can be used in both instance and static methods.

-
class Foo { 
+
class Foo { 
   construct new() {}
 
   static setFromStatic(a) { __a = a } 
@@ -452,19 +453,19 @@ not the instance. They can be used in both instance and static methods.
 
 
 

Just like instance fields, static fields are initially null:

-
Foo.printFromStatic() null
+
Foo.printFromStatic() null
 

They can be used from static methods:

-
Foo.setFromStatic("first") 
+
Foo.setFromStatic("first") 
 Foo.bar.printFromStatic() first
 

And also instance methods. When you do so, there is still only one static field shared among all instances of the class:

-
var foo1 = Foo.new() 
+
var foo1 = Foo.new() 
 var foo2 = Foo.new()
 
 foo1.setFromInstance("second") 
@@ -479,7 +480,7 @@ 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:

-
class Pegasus is Unicorn {}
+
class Pegasus is Unicorn {}
 
@@ -489,9 +490,10 @@ class using is when you declare the class:

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 +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.

-
class Unicorn { 
+
class Unicorn { 
   // Unicorns cannot fly. :(
   static canFly { false } 
 }
@@ -503,7 +505,7 @@ are not inherited. 

This also means constructors are not inherited:

-
class Unicorn { 
+
class Unicorn { 
   construct new(name) { 
     System.print("My name is " + name + ".") 
   } 
@@ -519,7 +521,7 @@ are not inherited. 

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:

-
class Unicorn { 
+
class Unicorn { 
   construct new(name) { 
     System.print("My name is " + name + ".") 
   } 
@@ -544,7 +546,7 @@ 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:

-
class Base { 
+
class Base { 
   method() { 
     System.print("base method") 
   } 
@@ -560,7 +562,7 @@ call: 

You can also use super without a method name inside a constructor to invoke a base class constructor:

-
class Base { 
+
class Base { 
   construct new(arg) { 
     System.print("base got " + arg) 
   } 
diff --git a/community.html b/community.html
deleted file mode 100644
index d41f3836..00000000
--- a/community.html
+++ /dev/null
@@ -1,152 +0,0 @@
-
-
-
-
-Community – Wren
-
-
-
-
-
-
-
-
-
-

wren

-

a classy little scripting language

-
-
-
-
- - -
-

Community

-

Like the bird, Wren’s community is small, -but it exists!

-

User group #

-

There’s one Wren user group, and it’s the official Wren mailing -list. 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:

- -

Language bindings #

-

Want to host a Wren VM within another language. Try these:

- -

Editor integrations #

-

If you want Wren syntax highlighting in your editor, look no further:

- -

Tools and Utilities #

-

Things that make life easier:

- -

Do you have anything to add here? Send a pull request!

-
-
- - - diff --git a/concurrency.html b/concurrency.html index 53712e2a..e575871c 100644 --- a/concurrency.html +++ b/concurrency.html @@ -45,7 +45,7 @@

reference

@@ -85,7 +85,7 @@ @@ -114,7 +114,7 @@ fiber for every line of code you type in.

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:

-
var fiber = Fiber.new { 
+
var fiber = Fiber.new { 
   System.print("This runs in a separate fiber.") 
 }
 
@@ -126,14 +126,14 @@ a function.

Invoking fibers #

Once you’ve created a fiber, you can invoke it (which suspends the current fiber) by calling its call() method:

-
fiber.call()
+
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:

-
var fiber = Fiber.new { System.print("Hi") } 
+
var fiber = Fiber.new { System.print("Hi") } 
 System.print(fiber.isDone) false
 fiber.call() 
 System.print(fiber.isDone) true
@@ -151,7 +151,7 @@ as one function calling another. 

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:

-
var fiber = Fiber.new { 
+
var fiber = Fiber.new { 
   System.print("fiber 1") 
   Fiber.yield() 
   System.print("fiber 2") 
@@ -166,7 +166,7 @@ fiber is called, it picks up right where it left off and keeps going. 

This program prints:

-
main 1 
+
main 1 
 fiber 1 
 main 2 
 fiber 2 
@@ -183,7 +183,7 @@ code. 

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:

-
var fiber = Fiber.new { 
+
var fiber = Fiber.new { 
   var result = Fiber.yield() 
   System.print(result) 
 }
@@ -199,7 +199,7 @@ 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:

-
var fiber = Fiber.new { 
+
var fiber = Fiber.new { 
   Fiber.yield("sent") 
 }
 
@@ -216,7 +216,7 @@ you can iterate over. 

Wren’s fibers can do that, but they can do much more. Like Lua, they are full coroutines—they can suspend from anywhere in the callstack. For example:

-
var fiber = Fiber.new { 
+
var fiber = Fiber.new { 
   (1..10).map {|i| 
     Fiber.yield(i) 
   } 
diff --git a/contributing.html b/contributing.html
index 9a83c1c9..5172761b 100644
--- a/contributing.html
+++ b/contributing.html
@@ -45,7 +45,7 @@
       

reference

@@ -85,7 +85,7 @@ @@ -105,8 +105,8 @@ help.

user. 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.

-

If you do any of the above, let us know by adding it to the wiki. We like to -keep track of:

+

If you do any of the above, let us know by adding it to the wiki. We +like to keep track of:

  • Applications that host Wren as a scripting language.
  • Modules written in Wren that others can use.
  • @@ -134,28 +134,28 @@ written in Markdown ( simple Python script, util/generate_docs.py, converts that to HTML and CSS.

    The site uses Pygments for syntax highlighting, with a custom lexer plug-in for Wren. To install that, run:

    -
    $ cd util/pygments-lexer 
    -$ sudo python setup.py develop 
    -$ cd ../.. # Back to the root Wren directory.
    +
    $ cd util/pygments-lexer 
    +$ sudo python setup.py develop 
    +$ cd ../.. # Back to the root Wren directory.
     

    Now you can build the docs:

    -
    $ make docs
    +
    $ make docs
     

    This generates the site in build/docs/. You can run any simple static web server from there. Python includes one:

    -
    $ cd build/docs 
    -$ python -m SimpleHTTPServer
    +
    $ 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:

    -
    $ make watchdocs
    +
    $ make watchdocs
     
    @@ -166,7 +166,7 @@ docs when you edit a file:

    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:

    -
    $ make test
    +
    $ make test
     
    @@ -202,7 +202,8 @@ docs when you edit a file:

    Getting help #

    If at any point you have questions, feel free to file an issue or ask -on the mailing list. You can also email me directly (robert at +on the mailing list. If you’re a Redditor, try the +/r/wren_lang subreddit. You can also email me directly (robert at stuffwithstuff.com) if you want something less public.

    diff --git a/control-flow.html b/control-flow.html index ce90822f..8cc91160 100644 --- a/control-flow.html +++ b/control-flow.html @@ -45,7 +45,7 @@

    reference

    @@ -85,7 +85,7 @@ @@ -118,14 +118,14 @@ values.

    If statements #

    The simplest branching statement, if lets you conditionally skip a chunk of code. It looks like this:

    -
    if (ready) System.print("go!")
    +
    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:

    -
    if (ready) { 
    +
    if (ready) { 
       System.print("getSet") 
       System.print("go!") 
     }
    @@ -134,12 +134,12 @@ a statement, you can have a block: 

    You may also provide an else branch. It will be executed if the condition is false:

    -
    if (ready) System.print("go!") else System.print("not ready!")
    +
    if (ready) System.print("go!") else System.print("not ready!")
     

    And, of course, it can take a block too:

    -
    if (ready) { 
    +
    if (ready) { 
       System.print("go!") 
     } else { 
       System.print("not ready!") 
    @@ -154,14 +154,15 @@ only conditionally evaluate right operand—they short-circuit. 

    A && (“logical and”) expression evaluates the left-hand argument. If it’s false, it returns that value. Otherwise it evaluates and returns the right-hand argument.

    -
    System.print(false && 1)  false
    +
    System.print(false && 1)  false
     System.print(1 && 2)      2
     
    -

    A || (“logical or”) expression is reversed. If the left-hand argument is true, it’s returned, otherwise the right-hand argument is evaluated and +

    A || (“logical or”) expression is reversed. If the left-hand argument is +true, it’s returned, otherwise the right-hand argument is evaluated and returned:

    -
    System.print(false || 1)  1
    +
    System.print(false || 1)  1
     System.print(1 || 2)      1
     
    @@ -170,7 +171,7 @@ returned:

    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.

    -
    System.print(1 != 2 ? "math is sane" : "math is not sane!")
    +
    System.print(1 != 2 ? "math is sane" : "math is not sane!")
     
    @@ -184,7 +185,7 @@ 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:

    -
    // Hailstone sequence.
    +
    // Hailstone sequence.
     var n = 27 
     while (n != 1) { 
       if (n % 2 == 0) { 
    @@ -203,7 +204,7 @@ 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:

    -
    var n = 27 
    +
    var n = 27 
     while (n != 1) if (n % 2 == 0) n = n / 2 else n = 3 * n + 1
     
    @@ -213,7 +214,7 @@ single statement:

    some complex condition. But in most cases, you’re looping through a list, a series of numbers, or some other “sequence” object. That’s what for is, uh, for. It looks like this:

    -
    for (beatle in ["george", "john", "paul", "ringo"]) { 
    +
    for (beatle in ["george", "john", "paul", "ringo"]) { 
       System.print(beatle) 
     }
     
    @@ -240,7 +241,7 @@ That’s what for is, uh, for. It looks like this:

    and stop. To do that, you can use a break statement. It’s just the break keyword all by itself. That immediately exits out of the nearest enclosing while or for loop.

    -
    for (i in [1, 2, 3, 4]) { 
    +
    for (i in [1, 2, 3, 4]) { 
       System.print(i)           1
       if (i == 3) break         2
     }                           3
    @@ -251,7 +252,7 @@ keyword all by itself. That immediately exits out of the nearest enclosing
     

    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, like so:

    -
    for (i in 1..100) { 
    +
    for (i in 1..100) { 
       System.print(i) 
     }
     
    @@ -259,7 +260,7 @@ sequence of numbers, or loop a number of times. For that, you can create a

    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:

    -
    for (i in 1...100) { 
    +
    for (i in 1...100) { 
       System.print(i) 
     }
     
    @@ -277,14 +278,14 @@ are defined in terms of an “iterator protocol”. The loop itself does 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:

    -
    for (i in 1..100) { 
    +
    for (i in 1..100) { 
       System.print(i) 
     }
     

    Wren sees it something like this:

    -
    var iter_ = null 
    +
    var iter_ = null 
     var seq_ = 1..100 
     while (iter_ = seq_.iterate(iter_)) { 
       var i = seq_.iteratorValue(iter_) 
    diff --git a/core-library.html b/core-library.html
    deleted file mode 100644
    index 50131e0e..00000000
    --- a/core-library.html
    +++ /dev/null
    @@ -1,321 +0,0 @@
    -
    -
    -
    -
    -Core Library – Wren
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Core Library

    -

    Object Class #

    -

    ==(other) and !=(other) operators #

    -

    Compares two objects using built-in equality. This compares numbers by value, -and all other objects are compared by identity—two objects are equal only -if they are the exact same object.

    -

    toString #

    -

    A default string representation of the object.

    -

    type #

    -

    The Class of the object.

    -

    Class Class #

    -

    name #

    -

    The name of the class.

    -

    Bool Class #

    -

    Boolean values. There are two instances, true and false.

    -

    ! operator #

    -

    Returns the logical complement of the value.

    -
    > !true
    -false
    -> !false
    -true
    -
    - - -

    toString #

    -

    The string representation of the value, either "true" or "false".

    -

    Fiber Class #

    -

    A lightweight coroutine. Here is a gentle introduction.

    -

    new Fiber(function) #

    -

    Creates a new fiber that executes function in a separate coroutine when the -fiber is run. Does not immediately start running the fiber.

    -
    var fiber = new Fiber {
    -  IO.print("I won't get printed")
    -}
    -
    - - -

    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.

    -
    var fiber = new Fiber {
    -  IO.print("Before yield")
    -  Fiber.yield
    -  IO.print("After yield")
    -}
    -
    -fiber.call              // "Before yield"
    -IO.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.

    -
    var fiber = new Fiber {
    -  IO.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, returns null.

    -

    It is a runtime error to call this when there is no parent fiber to return to.

    -
    Fiber.yield // ERROR
    -
    -new Fiber {
    -  Fiber.yield // ERROR
    -}.run
    -
    - - -

    Fiber.yield(value) #

    -

    Similar to Fiber.yield but provides a value to return to the parent fiber's -call.

    -
    var fiber = new Fiber {
    -  Fiber.yield("value")
    -}
    -
    -IO.print(fiber.call) // "value"
    -
    - - -

    call #

    -

    TODO

    -

    call(value) #

    -

    TODO

    -

    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.

    -

    run #

    -

    TODO

    -

    run(value) #

    -

    TODO

    -

    Fn Class #

    -

    A first class function—an object that wraps an executable chunk of code. -Here is a friendly introduction.

    -

    new Fn(function) #

    -

    Creates a new function from... function. Of course, function is already be -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 to some other method.

    -
    var fn = new Fn {
    -  IO.print("The body")
    -}
    -
    - - -

    It is a runtime error if block is not a function.

    -

    call(args...) #

    -

    TODO

    -

    Null Class #

    -

    ! operator #

    -

    Returns true, since null is considered false.

    -
    > !null
    -true
    -
    - - -

    Num Class #

    -

    TODO

    -

    abs #

    -

    The absolute value of the number.

    -
    -123.abs // 123
    -
    - - -

    ceil #

    -

    TODO

    -

    cos #

    -

    The cosine of the number.

    -

    floor #

    -

    TODO

    -

    isNan #

    -

    Whether the number is not a number. 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.

    -

    - operator #

    -

    Negates the number.

    -
    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.

    -

    <(other), >(other), <=(other), >=(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 #

    -

    TODO

    -

    ...(other) operator #

    -

    TODO

    -

    Object Class #

    -

    ! operator #

    -

    Returns false, since most objects are considered true.

    -

    String Class #

    -

    A string of Unicode code points stored in UTF-8.

    -

    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 length of the string.

    -

    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 search in the string or -1 if search is not a -substring of the string.

    -

    It is a runtime error if search is not a string.

    -

    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 one character string of the value at index.

    -

    It is a runtime error if index is greater than the length of the string.

    -

    Note: This does not currently handle UTF-8 characters correctly.

    -

    List Class #

    -

    TODO

    -

    Extends Sequence.

    -

    add(item) #

    -

    Appends item onto the end of the list.

    -

    clear #

    -

    Removes all items from the list.

    -

    count #

    -

    The number of items in the list.

    -

    insert(item, index) #

    -

    TODO

    -

    iterate(iterator), iteratorValue(iterator) #

    -

    TODO

    -

    removeAt(index) #

    -

    TODO

    -

    [index] operator #

    -

    TODO

    -

    [index]=(item) operator #

    -

    TODO

    -

    Range Class #

    -

    TODO

    -

    Extends Sequence.

    -

    from #

    -

    TODO

    -

    to #

    -

    TODO

    -

    min #

    -

    TODO

    -

    max #

    -

    TODO

    -

    isInclusive #

    -

    TODO

    -

    iterate(iterator), iteratorValue(iterator) #

    -

    TODO

    -

    Sequence Class #

    -

    An abstract base class for any iterable object. It provides a number of methods for working with sequences based on the core iterator protocol.

    -

    all(predicate) #

    -

    Tests whether all the elements in the list pass the predicate.

    -

    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.

    -
    -
    - - - \ No newline at end of file diff --git a/core/bool.html b/core/bool.html deleted file mode 100644 index 86fb8cbf..00000000 --- a/core/bool.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - -Bool Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Bool Class

    -

    Boolean values. There are two instances, true and false.

    -

    Methods #

    -

    ! operator #

    -

    Returns the logical complement of the value.

    -
    System.print(!true) // "false".
    -System.print(!false) // "true".
    -
    - - -

    toString #

    -

    The string representation of the value, either "true" or "false".

    -
    -
    - - - diff --git a/core/class.html b/core/class.html deleted file mode 100644 index e8c5b13b..00000000 --- a/core/class.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - -Class Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Class Class

    -

    Methods #

    -

    name #

    -

    The name of the class.

    -

    supertype #

    -

    The superclass of this class.

    -
    class Crustacean {}
    -class Crab is Crustacean {}
    -
    -System.print(Crab.supertype) // "Crustacean".
    -
    - - -

    A class with no explicit superclass implicitly inherits Object:

    -
    System.print(Crustacean.supertype) // "Object".
    -
    - - -

    Object forms the root of the class hierarchy and has no supertype:

    -
    System.print(Object.supertype) // "null".
    -
    -
    -
    - - - diff --git a/core/fiber.html b/core/fiber.html deleted file mode 100644 index 28848e96..00000000 --- a/core/fiber.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - -Fiber Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Fiber Class

    -

    A lightweight coroutine. Here 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.

    -
    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.

    -
    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.

    -
    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.

    -
    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.

    -
    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.

    -
    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.

    -
    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.

    -
    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

    -
    -
    - - - diff --git a/core/fn.html b/core/fn.html deleted file mode 100644 index 1e9f1c25..00000000 --- a/core/fn.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -Fn Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Fn Class

    -

    A first class function—an object that wraps an executable chunk of code. -Here 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 to some other method.

    -
    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.

    -
    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.

    -
    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.

    -
    -
    - - - diff --git a/core/index.html b/core/index.html deleted file mode 100644 index a34bbb36..00000000 --- a/core/index.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - -Core Library – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Core Library

    -

    Because Wren is designed for embedding in applications, 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:

    - -
    -
    - - - diff --git a/core/list.html b/core/list.html deleted file mode 100644 index 946571b8..00000000 --- a/core/list.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -List Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    List Class

    -

    Extends Sequence.

    -

    An indexable contiguous collection of elements. More details here.

    -

    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.

    -
    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.

    -
    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.

    -
    var list = ["a", "b"]
    -list.insert(-1, "d")
    -list.insert(-2, "c")
    -System.print(list) // "[a, b, c, d]".
    -
    - - -

    Returns the inserted item.

    -
    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 -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.

    -
    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.

    -
    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.

    -
    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.

    -
    -
    - - - diff --git a/core/map.html b/core/map.html deleted file mode 100644 index b7e81e0b..00000000 --- a/core/map.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - -Map Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Map Class

    -

    An associative collection that maps keys to values. More details here.

    -

    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 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 -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 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.

    -
    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, -Class, Null, Num, Range, -or String.

    -
    -
    - - - diff --git a/core/null.html b/core/null.html deleted file mode 100644 index 93c29294..00000000 --- a/core/null.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - -Null Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Null Class

    -

    Methods #

    -

    ! operator #

    -

    Returns true, since null is considered false.

    -
    System.print(!null) // "true".
    -
    -
    -
    - - - diff --git a/core/num.html b/core/num.html deleted file mode 100644 index 3112997b..00000000 --- a/core/num.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - -Num Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Num Class

    -

    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.

    -
    -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.

    -
    1.5.ceil // 2
    -(-3.2).ceil // -3
    -
    - - -

    cos #

    -

    The cosine of the number.

    -

    floor #

    -

    Rounds the number down to the nearest integer.

    -
    1.5.floor    // 1
    -(-3.2).floor // -4
    -
    - - -

    isNan #

    -

    Whether the number is not a number. 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.

    -
    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.

    -

    <(other), >(other), <=(other), >=(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 representing a consecutive range of numbers -from the beginning number to the ending number.

    -
    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 representing a consecutive range of numbers -from the beginning number to the ending number not including the ending number.

    -
    var range = 1.2...3.4
    -System.print(range.min)         // 1.2
    -System.print(range.max)         // 3.4
    -System.print(range.isInclusive) // false
    -
    -
    -
    - - - diff --git a/core/object.html b/core/object.html deleted file mode 100644 index 8194557d..00000000 --- a/core/object.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - -Object Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Object Class

    -

    Static Methods #

    -

    same(obj1, obj2) #

    -

    Returns true if obj1 and obj2 are the same. For value -types, 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.

    -

    ==(other) and !=(other) operators #

    -

    Compares two objects using built-in equality. This compares value -types by value, and all other objects are compared by -identity—two objects are equal only if they are the exact same object.

    -

    toString #

    -

    A default string representation of the object.

    -

    type #

    -

    The Class of the object.

    -
    -
    - - - diff --git a/core/range.html b/core/range.html deleted file mode 100644 index edbb5926..00000000 --- a/core/range.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - -Range Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Range Class

    -

    TODO

    -

    Extends Sequence.

    -

    Methods #

    -

    from #

    -

    TODO

    -

    to #

    -

    TODO

    -

    min #

    -

    TODO

    -

    max #

    -

    TODO

    -

    isInclusive #

    -

    TODO

    -

    iterate(iterator), iteratorValue(iterator) #

    -

    TODO

    -
    -
    - - - diff --git a/core/sequence.html b/core/sequence.html deleted file mode 100644 index 18530329..00000000 --- a/core/sequence.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - -Sequence Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Sequence Class

    -

    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.

    -

    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, stops iterating -and returns the value. Otherwise, returns true.

    -
    [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, stops iterating and -returns that value. Otherwise, returns false.

    -
    [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.

    -
    [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.

    -
    ["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.

    -
    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.

    -
    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 containing all the elements in the sequence.

    -
    (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.

    -
    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.

    -
    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].
    -
    -
    -
    - - - diff --git a/core/string.html b/core/string.html deleted file mode 100644 index 13771fea..00000000 --- a/core/string.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - -String Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    String Class

    -

    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—very roughly a single -"character"—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:

    -
    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:

    -
    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 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.

    -
    String.fromCodePoint(8225) // "‡"
    -
    - - -

    It is a runtime error if codePoint is not an integer between 0 and -0x10ffff, inclusive.

    -

    Methods #

    -

    bytes #

    -

    Gets a Sequence 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.

    -
    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 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.

    -
    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.

    -
    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 -for iterating over the code points in the string:

    -
    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.

    -
    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:

    -
    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.

    -
    -
    - - - diff --git a/core/system.html b/core/system.html deleted file mode 100644 index a4c7d4f6..00000000 --- a/core/system.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - -System Class – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    System Class

    -

    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.

    -
    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.

    -
    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.

    -
    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.

    -
    -
    - - - diff --git a/embedding-api.html b/embedding-api.html deleted file mode 100644 index f5ee9451..00000000 --- a/embedding-api.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - -Embedding API – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - - -
    -

    Embedding API

    -

    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, it - generates both shared and static libraries in lib that you can link to.

      -
    2. -
    3. -

      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++98 or anything later.

      -
    4. -
    -

    In either case, you also want to add src/include to your include path so you -can get to the public header for Wren:

    -
    #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:

    -
    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:

    -
    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().

    -
    config.loadModuleFn = ...; 
    -config.bindForeignMethodFn = ...; 
    -config.bindForeignClassFn = ...;
    -
    - - -

    These three callbacks are how Wren talks back to your program. We’ll cover -them in detail later.

    -
    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:

    -
    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:

    -
    WrenInterpretResult result = wrenInterpret(vm, "System.print(\"Hi!\")");
    -
    - - -

    The first string is the chunk of code to execute—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.

    -

    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.

    -

    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:

    -
    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.

    -
    -
    - - - diff --git a/embedding/calling-c-from-wren.html b/embedding/calling-c-from-wren.html new file mode 100644 index 00000000..244dfc79 --- /dev/null +++ b/embedding/calling-c-from-wren.html @@ -0,0 +1,196 @@ + + + + +Calling C from Wren – Wren + + + + + + +
    +
    +
    +

    wren

    +

    a classy little scripting language

    +
    +
    +
    +
    + + +
    +

    Calling C from Wren

    +

    When we are ensconced within the world of Wren, the external C world is +“foreign” to us. There are two reasons we might want to bring some foreign +flavor into our VM:

    +
      +
    • We want to execute code written in C.
    • +
    • We want to store raw C data.
    • +
    +

    Since Wren is object-oriented, behavior lives in methods, so for the former we +have foreign methods. Likewise, data lives in objects, so for the latter, we +define foreign classes. This page is about the first, foreign methods. The +next page covers foreign classes.

    +

    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 body of the method is written in C.

    +

    A foreign method is declared in Wren like so:

    +
    class Math { 
    +  foreign static add(a, b) 
    +}
    +
    + + +

    The foreign keyword tells Wren that the method add() is declared on Math, +but implemented in C. Both static and instance methods can be foreign.

    +

    Binding Foreign Methods #

    +

    When you call a foreign method, Wren needs to figure out which C function to +execute. This process is called binding. Binding is performed on-demand by the +VM. When a class that declares a foreign method is executed – when the class +statement itself is evaluated – the VM asks the host application for the C +function that should be used for the foreign method.

    +

    It does this through the bindForeignMethodFn callback you give it when you +first configure the VM. This callback isn’t the foreign method itself. +It’s the binding function your app uses to look up foreign methods.

    +

    Its signature is:

    +
    WrenForeignMethodFn bindForeignMethodFn( 
    +    WrenVM* vm, 
    +    const char* module, 
    +    const char* className, 
    +    bool isStatic, 
    +    const char* signature);
    +
    + + +

    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’s signature, and whether or not it’s a static +method. In the above example, it would pass something like:

    +
    bindForeignMethodFn(vm, "main", "Math", true, "add(_,_)");
    +
    + + +

    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:

    +
    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...
    +}
    +
    + + +

    This implementation is pretty tedious, but you get the idea. Feel free to do +something more clever here in your host application.

    +

    The important part is that it returns a pointer to a C function to use for that +foreign method. Wren does this binding step once when the class definition is +first executed. It then keeps the function pointer you return and associates it +with that method. This way, calls to the foreign method are fast.

    +

    Implementing a Foreign Method #

    +

    All C functions for foreign methods have the same signature:

    +
    void foreignMethod(WrenVM* vm);
    +
    + + +

    Arguments passed from Wren are not passed as C arguments, and the method’s +return value is not a C return value. Instead – you guessed it – we go through +the slot array.

    +

    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.

    +

    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:

    +
    void mathAdd(WrenVM* vm) 
    +{ 
    +  double a = wrenGetSlotDouble(vm, 1); 
    +  double b = wrenGetSlotDouble(vm, 2); 
    +  wrenSetSlotDouble(vm, 0, a + b); 
    +}
    +
    + + +

    While your foreign method is executing, the VM is completely suspended. No other +fibers run until your foreign method returns. You should not try to resume the +VM from within a foreign method by calling wrenCall() or wrenInterpret(). +The VM is not re-entrant.

    +

    This covers foreign behavior, but what about foreign state? For that, we need +a foreign class

    +

    Storing C Data → +← Calling Wren from C

    +
    +
    + + + diff --git a/embedding/calling-wren-from-c.html b/embedding/calling-wren-from-c.html new file mode 100644 index 00000000..7f92e2d8 --- /dev/null +++ b/embedding/calling-wren-from-c.html @@ -0,0 +1,230 @@ + + + + +Calling Wren from C – Wren + + + + + + +
    +
    +
    +

    wren

    +

    a classy little scripting language

    +
    +
    +
    +
    + + +
    +

    Calling Wren from C

    +

    From C, we can tell Wren to do stuff by calling wrenInterpret(), but that’s +not always the ideal way to drive the VM. First of all, it’s slow. It has to +parse and compile the string of source code you give it. Wren has a pretty fast +compiler, but that’s still a good bit of work.

    +

    It’s also not an effective way to communicate. You can’t pass arguments to +Wren—at least, not without doing something nasty like converting them to +literals in a string of source code—and you can’t get a result value back.

    +

    wrenInterpret() is great for loading code into the VM, but it’s not the best +way to execute code that’s already been loaded. What we want to do is invoke +some already compiled chunk of code. Since Wren is an object-oriented language, +“chunk of code” means a method, not a function.

    +

    The C API for doing this is wrenCall(). In order to invoke a Wren method from +C, we need a few things:

    +
      +
    • +

      The method to call. Wren is dynamically typed, so this means we’ll look it + up by name. Further, since Wren supports overloading by arity, we actually + need its entire signature.

      +
    • +
    • +

      The receiver object to invoke the method on. The receiver’s class + determines which method is actually called.

      +
    • +
    • +

      The arguments to pass to the method.

      +
    • +
    +

    We’ll tackle these one at a time.

    +

    Getting a Method Handle #

    +

    When you run a chunk of Wren code like this:

    +
    object.someMethod(1, 2, 3)
    +
    + + +

    At runtime, the VM has to look up the class of object and find a method there +whose signature is someMethod(_,_,_). This sounds like it’s doing some string +manipulation—at the very least hashing the signature—every time a +method is called. That’s how many dynamic languages work.

    +

    But, as you can imagine, that’s pretty slow. So, instead, Wren does as much of +that work at compile time as it can. When it’s compiling the above code to +bytecode, it takes that method signature a converts it to a method symbol, a +number that uniquely identifes that method. That’s the only part of the process +that requires treating a signature as a string.

    +

    At runtime, the VM just looks for the method symbol in the receiver’s class’s +method table. In fact, the way it’s implemented today, the symbol is simply the +array index into the table. That’s why method calls are so fast in Wren.

    +

    It would be a shame if calling a method from C didn’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 “compiled” method signature:

    +
    WrenHandle* wrenMakeCallHandle(WrenVM* vm, const char* signature);
    +
    + + +

    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 reusable handle +that can be used to very quickly call a certain method given a receiver and some +arguments.

    +

    This is just a regular WrenHandle, which means you can hold onto it as long as +you like. Typically, you’d call this once outside of your application’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 wrenReleaseHandle().

    +

    Setting Up a Receiver #

    +

    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 last section, we give that to Wren +by storing it in a slot. In particular, the receiver for a method call goes in +slot zero.

    +

    Any object you store in that slot can be used as a receiver. You could even call ++ on a number by storing a number in there if you felt like it.

    +

    Needing a receiver to call some Wren code from C might feel strange. C is +procedural, so it’s natural to want to just invoke a bare function from Wren, +but Wren isn’t procedural. Instead, if you want to define some executable +operation that isn’t logically tied to a specific object, the natural way is to +define a static method on an appropriate class.

    +

    For example, say we’re making a game engine. From C, we want to tell the game +engine to update all of the entities each frame. We’ll keep track of the list of +entities within Wren, so from C, there’s no obvious object to call update(_) +on. Instead, we’ll just make it a static method:

    +
    class GameEngine { 
    +  static update(elapsedTime) { 
    +    // ...
    +  } 
    +}
    +
    + + +

    Often, when you call a Wren method from C, you’ll be calling a static method. +But, even then, you need a receiver. Now, though, the receiver is the class +itself. Classes are first class objects in Wren, and when you define a named +class, you’re really declaring a variable with the class’s name and storing a +reference to the class object in it.

    +

    Assuming you declared that class at the top level, the C API gives you a way to +look it up. We can get a handle to the above class like so:

    +
    // Load the class into slot 0.
    +wrenEnsureSlots(vm, 1); 
    +wrenGetVariable(vm, "main", "GameEngine", 0);
    +
    + + +

    We could do this every time we call update(), but, again, that’s kind of slow +because we’re looking up “GameEngine” by name each time. A faster solution is to +create a handle to the class once and use it each time:

    +
    // Load the class into slot 0.
    +wrenEnsureSlots(vm, 1); 
    +wrenGetVariable(vm, "main", "GameEngine", 0); 
    +WrenHandle* gameEngineClass = wrenGetSlotHandle(vm, 0);
    +
    + + +

    Now, each time we want to call a method on GameEngine, we store that value back +in slot zero:

    +
    wrenSetSlotHandle(vm, 0, gameEngineClass);
    +
    + + +

    Just like we hoisted wrenMakeCallHandle() out of our performance critical +loop, we can hoist the call to wrenGetVariable() out. Of course, if your code +isn’t performance critical, you don’t have to do this.

    +

    Passing Arguments #

    +

    We’ve got a receiver in slot zero now, next we need to pass in any other +arguments. In our GameEngine example, that’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’s just:

    +
    wrenSetSlotDouble(vm, 1, elapsedTime);
    +
    + + +

    Calling the Method #

    +

    We have all of the data in place, so all that’s left is to pull the trigger and +tell the VM to start running some code:

    +
    WrenInterpretResult wrenCall(WrenVM* vm, WrenHandle* method);
    +
    + + +

    It takes the method handle we created using wrenMakeCallHandle(). 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 suspends.

    +

    wrenCall() returns the same WrenInterpretResult enum as wrenInterpret() to +tell you if the method completed successfully or a runtime error occurred. +(wrenCall() never returns WREN_ERROR_COMPILE since it doesn’t compile +anything.)

    +

    Getting the Return Value #

    +

    When wrenCall() returns, it leaves the slot array in place. In slot zero, you +can find the method’s return value, which you can access using any of the slot +reading functions. If you don’t need the return value, you can ignore it.

    +

    This is how you drive Wren from C, but how do you put control in Wren’s hands? +For that, you’ll need the next section…

    +

    Calling C From Wren → +← Slots and Handles

    +
    +
    + + + diff --git a/embedding/configuring-the-vm.html b/embedding/configuring-the-vm.html new file mode 100644 index 00000000..1d7aa679 --- /dev/null +++ b/embedding/configuring-the-vm.html @@ -0,0 +1,234 @@ + + + + +Configuring the VM – Wren + + + + + + +
    +
    +
    +

    wren

    +

    a classy little scripting language

    +
    +
    +
    +
    + + +
    +

    Configuring the VM

    +

    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.

    +

    The struct looks like:

    +
    typedef struct 
    +{ 
    +  WrenReallocateFn reallocateFn; 
    +  WrenLoadModuleFn loadModuleFn; 
    +  WrenBindForeignMethodFn bindForeignMethodFn; 
    +  WrenBindForeignClassFn bindForeignClassFn; 
    +  WrenWriteFn writeFn; 
    +  WrenErrorFn errorFn; 
    +  size_t initialHeapSize; 
    +  size_t minHeapSize; 
    +  int heapGrowthPercent; 
    +} WrenConfiguration;
    +
    + + +

    Most fields have useful defaults, which you can (and should) initialize by +calling:

    +
    wrenInitConfiguration(&configuration);
    +
    + + +

    Calling this ensures that your VM doesn’t get uninitialized configuration when +new fields are added to WrenConfiguration. Here is what each field does, roughly +categorized:

    +

    Binding #

    +

    The VM is isolated from the outside world. These callbacks let the VM request +access to imported code and foreign functionality.

    +

    loadModuleFn #

    +

    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 import statement is +executed, it relies on the host application to locate and read the source code +for a module.

    +

    The signature of this function is:

    +
    char* loadModule(WrenVM* vm, const char* name)
    +
    + + +

    When a module is imported, Wren calls this and passes in the module’s name. The +host should return the source code for that module. Memory for the source should +be allocated using the same allocator that the VM uses for other allocation (see +below). Wren will take ownership of the returned string and free it later.

    +

    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.

    +

    If your host application isn’t able to load a module with some name, it should +return NULL and Wren will report that as a runtime error.

    +

    If you don’t use any import statements, you can leave this NULL.

    +

    bindForeignMethodFn #

    +

    The callback Wren uses to find a foreign method and bind it to a class. See +this page for details. If your application defines no foreign +methods, you can leave this NULL.

    +

    bindForeignClassFn #

    +

    The callback Wren uses to find a foreign class and get its foreign methods. See +this page for details. If your application defines no foreign +classes, you can leave this NULL.

    +

    Diagnostics #

    +

    These let you wire up some minimal output so you can tell if your code is doing +what you expect.

    +

    writeFn #

    +

    This is the callback Wren uses to output text when System.print() or the other +related functions are called. This is the minimal connection the VM has with the +outside world and lets you do rudimentary “printf debugging”. Its signature is:

    +
    void write(WrenVM* vm, const char* text)
    +
    + + +

    Wren does not have a default implementation for this. It’s up to you to wire +it up to printf() or some other way to show the text. If you leave it NULL, +calls to System.print() and others silently do nothing.

    +

    errorFn #

    +

    Wren uses this callback to report compile time and runtime errors. Its signature +is:

    +
    void error( 
    +      WrenErrorType type, 
    +      const char* module, 
    +      int line, 
    +      const char* message)
    +
    + + +

    The type parameter is one of:

    +
    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;
    +
    + + +

    When a compile error occurs, errorFn is called once with type +WREN_ERROR_COMPILE, the name of the module and line where the error occurs, +and the error message.

    +

    Runtime errors include stack traces. To handle this, Wren first calls errorFn +with WREN_ERROR_RUNTIME, no module or line, and the runtime error’s message. +After that, it calls errorFn again using type WREN_ERROR_STACK_TRACE, 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 message is the name of the method +or function.

    +

    If you leave this NULL, Wren does not report any errors.

    +

    Memory Management #

    +

    These fields control how the VM allocates and manages memory.

    +

    reallocateFn #

    +

    This lets you provide a custom memory allocation function. Its signature is:

    +
    void* reallocate(void* memory, size_t newSize)
    +
    + + +

    Wren uses this one function to allocate, grow, shrink, and deallocate memory. +When called, memory is the existing pointer to the block of memory if an +allocation is being changed or freed. If Wren is requesting new memory, then +memory is NULL.

    +

    newSize 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.

    +

    If you don’t provide a custom allocator, the VM uses a default one that relies +on realloc and free.

    +

    initialHeapSize #

    +

    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.

    +

    If you set this to zero, Wren uses a default size of 10MB.

    +

    minHeapSize #

    +

    After a garbage collection occurs, the threshold for the next 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.

    +

    This can be used to ensure that the heap does not get too small, which can +in turn lead to a large number of collections afterwards as the heap grows +back to a usable size.

    +

    If zero, this defaults to 1MB.

    +

    heapGrowthPercent #

    +

    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.

    +

    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.)

    +

    Setting this to a smaller number wastes less memory, but triggers more +frequent garbage collections.

    +

    If set to zero, the VM uses a default of 50.

    +

    ← Storing C Data

    +
    +
    + + + diff --git a/embedding/index.html b/embedding/index.html new file mode 100644 index 00000000..70d98757 --- /dev/null +++ b/embedding/index.html @@ -0,0 +1,226 @@ + + + + +Embedding – Wren + + + + + + +
    +
    +
    +

    wren

    +

    a classy little scripting language

    +
    +
    +
    +
    + + +
    +

    Embedding

    +

    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:

    +
      +
    1. +

      Wren is dynamically typed, but C is not. A variable can hold a value of + any type in Wren, but that’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.

      +
    2. +
    3. +

      Wren uses garbage collection, but C manages memory manually. 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’s still in use.

      +

      Also, we ideally don’t want to let native C code see a bare pointer to a +chunk of memory managed by Wren. Many garbage collection strategies involve +moving objects in memory. If we allow C code to point directly to an +object, that pointer will be left dangling when the object moves. Wren’s GC +doesn’t move objects today, but we would like to keep that option for the +future.

      +
    4. +
    5. +

      The embedding API needs to be fast. 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 maximum performance you can get out of the system. It’s the + bottom of the stack, so there’s no way for a user to optimize around it if + it’s too slow. There is no lower level alternative.

      +
    6. +
    7. +

      We want the API to be pleasant to use. This is the last constraint + because it’s the softest. Of course, we want a beautiful, usable API. But we + really need to handle the above, so we’re willing to make things a bit more + of a chore to reach the first three goals.

      +
    8. +
    +

    Fortunately, we aren’t the first people to tackle this. If you’re familiar with +Lua’s C API, you’ll find Wren’s similar.

    +

    Performance and safety #

    +

    When code is safely snuggled within the confines of the VM, it’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’re within Wren code, it tries very hard to avoid crashing and burning.

    +

    This is why you use a high level language after all—it’s safer and more +productive than C. C, meanwhile, really assumes you know what you’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.

    +

    Wren’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.

    +

    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.

    +

    Including Wren #

    +

    There are two (well, three) ways to get the Wren VM into your program:

    +
      +
    1. +

      Link to the static or dynamic library. When you build Wren, it + generates both shared and static libraries in lib that you can link to.

      +
    2. +
    3. +

      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++98 or anything later.

      +
    4. +
    +

    In either case, you also want to add src/include to your include path so you +can find the public header for Wren:

    +
    #include "wren.h"
    +
    + + +

    Wren depends only on the C standard library, so you don’t usually need to link +to anything else. On some platforms (at least BSD and Linux) some of the math +functions in math.h are implemented in a separate library, libm, that you +have to explicitly link to.

    +

    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++:

    +
    #include "wren.hpp"
    +
    + + +

    Creating a Wren VM #

    +

    Once you’ve integrated the code into your executable, you need to create a +virtual machine. To do that, you create a WrenConfiguration:

    +
    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. We’ll +learn more about what you can configure later.

    +

    With this ready, you can create the VM:

    +
    WrenVM* vm = wrenNewVM(&config);
    +
    + + +

    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.

    +

    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 execute a string of Wren source code like so:

    +
    WrenInterpretResult result = wrenInterpret(vm, 
    +    "System.print(\"I am running in a VM!\")");
    +
    + + +

    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 +wrenInterpret(), Wren first compiles your source to bytecode. If an error +occurs, 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 or one suspends.

    +

    If a runtime error occurs (and another fiber doesn’t handle it), Wren aborts +fibers all the way back to the main one and returns WREN_RESULT_RUNTIME_ERROR. +Otherwise, when the last fiber successfully returns, it returns +WREN_RESULT_SUCCESS.

    +

    All code passed to wrenInterpret() runs in a special “main” module. That way, +top-level names defined in one call can be accessed in later ones. It’s similar +to a REPL session.

    +

    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:

    +
    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 WrenHandle +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.

    +

    Next, we’ll learn to make that VM do useful stuff…

    +

    Slots and Handles →

    +
    +
    + + + diff --git a/embedding/slots-and-handles.html b/embedding/slots-and-handles.html new file mode 100644 index 00000000..0c6bf897 --- /dev/null +++ b/embedding/slots-and-handles.html @@ -0,0 +1,303 @@ + + + + +Slots and Handles – Wren + + + + + + +
    +
    +
    +

    wren

    +

    a classy little scripting language

    +
    +
    +
    +
    + + +
    +

    Slots and Handles

    +

    With wrenInterpret(), we can execute code, but that code can’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.

    +

    To make our Wren code useful, 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: slots and +handles.

    +

    The Slot Array #

    +

    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.

    +

    The array is zero-based, and each slot can hold a value of any type. It is +dynamically sized, but it’s your responsibility to ensure there are enough slots +before you use them. You do this by calling:

    +
    wrenEnsureSlots(WrenVM* vm, int slotCount);
    +
    + + +

    This grows the slot array if needed to ensure that many slots are available. If +it’s already big enough, this does nothing. You’ll typically call this once +before populating the slots with data that you want to send to Wren.

    +
    wrenEnsureSlots(vm, 4); 
    +// Can now use slots 0 through 3, inclusive.
    +
    + + +

    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 wrenCall() or +wrenInterpret(), or returning from a foreign method.

    +

    If you read or write from a slot that you haven’t ensured is valid, Wren makes +no guarantees about what will happen. I’ve heard rumors of smoke and feathers +flying out of a user’s computer.

    +

    If you want to see how big the slot array is, use:

    +
    int wrenGetSlotCount(WrenVM* vm);
    +
    + + +

    It returns the number of slots in the array. Note that this may be higher than +the size you’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.

    +

    When Wren calls your C code and passes data to you, it ensures there are +enough slots for the objects it is sending you.

    +

    Writing slots #

    +

    Once you have some slots, you store data in them using a number of functions all +named wrenSetSlot<type>() where <type> is the kind of data. We’ll start with +the simple ones:

    +
    void wrenSetSlotBool(WrenVM* vm, int slot, bool value); 
    +void wrenSetSlotDouble(WrenVM* vm, int slot, double value); 
    +void wrenSetSlotNull(WrenVM* vm, int slot);
    +
    + + +

    Each of these takes a primitive C value and converts it to the corresponding +Wren value. (Since Wren’s native number type is a double, there’s not +really much conversion going on, but you get the idea.)

    +

    You can also pass string data to Wren:

    +
    void wrenSetSlotBytes(WrenVM* vm, int slot, 
    +                      const char* bytes, size_t length);
    +
    +void wrenSetSlotString(WrenVM* vm, int slot, 
    +                       const char* text);
    +
    + + +

    Both of these copy the bytes into a new String object managed by Wren’s +garbage collector, so you can free your copy of it after you call this. The +difference between the two is that wrenSetSlotBytes() takes an explicit +length. Since Wren strings may contain arbitrary byte values, including the null +byte, this lets you pass those in. It’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 strlen().

    +

    Reading slots #

    +

    You can, of course, also pull data out of slots. Here are the simple ones:

    +
    bool wrenGetSlotBool(WrenVM* vm, int slot); 
    +double wrenGetSlotDouble(WrenVM* vm, int slot);
    +
    + + +

    These take a Wren value of the corresponding type and convert it to its raw C +representation. For strings, we have:

    +
    const char* wrenGetSlotString(WrenVM* vm, int slot); 
    +const char* wrenGetSlotBytes(WrenVM* vm, int slot, 
    +                             int* length);
    +
    + + +

    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 length. 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’t move or free +the data.

    +

    With these functions, you are going from dynamically typed Wren data to +statically typed C. It’s up to you 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’re gonna have a bad time.

    +

    Fortunately, you usually know what type of data you have in a slot. If not, you +can ask:

    +
    WrenType wrenGetSlotType(WrenVM* vm, int slot);
    +
    + + +

    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 WREN_TYPE_UNKNOWN. If you want to move that +kind of data between Wren and C, you’ll have to pull the object apart into +simple primitive values first or use a foreign class.

    +

    Looking up variables #

    +

    There are a few other utility functions that move data into and out of slots. +Here’s the first:

    +
    void wrenGetVariable(WrenVM* vm, const char* module, 
    +                     const char* name, int slot);
    +
    + + +

    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.

    +

    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’s string table. You might want to avoid +calling this in the middle of a hot loop where performance is critical. Instead, +it’s faster to look up the variable once outside the loop and store a reference +to the object using a handle.

    +

    Working with lists #

    +

    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. List objects work well for that, so the C API lets you work +with them directly.

    +

    You can create a new empty list from C using:

    +
    void wrenSetSlotNewList(WrenVM* vm, int slot);
    +
    + + +

    It stores the resulting list in the given slot. If you have a list in a +slot—either one you created from C or from Wren—you can add elements +to it using:

    +
    void wrenInsertInList(WrenVM* vm, int listSlot, int index, 
    +                      int elementSlot);
    +
    + + +

    That’s a lot of int parameters:

    +
      +
    • +

      listSlot is the slot where the list object is stored. That’s the list you’ll + be modifying. If you created the list from C, it will be the slot you passed + to wrenSetSlotNewList().

      +
    • +
    • +

      index 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 -1 appends to the list.

      +
    • +
    • +

      elementSlot identifies the slot where the value you want to insert in the + list can be found.

      +
    • +
    +

    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’d need +wrenInsertInListDouble(), wrenInsertInListBool(), etc.

    +

    Handles #

    +

    Slots are pretty good for shuttling primitive data between C and Wren, but they +have two limitations:

    +
      +
    1. +

      They are short-lived. As soon as you execute some more Wren code, the + slot array is invalidated. You can’t use a slot to persistently keep track + of some object.

      +
    2. +
    3. +

      They only support primitive types. A slot can hold a value of any type, + but the C API we’ve seen so far doesn’t let you do anything with values + that aren’t simple primitive ones. If you want to grab a reference to, + say, an instance of some class, how do you do it?

      +
    4. +
    +

    To address those, we have handles. A handle wraps a reference to an object of +any kind—strings, numbers, instances of classes, collections, whatever. +You create a handle using this:

    +
    WrenHandle* wrenGetSlotHandle(WrenVM* vm, int slot);
    +
    + + +

    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:

    +
    void wrenSetSlotHandle(WrenVM* vm, int slot, WrenHandle* handle);
    +
    + + +

    Note that this doesn’t invalidate your WrenHandle. You can still keep using it.

    +

    Retaining and releasing handles #

    +

    A handle is an opaque wrapper around an object of any type, but just as +important, it’s a persistent 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.

    +

    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’t freed. But what if you don’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:

    +
    void wrenReleaseHandle(WrenVM* vm, WrenHandle* handle);
    +
    + + +

    This does not immediately delete the wrapped object—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.

    +

    You must release every WrenHandle you’ve created before shutting down the VM. +Wren warns you if you don’t, since it implies you’ve probably leaked a resource +somewhere.

    +

    Now we know how to pass values between Wren and C, but we don’t know how to +actually do anything with them. Next, we’ll learn how to use slots to pass +parameters to a Wren method from C…

    +

    Calling Wren from C → +← Introduction

    +
    +
    + + + diff --git a/embedding/storing-c-data.html b/embedding/storing-c-data.html new file mode 100644 index 00000000..dccee90b --- /dev/null +++ b/embedding/storing-c-data.html @@ -0,0 +1,413 @@ + + + + +Storing C Data – Wren + + + + + + +
    +
    +
    +

    wren

    +

    a classy little scripting language

    +
    +
    +
    +
    + + +
    +

    Storing C Data

    +

    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’s dynamism allows. You may want a Wren object +that represents a native resource like a file handle or database connection.

    +

    For those cases, you can define a foreign class, 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 foreign methods +written in C. It produces real Wren objects that you can pass around, do is +checks on, etc. But it also wraps a blob of raw memory that is opaque to Wren +but accessible from C.

    +

    Defining a Foreign Class #

    +

    You define one like so:

    +
    foreign class Point { 
    +  // ...
    +}
    +
    + + +

    The foreign 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.

    +

    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 how foreign methods are bound. When you configure +the VM, you set the bindForeignClassFn field in WrenConfiguration to point +to a C callback you define. Its signature must be:

    +
    WrenForeignClassMethods bindForeignClass( 
    +    WrenVM* vm, const char* module, const char* className);
    +
    + + +

    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’s responsibility is to return one of these +structs:

    +
    typedef struct 
    +{ 
    +  WrenForeignMethodFn allocate; 
    +  WrenFinalizerFn finalize; 
    +} WrenForeignClassMethods;
    +
    + + +

    It’s a pair of function pointers. The first, allocate, is called by Wren +whenever an instance of the foreign class is created. (We’ll get to the optional +finalize callback later.) The allocation callback has the same signature as a +foreign method:

    +
    void allocate(WrenVM* vm);
    +
    + + +

    Initializing an Instance #

    +

    When you create an instance of a foreign class by calling one its +constructors, Wren invokes the allocate 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:

    +
    void* wrenSetSlotNewForeign(WrenVM* vm, 
    +    int slot, int classSlot, size_t size);
    +
    + + +

    Like other slot manipulation functions, 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:

    +
      +
    • +

      The slot parameter is the destination slot where the new foreign object + should be placed. When you’re calling this in a foreign class’s allocate + callback, this should be 0.

      +
    • +
    • +

      The classSlot 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’ll pass 0 for + this too.

      +
    • +
    • +

      Finally, the size 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.

      +
    • +
    +

    So, for example, if you wanted to create a foreign instance that contains eight +bytes of C data, you’d call:

    +
    void* data = wrenSetSlotNewForeign(vm, 0, 0, 8);
    +
    + + +

    The value returned by wrenSetSlotNewForeign() 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.

    +

    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.

    +

    After the allocate callback returns, the class’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.

    +

    Accessing Foreign Data #

    +

    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’t care.

    +

    Once you have a foreign instance in a slot, you can access the raw bytes it +stores by calling:

    +
    void* wrenGetSlotForeign(WrenVM* vm, int slot);
    +
    + + +

    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’t do any +type or bounds checking, so it’s on you to make sure the object in that slot +actually is an instance of a foreign class and contains as much memory as you +access.

    +

    Given that void pointer, you can now freely read and modify the data it points +to. They’re your bits, Wren just holds them for you.

    +

    Freeing Resources #

    +

    If your foreign instances are just holding memory and you’re OK with Wren’s +garbage collector managing the lifetime of that memory, then you’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.

    +

    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’t get left open when the +GC frees the foreign instance.

    +

    Of course, you can (and usually should) add a method on your foreign class, like +close() 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’t leaked.

    +

    To that end, you can also provide a finalizer function when binding the +foreign class. That’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’s resources.

    +

    Because this is called during the middle of a garbage collection, you do not +have unfettered access to the VM. It’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.

    +

    Instead, the finalize callback’s signature is only:

    +
    void finalize(void* data);
    +
    + + +

    Wren gives you the pointer to your foreign function’s memory, and that’s it. The +only thing you should do inside a finalizer is release any external resources +referenced by that memory.

    +

    A Full Example #

    +

    That’s a lot to take in, so let’s walk through a full example of a foreign class +with a finalizer and a couple of methods. We’ll do a File class that wraps the +C standard file API.

    +

    In Wren, the class we want looks like this:

    +
    foreign class File { 
    +  construct create(path) {}
    +
    +  foreign write(text) 
    +  foreign close() 
    +}
    +
    + + +

    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.

    +

    Setting up the VM #

    +

    Over in the host, first we’ll set up the VM:

    +
    #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, "some code...");
    +
    +  return 0; 
    +}
    +
    + + +

    Binding the foreign class #

    +

    We give the VM two callbacks. The first is for wiring up the foreign class +itself:

    +
    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; 
    +}
    +
    + + +

    When our binding callback is invoked for the File class, we return the allocate +and finalize functions the VM should call. Allocation looks like:

    +
    #include <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"); 
    +}
    +
    + + +

    First we create the instance by calling wrenSetSlotNewForeign(). We tell it to +add enough extra bytes to store a FILE* in it, which is C’s representation of +a file handle. We’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 FILE**. In +most cases, you’ll just have a single *.

    +

    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 – a FILE* – and we +store that back into the foreign instance using *file. Now we have a foreign +object that wraps an open file handle.

    +

    The finalizer simply casts the foreign instance’s data back to the proper type +and closes the file:

    +
    void fileFinalize(void* data) 
    +{ 
    +  closeFile((FILE**)file); 
    +}
    +
    + + +

    It uses this little utility function:

    +
    static void closeFile(FILE** file) 
    +{ 
    +  // Already closed.
    +  if (*file == NULL) return;
    +
    +  fclose(*file); 
    +  *file = NULL; 
    +}
    +
    + + +

    This closes the file (if it’s not already closed) and also nulls out the file +handle so that we don’t try to use the file after it’s been closed.

    +

    Binding the foreign methods #

    +

    That’s the foreign class part. Now we have a couple of foreign methods to +handle. The host tells the VM how to find them by giving Wren a pointer to this +function:

    +
    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; 
    +}
    +
    + + +

    When Wren calls this, we look at the class and method name to figure out which +method it’s binding, and then return a pointer to the appropriate function. The +foreign method for writing to the file is:

    +
    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); 
    +}
    +
    + + +

    We use wrenGetSlotForeign() 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 itself a pointer, we get a pointer to a +pointer.

    +

    We do a little sanity checking to make sure the user isn’t writing to a file +they already closed. If not, we call fwrite() to write to the file.

    +

    The other method is close() to let them explicitly close the file:

    +
    void fileClose(WrenVM* vm) 
    +{ 
    +  closeFile(file); 
    +}
    +
    + + +

    It uses the same helper we defined above. And that’s it, a complete foreign +class with a finalizer and a couple of foreign methods. In Wren, you can use it +like so:

    +
    var file = File.create("some/path.txt") 
    +file.write("some text") 
    +file.close()
    +
    + + +

    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.

    +

    Configuring the VM → +← Calling C from Wren

    +
    +
    + + + diff --git a/error-handling.html b/error-handling.html index d624d89e..025384d9 100644 --- a/error-handling.html +++ b/error-handling.html @@ -45,7 +45,7 @@

    reference

    @@ -85,7 +85,7 @@ @@ -99,26 +99,26 @@

    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:

    -
    1 + * 2
    +
    1 + * 2
     

    Wren detects these errors as soon as it tries to read your code. When it hits one, you get a friendly error message, like:

    -
    [main line 1] Error on '*': Unexpected token for expression.
    +
    [main 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:

    -
    var a = "once" 
    +
    var a = "once" 
     var a = "twice"
     

    Wren tells you:

    -
    [main line 2] Error on 'a': Top-level variable is already defined.
    +
    [main line 2] Error on 'a': Top-level variable is already defined.
     
    @@ -136,7 +136,7 @@ statically. Since they can’t be found until your code is run, they’r 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:

    -
    class Foo { 
    +
    class Foo { 
       construct new() {} 
     }
     
    @@ -146,7 +146,7 @@ superclasses) don’t define that method, there’s nothing Wren can do:
     
     
     

    If you run this, Wren will print:

    -
    Foo does not implement method 'someRandomMethod'.
    +
    Foo does not implement method 'someRandomMethod'.
     
    @@ -158,18 +158,18 @@ 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:

    -
    var list = ["a", "b", "c"] 
    +
    var list = ["a", "b", "c"] 
     list["1"]
     

    This exits with:

    -
    Subscript must be a number or a range. 
    +
    Subscript must be a number or a range. 
     [main line 2] in (script)
     
    -

    These are the most two common kinds of runtime errors, but there are others. +

    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.

    Handling runtime errors #

    @@ -184,7 +184,7 @@ invoked that one, all the way to the main fiber, and then exit the VM.

    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:

    -
    var fiber = Fiber.new { 
    +
    var fiber = Fiber.new { 
       123.badMethod 
     }
     
    @@ -194,19 +194,19 @@ error message as a string. 

    It prints:

    -
    Caught error: Num does not implement method 'badMethod'.
    +
    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:

    -
    System.print(fiber.error)
    +
    System.print(fiber.error)
     

    This also prints:

    -
    Num does not implement method 'badMethod'.
    +
    Num does not implement method 'badMethod'.
     
    @@ -217,11 +217,12 @@ errors generated in fibers that are invoked by the one you called tryMost 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:

    -
    Fiber.abort("Something bad happened")
    +
    Fiber.abort("Something bad happened")
     

    You must pass in an error message, and it must be a string.

    +

    If the provided message is null, no runtime error is raised.

    Failures #

    The last flavor of errors is the highest-level one. All of the above errors indicate bugs—places where the code itself is incorrect. But some diff --git a/expressions.html b/expressions.html deleted file mode 100644 index f1e1b746..00000000 --- a/expressions.html +++ /dev/null @@ -1,414 +0,0 @@ - - - - -Expressions – Wren - - - - - - -

    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Expressions

    -

    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 -types—numbers, strings and friends—have literal forms as do the -built in collections: lists and maps.

    -

    Functions do not have standalone a literal form. Instead, -they are created by passing a block -argument to a method.

    -

    Identifiers #

    -

    Names in expressions come in a few flavors. A name that starts with an -underscore denotes a field, a piece of data stored in an -instance of a class. All other names refer to -variables.

    -

    Method calls #

    -

    Wren is object-oriented, so most code consists of method calls. Most of them -look like so:

    -
    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 ():

    -
    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:

    -
    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—number of parameters—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, it may be passed as a block -argument:

    -
    blondie.callMeAt(867, 5309) {
    -  System.print("This is the body!")
    -}
    -
    - - -

    Semantically, all method calls work like so:

    -
      -
    1. Evaluate the receiver and arguments.
    2. -
    3. Look up the method on the receiver's class.
    4. -
    5. Invoke it, passing in the arguments.
    6. -
    -

    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. 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:

    -
    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:

    -
    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:

    -
    ! ~ -
    -
    - - -

    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—they have operators on either side. They are:

    -
    == != < > <= >= .. ... | & + - * / %
    -
    - - -

    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 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, then the value of the right operand is stored in -the referenced variable or field.

    -

    The left-hand side may also be a method call, like:

    -
    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:

    -
    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:

    -
    matrix[3, 5]
    -
    - - -

    Subscripts may also be used on the left-hand side of an assignment:

    -
    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 structures than operators because -they conditionally execute some code—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, it returns that value. Otherwise it evaluates -and returns the right-hand argument.

    -
    System.print(false && 1)  // false
    -System.print(1 && 2)      // 2
    -
    - - -

    An || ("logical or") expression is reversed. If the left-hand argument is -true, it's returned, otherwise the right-hand -argument is evaluated and returned:

    -
    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.

    -
    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).

    -
    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—which operators bind more tightly than others—and -associativity—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:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    PrecOperatorDescriptionAssoc
    1() [] .Grouping, Subscript, Method callLeft
    2- ! ~Negate, Not, ComplementRight
    3* / %Multiply, Divide, ModuloLeft
    4+ -Add, SubtractLeft
    5.. ...Inclusive range, Exclusive rangeLeft
    6<< >>Left shift, Right shiftLeft
    7< <= > >=ComparisonLeft
    8==EqualsLeft
    8!=Not equalLeft
    9&Bitwise andLeft
    10^Bitwise xorLeft
    11|Bitwise orLeft
    12isType testLeft
    13&&Logical andLeft
    14||Logical orLeft
    15?:ConditionalRight
    16=AssignRight
    -
    -
    - - - diff --git a/fibers.html b/fibers.html deleted file mode 100644 index 6c982977..00000000 --- a/fibers.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - -Fibers – Wren - - - - - - -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Fibers

    -

    Fibers are a key part of Wren. They form its execution model, its concurrency -story, and take the place of exceptions in error -handling.

    -

    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:

    -
    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.

    -

    Invoking fibers #

    -

    Once you've created a fiber, you can invoke it (which suspends the current -fiber) by calling its call() method:

    -
    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:

    -
    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:

    -
    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:

    -
    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:

    -
    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:

    -
    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—they can suspend from anywhere in the callstack. For -example:

    -
    var fiber = Fiber.new {
    -  (1..10).map {|i|
    -    Fiber.yield(i)
    -  }
    -}
    -
    - - -

    Here, we're calling yield() from within a function 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.

    -
    -
    - - - diff --git a/functions.html b/functions.html index f87a2218..df9c1635 100644 --- a/functions.html +++ b/functions.html @@ -45,7 +45,7 @@

    reference

    @@ -85,7 +85,7 @@ @@ -109,7 +109,7 @@ 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:

    -
    blondie.callMe { 
    +
    blondie.callMe { 
       System.print("This is the body!") 
     }
     
    @@ -121,17 +121,19 @@ following block—everything between that p curly braces.

    Methods that take a block argument receive it as a normal parameter. callMe could be defined like so:

    -
    class Blondie { 
    +
    class Blondie { 
       callMe(fn) { 
         // Call it...
       } 
     }
    +
    +var blondie = Blondie.new()
     

    A method can take other arguments in addition to the block. They appear before the block just like a regular argument list. For example:

    -
    blondie.callMeAt(867, 5309) { 
    +
    blondie.callMeAt(867, 5309) { 
       System.print("This is the body!") 
     }
     
    @@ -140,7 +142,7 @@ the block just like a regular argument list. For example:

    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:

    -
    var someFn = // Get a function...
    +
    var someFn = // Get a function...
     blondie.callMe(someFn)
     
    @@ -149,7 +151,7 @@ argument:

    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:

    -
    var someFn = Fn.new { 
    +
    var someFn = Fn.new { 
       System.print("Hi!") 
     }
     
    @@ -160,7 +162,7 @@ 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:

    -
    class Blondie { 
    +
    class Blondie { 
       callMe(fn) { 
         fn.call() 
       } 
    @@ -171,7 +173,7 @@ so by calling a method on it: 

    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.

    -
    class FakeFn { 
    +
    class FakeFn { 
       call() { 
         System.print("I'm feeling functional!") 
       } 
    @@ -186,7 +188,7 @@ method is dynamically-dispatched like any other, so you can define your own
     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: 

    -
    blondie.callMe {|first, last| 
    +
    blondie.callMe {|first, last| 
       System.print("Hi, " + first + " " + last + "!") 
     }
     
    @@ -194,7 +196,7 @@ of the body, like so:

    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:

    -
    class Blondie { 
    +
    class Blondie { 
       callMe(fn) { 
         fn.call("Debbie", "Harry") 
       } 
    @@ -212,7 +214,7 @@ 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:

    -
    Fn.new { "return value" }
    +
    Fn.new { "return value" }
     
     Fn.new { 
       return "return value" 
    @@ -224,7 +226,7 @@ same thing: 

    As you expect, functions are closures—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:

    -
    class Counter { 
    +
    class Counter { 
       static create() { 
         var i = 0 
         return Fn.new { i = i + 1 } 
    @@ -237,7 +239,7 @@ leaving the scope where the function is defined: 

    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 toi:

    -
    var counter = Counter.create() 
    +
    var counter = Counter.create() 
     System.print(counter.call()) 1
     System.print(counter.call()) 2
     System.print(counter.call()) 3
    diff --git a/getting-started.html b/getting-started.html
    index 8041b31e..6ff3ef96 100644
    --- a/getting-started.html
    +++ b/getting-started.html
    @@ -45,7 +45,7 @@
           

    reference

    @@ -85,7 +85,7 @@ @@ -114,10 +114,10 @@ few dependencies are nice that way. “Wren” encompasses two separate

If you’re on a Unix or Mac and you can rock a command line, it’s just:

-
$ git clone https://github.com/munificent/wren.git
-$ cd wren 
-$ make 
-$ ./wren
+
$ git clone https://github.com/munificent/wren.git
+$ cd wren 
+$ make 
+$ ./wren
 
@@ -130,7 +130,7 @@ Windows brethren, util/msvc2013 contains a Visual Studio solution. 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:

-
$ make vm
+
$ make vm
 
@@ -140,12 +140,12 @@ libuv since it isn’t needed.

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:

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

Or a little more exciting:

-
for (i in 1..10) System.print("Counting up %(i)")
+
for (i in 1..10) System.print("Counting up %(i)")
 
@@ -155,7 +155,7 @@ your computer to the ground and storm off.

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:

-
for (yPixel in 0...24) { 
+
for (yPixel in 0...24) { 
   var y = yPixel / 12 - 1 
   for (xPixel in 0...80) { 
     var x = xPixel / 30 - 2 
@@ -178,7 +178,7 @@ your favorite text editor and paste this into it: 

Now run:

-
$ ./wren my_script.wren
+
$ ./wren my_script.wren
 
diff --git a/index.html b/index.html index ce2df73a..dd616b31 100644 --- a/index.html +++ b/index.html @@ -45,7 +45,7 @@

reference

@@ -85,7 +85,7 @@ @@ -98,7 +98,7 @@

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.

-
System.print("Hello, world!")
+
System.print("Hello, world!")
 
 class Wren { 
   flyTo(city) { 
@@ -138,7 +138,7 @@ a familiar, modern syntax. 

  • 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. It compiles cleanly as C99, C++98 + and an easy-to-use C API. It compiles cleanly as C99, C++98 or anything later.

  • diff --git a/lists.html b/lists.html index ddf8d053..ded300e2 100644 --- a/lists.html +++ b/lists.html @@ -45,7 +45,7 @@

    reference

    @@ -85,7 +85,7 @@ @@ -98,7 +98,7 @@

    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:

    -
    [1, "banana", true]
    +
    [1, "banana", true]
     
    @@ -108,28 +108,28 @@ have to be the same type.

    You can access an element from a list by calling the subscript operator on it with the index of the element you want. Like most languages, indexes start at zero:

    -
    var hirsute = ["sideburns", "porkchops", "'stache", "goatee"] 
    +
    var hirsute = ["sideburns", "porkchops", "'stache", "goatee"] 
     System.print(hirsute[0]) sideburns
     System.print(hirsute[1]) porkchops
     

    Negative indices counts backwards from the end:

    -
    System.print(hirsute[-1]) goatee
    +
    System.print(hirsute[-1]) goatee
     System.print(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:

    -
    System.print(hirsute.count) 4
    +
    System.print(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 to the subscript operator, like so:

    -
    System.print(hirsute[1..2]) [porkchops, 'stache]
    +
    System.print(hirsute[1..2]) [porkchops, 'stache]
     
    @@ -138,27 +138,27 @@ 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:

    -
    hirsute[0..-1]
    +
    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:

    -
    hirsute[1] = "muttonchops" 
    +
    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:

    -
    hirsute.add("goatee") 
    +
    hirsute.add("goatee") 
     System.print(hirsute.count) 4
     

    You can insert a new element at a specific position using insert:

    -
    hirsute.insert(2, "soul patch")
    +
    hirsute.insert(2, "soul patch")
     
    @@ -168,7 +168,7 @@ 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:

    -
    var letters = ["a", "b", "c"] 
    +
    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.
    @@ -180,19 +180,19 @@ back. Doing so counts back from the size of the list after it’s g
     

    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:

    -
    var letters = ["a", "b", "c", "d"] 
    +
    var letters = ["a", "b", "c", "d"] 
     letters.removeAt(1) 
     System.print(letters) [a, c, d]
     

    The removeAt method returns the removed item:

    -
    System.print(letters.removeAt(1)) c
    +
    System.print(letters.removeAt(1)) c
     

    If you want to remove everything from the list, you can clear it:

    -
    hirsute.clear() 
    +
    hirsute.clear() 
     System.print(hirsute) []
     
    diff --git a/maps.html b/maps.html index 52c639ff..c1bc83c6 100644 --- a/maps.html +++ b/maps.html @@ -45,7 +45,7 @@

    reference

    @@ -85,7 +85,7 @@ @@ -100,7 +100,7 @@ maps a key to a value. The same data structure has a variety o 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:

    -
    { 
    +
    { 
       "George": "Harrison", 
       "John":   "Lennon", 
       "Paul":   "McCartney", 
    @@ -118,12 +118,13 @@ value. Keys have a few limitations. They must be one of the immutable built-in
     value types in Wren. That means a number, string, range, bool, or null. 
     You can also use a class object as a key. 

    The reason for this limitation—and the reason maps are called “hash -tables” in other languages—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 +tables” in other languages—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 using the subscript operator:

    -
    var capitals = {} 
    +
    var capitals = {} 
     capitals["Georgia"] = "Atlanta" 
     capitals["Idaho"] = "Boise" 
     capitals["Maine"] = "Augusta"
    @@ -135,7 +136,7 @@ value. If the key is already there, this just replaces its value. 

    Looking up values #

    To find the value associated with some key, again you use your friend the subscript operator:

    -
    System.print(capitals["Idaho"]) Boise
    +
    System.print(capitals["Idaho"]) Boise
     
    @@ -143,7 +144,7 @@ subscript operator:

    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():

    -
    var belief = {"nihilism": null}
    +
    var belief = {"nihilism": null}
     
     System.print(belief["nihilism"]) null (though key exists)
     System.print(belief["solipsism"]) null
    @@ -153,27 +154,27 @@ doesn’t necessarily mean the key wasn’t found. 

    You can see how many entries a map contains using count:

    -
    System.print(capitals.count) 3
    +
    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:

    -
    capitals.remove("Maine") 
    +
    capitals.remove("Maine") 
     System.print(capitals.containsKey("Maine")) false
     

    If the key was found, this returns the value that was associated with it:

    -
    System.print(capitals.remove("Georgia")) Atlanta
    +
    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, like with lists, you call clear():

    -
    capitals.clear() 
    +
    capitals.clear() 
     System.print(capitals.count) 0
     
    @@ -186,7 +187,7 @@ For that, map exposes two methods: keys and values.

    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:

    -
    var birds = { 
    +
    var birds = { 
       "Arizona": "Cactus wren", 
       "Hawaii": "Nēnē", 
       "Ohio": "Northern Cardinal" 
    diff --git a/method-calls.html b/method-calls.html
    index 677032f9..8818b936 100644
    --- a/method-calls.html
    +++ b/method-calls.html
    @@ -45,7 +45,7 @@
           

    reference

    @@ -85,7 +85,7 @@ @@ -97,19 +97,19 @@

    Method Calls

    Wren is deeply object oriented, so most code consists of invoking methods on objects, usually something like this:

    -
    System.print("Heyoo!") Heyoo!
    +
    System.print("Heyoo!") Heyoo!
     

    You have a receiver expression (here System) followed by a ., then a name (print) and an argument list in parentheses (("Heyoo!")). Multiple arguments are separated by commas:

    -
    list.insert("item", 3)
    +
    list.insert(3, "item")
     

    The argument list can also be empty:

    -
    list.clear()
    +
    list.clear()
     
    @@ -127,7 +127,7 @@ takes. In technical terms, this means you can overload by arity.

    For example, the Random 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:

    -
    var random = Random.new() 
    +
    var random = Random.new() 
     random.int(3, 10) 
     random.int(4)
     
    @@ -148,7 +148,7 @@ any “if I got two arguments do this…” logic.

    Getters #

    Some methods exist to expose a stored or computed property of an object. These are getters and have no parentheses:

    -
    "string".count    6
    +
    "string".count    6
     (1..10).min       1
     1.23.sin          0.9424888019317
     [1, 2, 3].isEmpty false
    @@ -158,13 +158,13 @@ are getters and have no parentheses: 

    Sometimes you have a method that doesn’t need any parameters, but modifies the object or has some other side effect. For those, it’s better to use empty parentheses:

    -
    list.clear()
    +
    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:

    -
    Fiber.yield() 
    +
    Fiber.yield() 
     Fiber.yield("value")
     
    @@ -173,7 +173,7 @@ Fiber.yield("value") part of the signature, so count and count() have different signatures. Unlike Ruby’s optional parentheses, Wren wants to make sure you call a getter like a getter and a () method like a () method. These don’t work:

    -
    "string".count() 
    +
    "string".count() 
     [1, 2, 3].clear
     
    @@ -181,7 +181,7 @@ like a getter and a () method like a () method. These

    Setters #

    A getter lets an object expose a public “property” that you can read. Likewise, a setter let you write to a property:

    -
    person.height = 74 // Grew up!
    +
    person.height = 74 // Grew up!
     
    @@ -194,7 +194,7 @@ read/write properties.

    Operators #

    Wren has most of the same operators you know and love with the same precedence and associativity. We have three prefix operators:

    -
    ! ~ -
    +
    ! ~ -
     
    @@ -202,7 +202,7 @@ and associativity. We have three prefix operators:

    expression like !possible means “call the ! method on possible”.

    We also have a slew of infix operators—they have operands on both sides. They are:

    -
    * / % + - .. ... << >> < <= > >= == != & ^ | is
    +
    * / % + - .. ... << >> < <= > >= == != & ^ | is
     
    @@ -221,7 +221,7 @@ like mocks or proxies where you want an object to masquerade as a certain class.

    Subscripts #

    Another familiar syntax from math class is subscripting using square brackets ([]). It’s handy for working with collection-like objects. For example:

    -
    list[0]    // Get the first item in a list.
    +
    list[0]    // Get the first item in a list.
     map["key"] // Get the value associated with "key".
     
    @@ -229,13 +229,13 @@ like mocks or proxies where you want an object to masquerade as a certain class.

    You know the refrain by now. In Wren, these are method calls. In the above examples, the signature is [_]. Subscript operators may also take multiple arguments, which is useful for things like multi-dimensional arrays:

    -
    matrix[3, 5]
    +
    matrix[3, 5]
     

    These examples are subscript “getters”, and there are also corresponding subscript setters:

    -
    list[0] = "item" 
    +
    list[0] = "item" 
     map["key"] = "value"
     
    diff --git a/modularity.html b/modularity.html index ec7dde71..bbe9628b 100644 --- a/modularity.html +++ b/modularity.html @@ -45,7 +45,7 @@

    reference

    @@ -85,7 +85,7 @@ @@ -119,7 +119,7 @@ a name collision. Each module is, well, modular.

    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:

    -
    import "beverages" for Coffee, Tea
    +
    import "beverages" for Coffee, Tea
     
    @@ -128,7 +128,7 @@ looks up two top-level variables, Coffee and Tea in this module with their values.

    This statement can appear anywhere a variable declaration is allowed, even inside blocks:

    -
    if (thirsty) { 
    +
    if (thirsty) { 
       import "beverages" for Coffee, Tea 
     }
     
    @@ -136,7 +136,7 @@ inside blocks:

    If you want to load a module, but not bind any variables from it, you can omit the for clause:

    -
    import "some_imperative_code"
    +
    import "some_imperative_code"
     
    @@ -156,7 +156,7 @@ 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:

    -
    WrenConfiguration config; 
    +
    WrenConfiguration config; 
     config.loadModuleFn = loadModule;
     
     // Other configuration...
    @@ -166,7 +166,7 @@ function: 

    That function has this signature:

    -
    char* WrenLoadModuleFn(WrenVM* vm, const char* name);
    +
    char* WrenLoadModuleFn(WrenVM* vm, const char* name);
     
    @@ -181,12 +181,12 @@ found. When you do this, Wren will report it as a runtime error.

    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:

    -
    $ wren /code/my_program.wren
    +
    $ wren /code/my_program.wren
     

    And that main module has:

    -
    import "some/module"
    +
    import "some/module"
     
    @@ -216,7 +216,7 @@ These are simply variables declared outside of any method or function.

    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:

    -
    import "beverages" for Coffee, Tea
    +
    import "beverages" for Coffee, Tea
     
    @@ -236,7 +236,7 @@ rarely makes a difference.

    Earlier, I described a program’s 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:

    -
    // main.wren
    +
    // main.wren
     import "a" 
     import "b"
     
    @@ -276,7 +276,7 @@ the registry before it is executed. This means if an import for that sa
     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:

    -
    // main.wren
    +
    // main.wren
     import "a"
     
     // a.wren
    @@ -292,7 +292,7 @@ it will be found in the registry and the cycle is short-circuited. 

    This program runs successfully and prints:

    -
    start a 
    +
    start a 
     start b 
     end b 
     end a
    @@ -300,7 +300,7 @@ end a
     
     
     

    Where you have to be careful is binding variables. Consider:

    -
    // main.wren
    +
    // main.wren
     import "a"
     
     // a.wren
    @@ -325,7 +325,7 @@ get: 

    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:

    -
    // main.wren
    +
    // main.wren
     import "a"
     
     // a.wren
    diff --git a/modules.html b/modules.html
    deleted file mode 100644
    index de739af0..00000000
    --- a/modules.html
    +++ /dev/null
    @@ -1,330 +0,0 @@
    -
    -
    -
    -
    -Modules – Wren
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    wren

    -

    a classy little scripting language

    -
    -
    -
    -
    - -
    -

    Modules

    -

    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. -
    3. -

      You want to reuse pieces of them across different programs.

      -
    4. -
    -

    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:

    -
    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:

    -
    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:

    -
    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. -
    3. Execute the imported module's code.
    4. -
    5. Bind new variables in the importing module to values defined in the imported module.
    6. -
    -

    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—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:

    -
    WrenConfiguration config;
    -config.loadModuleFn = loadModule;
    -
    -// Other configuration...
    -
    -WrenVM* vm = wrenNewVM(&config);
    -
    - - -

    That function has this signature:

    -
    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:

    -
    $ wren /code/my_program.wren
    -
    - - -

    And that main module has:

    -
    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—a new fresh top-level scope, -basically—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. -These are simply variables declared outside of any -method or function.

    -

    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:

    -
    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:

    -
    // 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. -
    3. If so, use it.
    4. -
    5. Otherwise, create a new module with the name and store it in the module - registry.
    6. -
    7. Create a fiber for it and execute its code.
    8. -
    -

    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:

    -
    // 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:

    -
    start a
    -start b
    -end b
    -end a
    -
    - - -

    Where you have to be careful is binding variables. Consider:

    -
    // 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. -
    3. Execute import "b" in "a.wren". That suspends "a.wren".
    4. -
    5. Execute import "a" in "b.wren". Since "a" is already in the module map, - this does not suspend it.
    6. -
    -

    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:

    -
    // 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. -
    3. Define A in "a.wren".
    4. -
    5. Execute import "b" in "a.wren". That suspends "a.wren".
    6. -
    7. 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.
    8. -
    9. Define B in "b.wren".
    10. -
    11. Complete "b.wren".
    12. -
    13. Look up B in "b.wren" and bind it in "a.wren".
    14. -
    15. Resume "a.wren".
    16. -
    -

    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.

    -
    -
    - - - diff --git a/modules/core/bool.html b/modules/core/bool.html index 1eacd050..8b618c3c 100644 --- a/modules/core/bool.html +++ b/modules/core/bool.html @@ -83,7 +83,7 @@

    Methods #

    ! operator #

    Returns the logical complement of the value.

    -
    System.print(!true) false
    +
    System.print(!true) false
     System.print(!false) true
     
    diff --git a/modules/core/class.html b/modules/core/class.html index ef67ffb6..6772abd4 100644 --- a/modules/core/class.html +++ b/modules/core/class.html @@ -85,7 +85,7 @@

    The name of the class.

    supertype #

    The superclass of this class.

    -
    class Crustacean {} 
    +
    class Crustacean {} 
     class Crab is Crustacean {}
     
     System.print(Crab.supertype) Crustacean
    @@ -93,12 +93,12 @@
     
     
     

    A class with no explicit superclass implicitly inherits Object:

    -
    System.print(Crustacean.supertype) Object
    +
    System.print(Crustacean.supertype) Object
     

    Object forms the root of the class hierarchy and has no supertype:

    -
    System.print(Object.supertype) null
    +
    System.print(Object.supertype) null
     
    diff --git a/modules/core/fiber.html b/modules/core/fiber.html index d9173c4f..7ec4a6fe 100644 --- a/modules/core/fiber.html +++ b/modules/core/fiber.html @@ -80,27 +80,37 @@

    Fiber Class

    A lightweight coroutine. Here is a gentle introduction.

    +

    Static Methods #

    +

    Fiber.abort(message) #

    +

    Raises a runtime error with the provided message:

    +
    Fiber.abort("Something bad happened.")
    +
    + + +

    If the message is null, does nothing.

    +

    Fiber.current #

    +

    The currently executing fiber.

    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.

    -
    var fiber = Fiber.new { 
    +
    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.

    +

    Typically, you store a reference to the fiber using Fiber.current before +calling this. The fiber can be resumed later by calling or transferring to that +reference. If there are no references to it, it is eventually garbage collected.

    +

    Much like yield(), returns the value passed to call() or transfer() when +the fiber is 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.

    -
    var fiber = Fiber.new { 
    +here means the last fiber that was started using call and not transfer. 

    +
    var fiber = Fiber.new { 
       System.print("Before yield") 
       Fiber.yield() 
       System.print("After yield") 
    @@ -113,9 +123,9 @@ here means the last fiber that was started using call and not 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.

    -
    var fiber = Fiber.new { 
    +

    If a yielded fiber is resumed by calling call() or transfer() with an +argument, yield() returns that value.

    +
    var fiber = Fiber.new { 
       System.print(Fiber.yield()) value
     }
     
    @@ -124,19 +134,20 @@ here means the last fiber that was started using call and not 
    -

    If it was resumed by calling call() or run() with no argument, it returns -null.

    +

    If it was resumed by calling call() or transfer() 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.

    -
    Fiber.yield() 
    +
    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.

    -
    var fiber = Fiber.new { 
    +

    Similar to Fiber.yield but provides a value to return to the parent fiber’s +call.

    +
    var fiber = Fiber.new { 
       Fiber.yield("value") 
     }
     
    @@ -147,7 +158,7 @@ later. 

    Methods #

    call() #

    Starts or resumes the fiber if it is in a paused state.

    -
    var fiber = Fiber.new { 
    +
    var fiber = Fiber.new { 
       System.print("Fiber called") 
       Fiber.yield() 
       System.print("Fiber called again") 
    @@ -162,7 +173,7 @@ later. 

    called it.

    If the called fiber is resuming from a yield, the yield() method returns null in the called fiber.

    -
    var fiber = Fiber.new { 
    +
    var fiber = Fiber.new { 
       System.print(Fiber.yield()) 
     }
     
    @@ -174,7 +185,7 @@ called it. 

    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.

    -
    var fiber = Fiber.new { 
    +
    var fiber = Fiber.new { 
       System.print(Fiber.yield()) 
     }
     
    @@ -183,10 +194,35 @@ called it. 

    +

    error* #

    +

    The error message that was passed when aborting the fiber, or null if the +fiber has not been aborted.

    +
    var fiber = Fiber.new { 
    +  123.badMethod 
    +}
    +
    +fiber.try() 
    +System.print(fiber.error) Num does not implement method 'badMethod'.
    +
    + +

    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() #

    +

    try() #

    +

    Tries to run the fiber. If a runtime error occurs +in the called fiber, the error is captured and is returned as a string.

    +
    var fiber = Fiber.new { 
    +  123.badMethod 
    +}
    +
    +var error = fiber.try() 
    +System.print("Caught error: " + error)
    +
    + + +

    If the called fiber raises an error, it can no longer be used.

    TODO

    transfer(value) #

    TODO

    diff --git a/modules/core/fn.html b/modules/core/fn.html index b44fcfd4..d6726404 100644 --- a/modules/core/fn.html +++ b/modules/core/fn.html @@ -81,12 +81,13 @@

    Fn Class

    A first class function—an object that wraps an executable chunk of code. Here is a friendly introduction.

    +

    Static Methods #

    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 to some other method.

    -
    var fn = Fn.new { 
    +
    var fn = Fn.new { 
       System.print("The body") 
     }
     
    @@ -96,14 +97,14 @@ argument to some other method.

    Methods #

    arity #

    The number of arguments the function requires.

    -
    System.print(Fn.new {}.arity)             0
    +
    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.

    -
    var fn = Fn.new { |arg| 
    +
    var fn = Fn.new { |arg| 
       System.print(arg)     Hello world
     }
     
    diff --git a/modules/core/list.html b/modules/core/list.html
    index 71601939..c5fbf834 100644
    --- a/modules/core/list.html
    +++ b/modules/core/list.html
    @@ -81,6 +81,12 @@
         

    List Class

    Extends Sequence.

    An indexable contiguous collection of elements. More details here.

    +

    Static Methods #

    +

    List.filled(size, element) #

    +

    Creates a new list with size elements, all set to element.

    +

    It is a runtime error if size is not a nonnegative integer.

    +

    List.new() #

    +

    Creates a new empty list. Equivalent to [].

    Methods #

    add(item) #

    Appends item to the end of the list.

    @@ -90,21 +96,21 @@

    The number of elements in the list.

    insert(index, item) #

    Inserts the item at index in the list.

    -
    var list = ["a", "b", "c", "d"] 
    +
    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.

    -
    var list = ["a", "b", "c"] 
    +
    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.

    -
    var list = ["a", "b"] 
    +
    var list = ["a", "b"] 
     list.insert(-1, "d") 
     list.insert(-2, "c") 
     System.print(list) [a, b, c, d]
    @@ -112,7 +118,7 @@
     
     
     

    Returns the inserted item.

    -
    System.print(["a", "c"].insert(1, "b")) b
    +
    System.print(["a", "c"].insert(1, "b")) b
     
    @@ -124,14 +130,14 @@ list.

    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.

    -
    var list = ["a", "b", "c", "d"] 
    +
    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
    +
    System.print(["a", "b", "c"].removeAt(1)) b
     
    @@ -139,7 +145,7 @@ are shifted up to fill in where the removed element was.

    [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.

    -
    var list = ["a", "b", "c"] 
    +
    var list = ["a", "b", "c"] 
     System.print(list[1]) b
     
    @@ -148,7 +154,7 @@ the end of the list where -1 is the last element.

    [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.

    -
    var list = ["a", "b", "c"] 
    +
    var list = ["a", "b", "c"] 
     list[1] = "new" 
     System.print(list) [a, new, c]
     
    diff --git a/modules/core/map.html b/modules/core/map.html index e3b3e306..45f7f8fb 100644 --- a/modules/core/map.html +++ b/modules/core/map.html @@ -103,7 +103,7 @@ 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.

    -
    var map = {"george": "harrison", "ringo": "starr"} 
    +
    var map = {"george": "harrison", "ringo": "starr"} 
     System.print(map["ringo"]) starr
     System.print(map["pete"])  null
     
    diff --git a/modules/core/null.html b/modules/core/null.html index 6dc0c926..ce04cb43 100644 --- a/modules/core/null.html +++ b/modules/core/null.html @@ -82,7 +82,7 @@

    Methods #

    ! operator #

    Returns true, since null is considered false.

    -
    System.print(!null) true
    +
    System.print(!null) true
     
    diff --git a/modules/core/num.html b/modules/core/num.html index ea490c19..6d142ab9 100644 --- a/modules/core/num.html +++ b/modules/core/num.html @@ -86,10 +86,14 @@

    It is a runtime error if value is not a string.

    Num.pi #

    The value of π.

    +

    Num.largest #

    +

    The largest representable numeric value.

    +

    Num.smallest #

    +

    The smallest positive representable numeric value.

    Methods #

    abs #

    The absolute value of the number.

    -
    System.print( (-123).abs ) 123
    +
    System.print( (-123).abs ) 123
     
    @@ -104,7 +108,7 @@ numbers to determine the quadrant of the result.

    ceil #

    Rounds the number up to the nearest integer.

    -
    System.print(1.5.ceil)    2
    +
    System.print(1.5.ceil)    2
     System.print((-3.2).ceil) -3
     
    @@ -113,21 +117,21 @@ numbers to determine the quadrant of the result.

    The cosine of the number.

    floor #

    Rounds the number down to the nearest integer.

    -
    System.print(1.5.floor)    1
    +
    System.print(1.5.floor)    1
     System.print((-3.2).floor) -4
     

    isInfinity #

    Whether the number is positive or negative infinity or not.

    -
    System.print(99999.isInfinity)  false
    +
    System.print(99999.isInfinity)  false
     System.print((1/0).isInfinity)  true
     

    isInteger #

    Whether the number is an integer or has some fractional component.

    -
    System.print(2.isInteger)   true
    +
    System.print(2.isInteger)   true
     System.print(2.3.isInteger) false
     
    @@ -136,6 +140,18 @@ numbers to determine the quadrant of the result.

    Whether the number is not a number. 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.

    +

    log #

    +

    The natural logarithm of the number.

    +

    pow(power) #

    +

    Raises this number (the base) to power. Returns nan if the base is negative.

    +

    round #

    +

    Rounds the number to the nearest integer.

    +
    System.print(1.5.round)    2
    +System.print((-3.2).round) -3
    +System.print((-3.7).round) -4
    +
    + +

    sin #

    The sine of the number.

    sqrt #

    @@ -144,7 +160,7 @@ numbers to determine the quadrant of the result.

    The tangent of the number.

    - operator #

    Negates the number.

    -
    var a = 123 
    +
    var a = 123 
     System.print(-a) -123
     
    @@ -171,12 +187,12 @@ unsigned values. The result is then a 32-bit unsigned number where each bit is

    |(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.

    +true only where the corresponding bits of one or both inputs were true.

    It is a runtime error if other is not a number.

    ..(other) operator #

    Creates a Range representing a consecutive range of numbers from the beginning number to the ending number.

    -
    var range = 1.2..3.4 
    +
    var range = 1.2..3.4 
     System.print(range.min)         1.2
     System.print(range.max)         3.4
     System.print(range.isInclusive) true
    @@ -186,7 +202,7 @@ from the beginning number to the ending number. 

    (other) operator #

    Creates a Range representing a consecutive range of numbers from the beginning number to the ending number not including the ending number.

    -
    var range = 1.2...3.4 
    +
    var range = 1.2...3.4 
     System.print(range.min)         1.2
     System.print(range.max)         3.4
     System.print(range.isInclusive) false
    diff --git a/modules/core/object.html b/modules/core/object.html
    index cc01c440..956e3712 100644
    --- a/modules/core/object.html
    +++ b/modules/core/object.html
    @@ -98,7 +98,7 @@ types by value, and all other objects are compared by
     identity—two objects are equal only if they are the exact same object. 

    is(class) operator #

    Returns true if this object’s class or one of its superclasses is class.

    -
    System.print(123 is Num)     true
    +
    System.print(123 is Num)     true
     System.print("s" is Num)     false
     System.print(null is String) false
     System.print([] is List)     true
    diff --git a/modules/core/range.html b/modules/core/range.html
    index 3e205401..39846954 100644
    --- a/modules/core/range.html
    +++ b/modules/core/range.html
    @@ -80,13 +80,13 @@
       

    Range Class

    A range defines a bounded range of values from a starting point to a possibly -exclusive endpoint. Here is a friendly introduction.

    +exclusive endpoint. Here is a friendly introduction.

    Extends Sequence.

    Methods #

    from #

    The starting point of the range. A range may be backwards, so this can be greater than [to].

    -
    System.print((3..5).min) 3
    +
    System.print((3..5).min) 3
     System.print((4..2).min) 4
     
    @@ -94,7 +94,7 @@ greater than [to].

    to #

    The endpoint of the range. If the range is inclusive, this value is included, otherwise it is not.

    -
    System.print((3..5).min) 5
    +
    System.print((3..5).min) 5
     System.print((4..2).min) 2
     
    @@ -102,7 +102,7 @@ otherwise it is not.

    min #

    The minimum bound of the range. Returns either from, or to, whichever is lower.

    -
    System.print((3..5).min) 3
    +
    System.print((3..5).min) 3
     System.print((4..2).min) 2
     
    @@ -110,14 +110,14 @@ lower.

    max #

    The maximum bound of the range. Returns either from, or to, whichever is greater.

    -
    System.print((3..5).min) 5
    +
    System.print((3..5).min) 5
     System.print((4..2).min) 4
     

    isInclusive #

    Whether or not the range includes to. (from is always included.)

    -
    System.print((3..5).isInclusive)   true
    +
    System.print((3..5).isInclusive)   true
     System.print((3...5).isInclusive)  false
     
    diff --git a/modules/core/sequence.html b/modules/core/sequence.html index a429185e..7e8ebed7 100644 --- a/modules/core/sequence.html +++ b/modules/core/sequence.html @@ -87,7 +87,7 @@ core iterator protocolIterates over the sequence, passing each element to the function predicate. If it returns something false, stops iterating and returns the value. Otherwise, returns true.

    -
    System.print([1, 2, 3].all {|n| n > 2}) false
    +
    System.print([1, 2, 3].all {|n| n > 2}) false
     System.print([1, 2, 3].all {|n| n < 4}) true
     
    @@ -97,7 +97,7 @@ and returns the value. Otherwise, returns true.

    Iterates over the sequence, passing each element to the function predicate. If it returns something true, stops iterating and returns that value. Otherwise, returns false.

    -
    System.print([1, 2, 3].any {|n| n < 1}) false
    +
    System.print([1, 2, 3].any {|n| n < 1}) false
     System.print([1, 2, 3].any {|n| n > 2}) true
     
    @@ -112,14 +112,14 @@ sequence in order to determine how many elements it contains.

    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.

    -
    System.print([1, 2, 3].count {|n| n > 2}) 1
    +
    System.print([1, 2, 3].count {|n| n > 2}) 1
     System.print([1, 2, 3].count {|n| n < 4}) 3
     

    each(function) #

    Iterates over the sequence, passing each element to the given function.

    -
    ["one", "two", "three"].each {|word| System.print(word) }
    +
    ["one", "two", "three"].each {|word| System.print(word) }
     
    @@ -137,7 +137,7 @@ 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.

    -
    var doubles = [1, 2, 3].map {|n| n * 2 } 
    +
    var doubles = [1, 2, 3].map {|n| n * 2 } 
     for (n in doubles) { 
       System.print(n) 2
                       4
    @@ -153,7 +153,7 @@ sequence. 

    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.

    -
    var numbers = [1, 2, 3] 
    +
    var numbers = [1, 2, 3] 
     var doubles = numbers.map {|n| n * 2 }.toList 
     numbers.add(4) 
     System.print(doubles) [2, 4, 6]
    @@ -170,9 +170,20 @@ iteratively updating the accumulator. 

    reduce(seed, function) #

    Similar to above, but uses seed for the initial value of the accumulator. If the sequence is empty, returns seed.

    +

    skip(count) #

    +

    Creates a new sequence that skips the first count elements of the original +sequence.

    +

    The returned sequence is lazy. The first count elements are only skipped +once you start to iterate the returned sequence. Changes to the original +sequence will be reflected in the filtered sequence.

    +

    take(count) #

    +

    Creates a new sequence that iterates only the first count elements of the +original sequence.

    +

    The returned sequence is lazy. Changes to the original sequence will be +reflected in the filtered sequence.

    toList #

    Creates a list containing all the elements in the sequence.

    -
    System.print((1..3).toList)  [1, 2, 3]
    +
    System.print((1..3).toList)  [1, 2, 3]
     
    @@ -182,7 +193,7 @@ the sequence is empty, returns seed.

    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.

    -
    var odds = (1..6).where {|n| n % 2 == 1 } 
    +
    var odds = (1..6).where {|n| n % 2 == 1 } 
     for (n in odds) { 
         System.print(n) 1
                         3
    @@ -199,7 +210,7 @@ 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.

    -
    var numbers = [1, 2, 3, 4, 5, 6] 
    +
    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]
    diff --git a/modules/core/string.html b/modules/core/string.html
    index eed4ec5b..73eedb28 100644
    --- a/modules/core/string.html
    +++ b/modules/core/string.html
    @@ -105,14 +105,14 @@ 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:

    -
    someString[3]
    +
    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:

    -
    var metalBand = "Fäcëhämmër" 
    +
    var metalBand = "Fäcëhämmër" 
     var hPosition = metalBand.indexOf("h") 
     System.print(metalBand[hPosition]) h
     
    @@ -126,7 +126,7 @@ 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.

    -
    String.fromCodePoint(8225) 
    +
    String.fromCodePoint(8225) 
     
    @@ -138,7 +138,7 @@ ignores any UTF-8 encoding and works directly at the byte level.

    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.

    -
    System.print("hello".bytes[1]) 101 (for "e")
    +
    System.print("hello".bytes[1]) 101 (for "e")
     
    @@ -150,7 +150,7 @@ the string, and runs in constant time instead.

    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.

    -
    var string = "(ᵔᴥᵔ)" 
    +
    var string = "(ᵔᴥᵔ)" 
     System.print(string.codePoints[0]) 40 (for "(")
     System.print(string.codePoints[4]) 7461 (for "ᴥ")
     
    @@ -158,7 +158,7 @@ single-character strings, this returns the numeric code point values.

    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.

    -
    var string = "(ᵔᴥᵔ)" 
    +
    var string = "(ᵔᴥᵔ)" 
     System.print(string.codePoints[2]) -1 (in the middle of "ᵔ")
     
    @@ -179,10 +179,31 @@ count as well.

    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.

    +

    indexOf(search, start) #

    +

    Returns the index of the first byte matching search in the string or -1 if +search was not found, starting a byte offset start. The start can be +negative to count backwards from the end of the string.

    +

    It is a runtime error if search is not a string or start is not an integer +index within the string’s byte length.

    +

    split(separator) #

    +

    Returns a list of one or more strings separated by separator.

    +
    var string = "abc abc abc" 
    +System.print(string.split(" ")) [abc, abc, abc]
    +
    + + +

    It is a runtime error if separator is not a string or is an empty string.

    +

    replace(old, swap) #

    +

    Returns a new string with all occurences of old replaced with swap.

    +
    var string = "abc abc abc" 
    +System.print(string.replace(" ", "")) abcabcabc
    +
    + +

    iterate(iterator), iteratorValue(iterator) #

    -

    Implements the iterator protocol +

    Implements the iterator protocol for iterating over the code points in the string:

    -
    var codePoints = [] 
    +
    var codePoints = [] 
     for (c in "(ᵔᴥᵔ)") { 
       codePoints.add(c) 
     }
    @@ -205,7 +226,7 @@ those too, one byte at a time. 

    Check if the string is not equal to other.

    [index] operator #

    Returns a string containing the code point starting at byte index.

    -
    System.print("ʕ•ᴥ•ʔ"[5]) 
    +
    System.print("ʕ•ᴥ•ʔ"[5]) 
     
    @@ -213,7 +234,7 @@ those too, one byte at a time.

    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:

    -
    System.print("I ♥ NY"[3]) (one-byte string [153])
    +
    System.print("I ♥ NY"[3]) (one-byte string [153])
     
    diff --git a/modules/core/system.html b/modules/core/system.html index 9940977a..782ba6af 100644 --- a/modules/core/system.html +++ b/modules/core/system.html @@ -93,21 +93,21 @@ memory.

    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.

    -
    System.print("I like bananas") I like bananas
    +
    System.print("I like bananas") 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.

    -
    System.printAll([1, [2, 3], 4]) 1[2, 3]4
    +
    System.printAll([1, [2, 3], 4]) 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.

    -
    System.write(4 + 5) 9
    +
    System.write(4 + 5) 9
     
    diff --git a/modules/index.html b/modules/index.html index c21019de..7855ac0f 100644 --- a/modules/index.html +++ b/modules/index.html @@ -37,7 +37,7 @@

    cli

    @@ -65,7 +65,7 @@ @@ -107,7 +107,7 @@ of the command-line app, so can’t be separated out and pulled into host applications that want to embed Wren.

    diff --git a/modules/io/directory.html b/modules/io/directory.html index 4b351ce0..05188535 100644 --- a/modules/io/directory.html +++ b/modules/io/directory.html @@ -32,6 +32,7 @@
  • FileFlags
  • Stat
  • Stdin
  • +
  • Stdout
  • @@ -56,6 +57,7 @@ diff --git a/modules/io/file-flags.html b/modules/io/file-flags.html index 48bf8028..f0499b94 100644 --- a/modules/io/file-flags.html +++ b/modules/io/file-flags.html @@ -32,6 +32,7 @@
  • FileFlags
  • Stat
  • Stdin
  • +
  • Stdout
  • @@ -56,6 +57,7 @@ diff --git a/modules/io/file.html b/modules/io/file.html index 4942dca0..343136dc 100644 --- a/modules/io/file.html +++ b/modules/io/file.html @@ -32,6 +32,7 @@
  • FileFlags
  • Stat
  • Stdin
  • +
  • Stdout
  • @@ -56,6 +57,7 @@ @@ -74,7 +76,7 @@ a file descriptor.

    Opens the file at path for writing and passes it to fn. If there is already a file at that path, it is truncated. After the function returns, the file is automatically closed.

    -
    File.create("numbers.txt") {|file| 
    +
    File.create("numbers.txt") {|file| 
       file.writeBytes("one two three") 
     }
     
    @@ -88,7 +90,7 @@ or other special file system entities.

    File.open(path, fn) #

    Opens the file at path for reading and passes it to fn. After the function returns, the file is automatically closed.

    -
    File.open("words.txt") {|file| 
    +
    File.open("words.txt") {|file| 
       file.readBytes(5) 
     }
     
    @@ -96,20 +98,28 @@ returns, the file is automatically closed.

    File.read(path) #

    Reads the entire contents of the file at path and returns it as a string.

    -
    File.read("words.txt")
    +
    File.read("words.txt")
     

    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.

    +

    File.realPath(path) #

    +

    Resolves path, traversing symlinks and removining any unneeded ./ and ../ +components. Returns the canonical absolute path to the file.

    +
    var path = "/some/./symlink/a/../b/file.txt" 
    +System.print(File.realPath(path)) /real/path/a/file.txt
    +
    + +

    File.size(path) #

    Returns the size in bytes of the contents of the file at path.

    Constructors #

    File.create(path) #

    Opens the file at path for writing. If there is already a file at that path, it is truncated.

    -
    var file = File.create("colors.txt") 
    +
    var file = File.create("colors.txt") 
     file.writeBytes("chartreuse lime teal") 
     file.close()
     
    @@ -129,7 +139,7 @@ done with it.

    Closes the file. After calling this, you can read or write from it.

    readBytes(count) #

    Reads up to count bytes starting from the beginning of the file.

    -
    // Assume this file contains "I am a file!".
    +
    // Assume this file contains "I am a file!".
     File.open("example.txt") {|file| 
       System.print(file.readBytes(6)) I am a
     }
    @@ -139,7 +149,7 @@ done with it. 

    readBytes(count, offset) #

    Reads up to count bytes starting at offset bytes from the beginning of the file.

    -
    // Assume this file contains "I am a file!".
    +
    // Assume this file contains "I am a file!".
     File.open("example.txt") {|file| 
       System.print(file.readBytes(6, 2)) am a f
     }
    diff --git a/modules/io/index.html b/modules/io/index.html
    index 86ec441c..4fa930bf 100644
    --- a/modules/io/index.html
    +++ b/modules/io/index.html
    @@ -32,6 +32,7 @@
             
  • FileFlags
  • Stat
  • Stdin
  • +
  • Stdout
  • @@ -56,6 +57,7 @@ @@ -69,6 +71,7 @@
  • File
  • Stat
  • Stdin
  • +
  • Stdout
  • diff --git a/modules/io/stat.html b/modules/io/stat.html index fff54e69..710242d9 100644 --- a/modules/io/stat.html +++ b/modules/io/stat.html @@ -32,6 +32,7 @@
  • FileFlags
  • Stat
  • Stdin
  • +
  • Stdout
  • @@ -56,6 +57,7 @@ diff --git a/modules/io/stdin.html b/modules/io/stdin.html index 01b55a0c..b3a260c8 100644 --- a/modules/io/stdin.html +++ b/modules/io/stdin.html @@ -32,6 +32,7 @@
  • FileFlags
  • Stat
  • Stdin
  • +
  • Stdout
  • @@ -56,6 +57,7 @@ @@ -65,10 +67,31 @@

    Stdin Class

    The standard input stream.

    Static Methods #

    +

    isRaw #

    +

    Returns true 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.

    +

    Defaults to false.

    +

    isRaw=(value) #

    +

    Sets raw mode on or off.

    +

    isTerminal #

    +

    Returns true if Stdin is connected to a “TTY”. This is true when the user is +running Wren in an interactive terminal, and false if it its input is coming +from a pipe.

    +

    readByte() #

    +

    Reads one byte of input from stdin. Blocks the current fiber until a byte has +been received.

    +

    Returns the byte value as a number or null if stdin is closed.

    +

    Note that output is not automatically flushed when calling this. If you want to +display a prompt before reading input, you’ll want to call Stdout.flush() +after printing the prompt.

    readLine() #

    Reads one line of input from stdin. Blocks the current fiber until a full line of input has been received.

    Returns the string of input or null if stdin is closed.

    +

    Note that output is not automatically flushed when calling this. If you want to +display a prompt before reading input, you’ll want to call Stdout.flush() +after printing the prompt.