1
0
forked from Mirror/wren

Reorganize the language guide.

- Rename "Expressions" -> "Method Calls".
- Organize "Types" and "Language" into a single linear narrative.
- Mobile-specific navigation to handle the longer guide.
- Rename "Fibers" -> "Concurrency".
- Get rid of duplicate stuff about signatures in "Classes".
- Add next/prev links to each page in the guide.
- Move "Contributing" and "Community" up to the top level.
- Move the precendence table to a separate "Grammar" page.
- Lots of other little stuff.
This commit is contained in:
Bob Nystrom
2015-11-07 11:09:04 -08:00
parent bbd6b827b5
commit 931d9ca4d3
25 changed files with 751 additions and 615 deletions

View File

@ -51,7 +51,7 @@ involved][contribute]!
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
[perf]: http://munificent.github.io/wren/performance.html
[classes]: http://munificent.github.io/wren/classes.html
[fibers]: http://munificent.github.io/wren/fibers.html
[fibers]: http://munificent.github.io/wren/concurrency.html
[embedding]: http://munificent.github.io/wren/embedding-api.html
[started]: http://munificent.github.io/wren/getting-started.html
[browser]: http://ppvk.github.io/wren-nest/

View File

@ -1,14 +1,17 @@
^title Classes
^category types
^category guide
Every value in Wren is an object, and every object is an instance of a class.
Even `true` and `false` are full-featured objects—instances of the
[`Bool`](core/bool.html) class.
Classes contain both *behavior* and *state*. Behavior is defined in *methods*
which are stored in the class. State is defined in *fields*, whose values are
Classes define an objects *behavior* and *state*. Behavior is defined by
[*methods*][method calls] which live in the class. Every object of the same
class supports the same methods. State is defined in *fields*, whose values are
stored in each instance.
[method calls]: method-calls.html
## Defining a class
Classes are created using the `class` keyword, unsurprisingly:
@ -29,8 +32,8 @@ To let our unicorn do stuff, we need to give it methods.
}
}
This defines a `prance()` method that takes no arguments. To support
parameters, put their names inside the parentheses:
This defines a `prance()` method that takes no arguments. To add parameters, put
their names inside the parentheses:
:::wren
class Unicorn {
@ -39,12 +42,10 @@ parameters, put their names inside the parentheses:
}
}
### Signature
Since the number of parameters is part of a method's [signature][] a class can
define multiple methods with the same name:
Unlike most other dynamically-typed languages, in Wren you can have multiple
methods in a class with the same name, as long as they have a different
*signature*. In technical terms, you can *overload by arity*. So this class is
fine:
[signature]: method-calls.html#signature
:::wren
class Unicorn {
@ -61,132 +62,105 @@ fine:
}
}
And you can call each of the methods like so:
:::wren
var unicorn = Unicorn.new()
unicorn.prance()
unicorn.prance("Antwerp")
unicorn.prance("Brussels", "high noon")
The number of arguments provided at the callsite determines which method is
chosen.
It's often natural to have the same conceptual operation work with different
sets of arguments. In other languages, you'd define a single method for the
operation and have to check for "undefined" or missing arguments. Wren just
treats them as different methods that you can implement separately.
operation and have to check for missing optional arguments. In Wren, they are
different methods that you implement separately.
In addition to named methods with parameter lists, Wren has a bunch of other
different syntaxes for methods. Your classes can define all of them.
### Getters
Many methods on a class exist to expose or compute some property of the object.
For example:
:::wren
System.print("string".count) //> 6
These *getters* are just another kind of method—one without a parameter
list. You can define them like so:
A getter leaves off the parameter list and the parentheses:
:::wren
class Unicorn {
isFancy { true } // Unicorns are always fancy.
}
Whether or not a method name has parentheses is also part of its signature.
This lets you distinguish between a method that takes an *empty* argument list
(`()`) and no argument list at all:
### Setters
:::wren
class Confusing {
method { "no argument list" }
method() { "empty argument list" }
}
var confusing = Confusing.new()
confusing.method // "no argument list".
confusing.method() // "empty argument list".
Like the example says, having two methods that differ just by an empty set of
parentheses is pretty confusing. That's not what this is for. Instead, it
ensures that the way you *declare* the method is the way you *call* it.
Unlike other languages with "optional parentheses", Wren wants to make sure you
call a getter like a getter and a `()` method like a `()` method. These don't
work:
:::wren
"string".count()
list.clear
Methods that don't need arguments and don't modify the underlying object are
usually getters:
:::wren
"string".count
(1..10).min
1.23.sin
[1, 2, 3].isEmpty
When a method doesn't need any parameters, but does modify the object, it's
helpful to draw attention to that by requiring an empty set of parentheses:
:::wren
list.clear()
Also, when a method supports multiple arities, it's typical to include the `()`
in the zero-argument case to be consistent with the other versions:
Fn.new { "a function" }.call()
Fiber.yield()
### Operators
Operators are just special syntax for a method call on the left hand operand
(or only operand in the case of unary operators like `!` and `~`). In other
words, you can think of `a + b` as meaning `a.+(b)`.
You can define operators in your class like so:
A setter has `=` after the name, followed by a single parenthesized parameter:
:::wren
class Unicorn {
// Infix:
+(other) {
System.print("Adding to a unicorn?")
}
// Prefix:
! {
System.print("Negating a unicorn?!")
rider=(value) {
System.print("I am being ridden by " + value)
}
}
This can be used to define any of these operators:
### Operators
Prefix operators, like getters, have no parameter list:
:::wren
// Infix:
+ - * / % < > <= >= == != & |
class Unicorn {
- {
System.print("Negating a unicorn is weird")
}
}
// Prefix:
! ~ -
Infix operators, like setters, have a single parenthesized parameter for the
right-hand operand:
Note that `-` can be both a prefix and infix operator. If there's a parameter
list, it's the infix one, otherwise, it's prefix. Since Wren supports
overloading by arity, it's no problem for a class to define both.
:::wren
class Unicorn {
-(other) {
System.print("Subtracting " + other + " from a unicorn is weird")
}
}
### Subscript operators
A subscript operator puts the parameters inside square brackets and can have
more than one:
**TODO**
:::wren
class Unicorn {
[index] {
System.print("Unicorns are not lists!")
}
### Setters
[x, y] {
System.print("Unicorns are not matrices either!")
}
}
**TODO**
Unlike with named methods, you can't define a subscript operator with an empty
parameter list.
As the name implies, a subscript setter looks like a combination of a subscript
operator and a setter:
:::wren
class Unicorn {
[index]=(value) {
System.print("You can't stuff " + value + " into me at " + index)
}
}
## This
**TODO: Integrate this into the page better.**
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`.)
## Constructors
Unicorns can prance around now, but we don't actually *have* any unicorns to do
it. To create instances of a class, we need a *constructor*. You can define one
like so:
Unicorns can prance around now (as well as a bunch of weird operators that don't
make sense outside of these examples), but we don't actually *have* any unicorns
to do it. To create instances of a class, we need a *constructor*. You can
define one like so:
:::wren
class Unicorn {
@ -196,10 +170,10 @@ like so:
}
The `construct` keyword says we're defining a constructor, and `new` is its
name. In Wren, all constructors have names, just like [methods][#methods]. The
word "new" isn't special to Wren, it's just a common constructor name.
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 just call the constructor method on the class itself:
To make a unicorn now, we call the constructor method on the class itself:
:::wren
var fred = Unicorn.new("Fred", "palomino")
@ -359,7 +333,10 @@ class using `is` when you declare the class:
This declares a new class `Pegasus` that inherits from `Unicorn`.
Note that you should not create classes that inherit from the built-in types (Bool, Num, String, Range, List). The built-in types expect their internal bit representation to be very specific and get horribly confused when you invoke one of the inherited built-in methods on the derived type.
Note that you should not create classes that inherit from the built-in types
(Bool, Num, String, Range, List). The built-in types expect their internal bit
representation to be very specific and get horribly confused when you invoke one
of the inherited built-in methods on the derived type.
The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if
`Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will not inherit from
@ -409,3 +386,48 @@ This means you can do `super` calls inside a constructor:
}
Pegasus.new("Fred") //> My name is Fred
## Super
**TODO: Integrate better into page. Should explain this before mentioning
super above.**
Sometimes you want to invoke a method on yourself, but only methods defined in
one of your [superclasses](classes.html#inheritance). You typically do this in
an overridden method when you want to access the original method being
overridden.
To do that, you can use the special `super` keyword as the receiver in a method
call:
:::wren
class Base {
method() {
System.print("base method")
}
}
class Derived is Base {
method() {
super.method() //> base method
}
}
You can also use `super` without a method name inside a constructor to invoke a
base class constructor:
:::wren
class Base {
construct new(arg) {
System.print("base got " + arg)
}
}
class Derived is Base {
construct new() {
super("value") //> base got value
}
}
<a class="right" href="concurrency.html">Concurrency &rarr;</a>
<a href="functions.html">&larr; Functions</a>

View File

@ -1,5 +1,4 @@
^title Community
^category reference
Like the [bird](https://en.wikipedia.org/wiki/Wren), Wren's community is small,
but it exists!

View File

@ -1,23 +1,23 @@
^title Fibers
^category types
^title Concurrency
^category guide
Fibers are a key part of Wren. They form its execution model, its concurrency
story, and take the place of exceptions in [error
handling](error-handling.html).
Lightweight concurrency is a key feature of Wren and it is expressed using
*fibers*. They control how all code is executed, and take the place of
exceptions in [error handling](error-handling.html).
They are a bit like threads except they are *cooperatively* scheduled. That
Fibers 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.
Wren takes care of all of the fibers in the VM, so they don't use OS thread
resources, or require heavyweight context switches. Each just needs a bit of
memory for its stack. A fiber will get garbage collected like any other object
when not referenced any more, so you can create them freely.
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
They are lightweight enough that you can, for example, have a separate fiber for
each entity in a game. Wren can handle thousands of them without breaking a
sweat. For example, when you run Wren in interactive mode, it creates a new
fiber for every line of code you type in.
## Creating fibers
@ -168,3 +168,6 @@ 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.
<a class="right" href="error-handling.html">Error Handling &rarr;</a>
<a href="classes.html">&larr; Classes</a>

View File

@ -1,8 +1,7 @@
^title Contributing
^category reference
It should be obvious by now that Wren is under active development and there's
lots left to do. We'd be delighted to have you participate.
Wren is under active development and there's lots to do. We'd be delighted to
have you help!
## Getting acquainted

View File

@ -1,17 +1,17 @@
^title Control Flow
^category language
^category guide
Control flow is used to determine which chunks of code are executed and how
many times. *Branching* statements decide whether or not to execute some code
and *looping* ones execute something more than once.
Control flow is used to determine which chunks of code are executed and how many
times. *Branching* statements and expressions decide whether or not to execute
some code and *looping* ones execute something more than once.
## Truth
All control flow is based on *deciding* whether or not to do something. This
decision is conditional on the value of some expression. We take the entire
universe of possible values and divide them into two buckets: some we consider
"true" and the rest are "false". If the expression results in a value in the
true bucket, we do one thing. Otherwise, we do something else.
decision depends on some expression's value. We take the entire universe of
possible objects and divide them into two buckets: some we consider "true" and
the rest are "false". If the expression results in a value in the true bucket,
we do one thing. Otherwise, we do something else.
Obviously, the boolean `true` is in the "true" bucket and `false` is in
"false", but what about values of other types? The choice is ultimately
@ -58,6 +58,45 @@ And, of course, it can take a block too:
System.print("not ready!")
}
## Logical operators
Unlike most other [operators][] in Wren which are just a special syntax for
[method calls][], the `&&` and `||` operators are special. This is because they
only conditionally evaluate right operand&mdash;they short-circuit.
[operators]: method-calls.html#operators
[method calls]: method-calls.html
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.
:::wren
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
returned:
:::wren
System.print(false || 1) //> 1
System.print(1 || 2) //> 1
## The conditional operator `?:`
Also known as the "ternary" operator since it takes three arguments, Wren has
the little "if statement in the form of an expression" you know and love from C
and its brethren.
:::wren
System.print(1 != 2 ? "math is sane" : "math is not sane!")
It takes a condition expression, followed by `?`, followed by a then
expression, a `:`, then an else expression. Just like `if`, it evaluates the
condition. If true, it evaluates and returns the then expression. Otherwise
it does the else expression.
## While statements
It's hard to write a useful program without executing some chunk of code
@ -119,16 +158,14 @@ A `for` loop has three components:
Sometimes, right in the middle of a loop body, you decide you want to bail out
and stop. To do that, you can use a `break` statement. It's just the `break`
keyword all by itself. That will immediately exit out of the nearest enclosing
keyword all by itself. That immediately exits out of the nearest enclosing
`while` or `for` loop.
:::wren
for (i in [1, 2, 3, 4]) {
System.print(i)
if (i == 3) break
}
So this program will print the numbers from 1 to 3, but will not print 4.
System.print(i) //> 1
if (i == 3) break //> 2
} //> 3
## Numeric ranges
@ -149,12 +186,13 @@ leave off the last value, use three dots instead of two:
System.print(i)
}
This looks like some special "range" syntax in the `for` loop, but it's
actually just a pair of operators. The `..` and `...` syntax are infix "range"
operators. Like [other operators](expressions.html#operators), they are just
special syntax for a regular method call. The number type implements them and
returns a [range object](values.html#ranges) that knows how to iterate over a
series of numbers.
This looks like some special "range" syntax in the `for` loop, but it's actually
just a pair of operators. The `..` and `...` syntax are infix "range" operators.
Like [other operators][operators], they are special syntax for a regular method
call. The number type implements them and returns a [range object][] that knows
how to iterate over a series of numbers.
[range object]: values.html#ranges
## The iterator protocol
@ -202,3 +240,6 @@ that to look up and return the appropriate element.
The built-in [List](lists.html) and [Range](values.html#ranges) types implement
`iterate()` and `iteratorValue()` to walk over their respective sequences. You
can implement the same methods in your classes to make your own types iterable.
<a class="right" href="variables.html">Variables &rarr;</a>
<a href="method-calls.html">&larr; Method Calls</a>

View File

@ -1,7 +1,9 @@
^title Fiber Class
^category core
A lightweight coroutine. [Here](../fibers.html) is a gentle introduction.
A lightweight coroutine. [Here][fibers] is a gentle introduction.
[fibers]: ../concurrency.html
### Fiber.**new**(function)

View File

@ -98,7 +98,7 @@ Otherwise, Wren spins up a new [fiber][] and executes the code in that. Your
code can in turn spawn whatever other fibers it wants. It keeps running fibers
until they all complete.
[fiber]: fibers.html
[fiber]: concurrency.html
If a [runtime error][] occurs (and another fiber doesn't catch it), it will
abort fibers all the way back to the main one and then return

View File

@ -1,5 +1,5 @@
^title Error Handling
^category language
^category guide
Errors come in a few fun flavors.
@ -90,11 +90,12 @@ Most of the time, runtime errors indicate a bug in your code and the best
solution is to fix the bug. However, sometimes it's useful to be able to handle
them at, uh, runtime.
To keep the language simpler, Wren does not have exception handling. Instead,
it takes advantage of [fibers](fibers.html) for handling errors. When a runtime
error occurs, the current fiber is aborted. Normally, Wren will also abort any
fibers that invoked that one, all the way to the main fiber, and then exit the
VM.
To keep the language simpler, Wren does not have exception handling. Instead, it
takes advantage of [fibers][] for handling errors. When a runtime error occurs,
the current fiber is aborted. Normally, Wren will also abort any fibers that
invoked that one, all the way to the main fiber, and then exit the VM.
[fibers]: concurrency.html
However, you can run a fiber using the `try` method. If a runtime error occurs
in the called fiber, the error is captured and the `try` method returns the
@ -163,3 +164,6 @@ indication.
For example, a method for parsing a number could return a number on success and
`null` to indicate parsing failed. Since Wren is dynamically typed, it's easy
and natural for a method to return different types of values.
<a class="right" href="modules.html">Modules &rarr;</a>
<a href="concurrency.html">&larr; Concurrency</a>

View File

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

View File

@ -1,5 +1,5 @@
^title Functions
^category types
^category guide
No self-respecting language today can get by without functions&mdash;first
class little bundles of code. Since Wren is object-oriented, most of your code
@ -161,3 +161,6 @@ to`i`:
System.print(counter.call()) //> 1
System.print(counter.call()) //> 2
System.print(counter.call()) //> 3
<a class="right" href="classes.html">Classes &rarr;</a>
<a href="variables.html">&larr; Variables</a>

View File

@ -93,9 +93,9 @@ Now run:
:::sh
$ ./wren my_script.wren
Neat, right? You're a Wren programmer now! The next step is to [read more
docs](syntax.html) and learn your way around the language. If you run into
bugs, or have ideas or questions, any of the following work:
Neat, right? You're a Wren programmer now! The next step is to [learn the
language](syntax.html). If you run into bugs, or have ideas or questions, any of
the following work:
* **Ask on the [Wren mailing list][list].**
* Tell me on twitter at [@munificentbob][twitter].

130
doc/site/grammar.markdown Normal file
View File

@ -0,0 +1,130 @@
^title Grammar
^category reference
**TODO: Fill in the rest of the grammar.**
## Precedence
When you mix the different [method call][] syntaxes and other [control flow][]
operators together, you need to worry about *precedence*&mdash;which ones bind
more tightly than others&mdash;and *associativity*&mdash;how a series of the
same kind of call is ordered. Wren mostly follows C, except that it fixes [the
bitwise operator mistake][mistake]. The full precedence table, from tightest to
loosest, is:
[method call]: method-calls.html
[control flow]: control-flow.html
[mistake]: http://www.lysator.liu.se/c/dmr-on-or.html
<table class="precedence">
<tbody>
<tr>
<th>Prec</th>
<th>Operator</th>
<th>Description</th>
<th>Assoc</th>
</tr>
<tr>
<td>1</td>
<td><code>()</code> <code>[]</code> <code>.</code></td>
<td>Grouping, Subscript, Method call</td>
<td>Left</td>
</tr>
<tr>
<td>2</td>
<td><code>-</code> <code>!</code> <code>~</code></td>
<td>Negate, Not, Complement</td>
<td>Right</td>
</tr>
<tr>
<td>3</td>
<td><code>*</code> <code>/</code> <code>%</code></td>
<td>Multiply, Divide, Modulo</td>
<td>Left</td>
</tr>
<tr>
<td>4</td>
<td><code>+</code> <code>-</code></td>
<td>Add, Subtract</td>
<td>Left</td>
</tr>
<tr>
<td>5</td>
<td><code>..</code> <code>...</code></td>
<td>Inclusive range, Exclusive range</td>
<td>Left</td>
</tr>
<tr>
<td>6</td>
<td><code>&lt;&lt;</code> <code>&gt;&gt;</code></td>
<td>Left shift, Right shift</td>
<td>Left</td>
</tr>
<tr>
<td>7</td>
<td><code>&lt;</code> <code>&lt;=</code> <code>&gt;</code> <code>&gt;=</code></td>
<td>Comparison</td>
<td>Left</td>
</tr>
<tr>
<td>8</td>
<td><code>==</code></td>
<td>Equals</td>
<td>Left</td>
</tr>
<tr>
<td>8</td>
<td><code>!=</code></td>
<td>Not equal</td>
<td>Left</td>
</tr>
<tr>
<td>9</td>
<td><code>&amp;</code></td>
<td>Bitwise and</td>
<td>Left</td>
</tr>
<tr>
<td>10</td>
<td><code>^</code></td>
<td>Bitwise xor</td>
<td>Left</td>
</tr>
<tr>
<td>11</td>
<td><code>|</code></td>
<td>Bitwise or</td>
<td>Left</td>
</tr>
<tr>
<td>12</td>
<td><code>is</code></td>
<td>Type test</td>
<td>Left</td>
</tr>
<tr>
<td>13</td>
<td><code>&amp;&amp;</code></td>
<td>Logical and</td>
<td>Left</td>
</tr>
<tr>
<td>14</td>
<td><code>||</code></td>
<td>Logical or</td>
<td>Left</td>
</tr>
<tr>
<td>15</td>
<td><code>?:</code></td>
<td>Conditional</td>
<td>Right</td>
</tr>
<tr>
<td>16</td>
<td><code>=</code></td>
<td>Assign</td>
<td>Right</td>
</tr>
</tbody>
</table>

View File

@ -50,7 +50,7 @@ involved][contribute]!
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
[perf]: performance.html
[classes]: classes.html
[fibers]: fibers.html
[fibers]: concurrency.html
[embedding]: embedding-api.html
[started]: getting-started.html
[browser]: http://ppvk.github.io/wren-nest/

View File

@ -1,5 +1,5 @@
^title Lists
^category types
^category guide
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
@ -14,9 +14,11 @@ have to be the same type.
## Accessing elements
You can access an element from a list by calling the [subscript
operator](expressions.html#subscript-operators) on it with the index of the
operator][] on it with the index of the
element you want. Like most languages, indexes start at zero:
[subscript operator]: method-calls.html#subscripts
:::wren
var hirsute = ["sideburns", "porkchops", "'stache", "goatee"]
hirsute[0] //> sideburns
@ -109,3 +111,6 @@ If you want to remove everything from the list, you can clear it:
:::wren
hirsute.clear()
System.print(hirsute) //> []
<a class="right" href="maps.html">Maps &rarr;</a>
<a href="values.html">&larr; Values</a>

View File

@ -1,5 +1,5 @@
^title Maps
^category types
^category guide
A map is an *associative* collection. It holds a set of entries, each of which
maps a *key* to a *value*. The same data structure has a variety of names in
@ -21,15 +21,19 @@ names. Syntactically, in a map literal, keys can be any literal, a variable
name, or a parenthesized expression. Values can be any expression. Here, we're
using string literals for both keys and values.
*Semantically*, values can be any object, and multiple keys may map to the
same value. Keys have a few limitations. They must be one of the immutable
built-in [value types](values.html) in Wren. That means a number, string,
range, bool, or `null`. You can also use a [class object](classes.html) as a
key.
*Semantically*, values can be any object, and multiple keys may map to the same
value. Keys have a few limitations. They must be one of the immutable built-in
[value types][] in Wren. That means a number, string, range, bool, or `null`.
You can also use a [class object][] as a key.
In addition, even though they aren't strictly immutable, [fibers](fibers.html)
can be used as map keys. This is handy for storing data that's roughly
"thread-local" by using the current fiber as a map key.
[value types]: values.html
[class object]: classes.html
In addition, even though they aren't strictly immutable, [fibers][] can be used
as map keys. This is handy for storing data that's roughly "thread-local" by
using the current fiber as a map key.
[fibers]: concurrency.html
The reason for this limitation&mdash;and the reason maps are called "*hash*
tables" in other languages&mdash;is that each key is used to generate a numeric
@ -41,6 +45,8 @@ built-in types, only those can be used as keys.
You add new key-value pairs to the map by using the [subscript operator][]:
[subscript operator]: method-calls.html#subscripts
:::wren
var capitals = {}
capitals["Georgia"] = "Atlanta"
@ -50,8 +56,6 @@ You add new key-value pairs to the map by using the [subscript operator][]:
If the key isn't already present, this adds it and associates it with the given
value. If the key is already there, this just replaces its value.
[subscript operator]: expressions.html#subscript-operators
## Looking up values
To find the value associated with some key, again you use your friend the
@ -98,12 +102,12 @@ If the key wasn't in the map to begin with, `remove()` just returns `null`.
If you want to remove *everything* from the map, just like with [lists][], you
can just call `clear()`:
[lists]: lists.html
:::wren
capitals.clear()
System.print(capitals.count) //> 0
[lists]: lists.html
## Iterating over the contents
The subscript operator works well for finding values when you know the key
@ -134,3 +138,6 @@ This program will print the three states and their birds. However, the *order*
that they are printed isn't defined. Wren makes no promises about what order
keys and values will be iterated in when you use these methods. All it promises
is that every entry will appear exactly once.
<a class="right" href="method-calls.html">Method Calls &rarr;</a>
<a href="lists.html">&larr; Lists</a>

View File

@ -0,0 +1,190 @@
^title Method Calls
^category guide
Wren is deeply object oriented, so most code consists of invoking methods on
objects, usually something like this:
:::wren
System.print("hello")
You have a *receiver* expression (here `System`) followed by a `.`, then a name
(`print`) and an argument list in parentheses (`("hello")`). Multiple arguments
are separated by commas:
:::wren
list.insert("item", 3)
The argument list can also be empty:
:::wren
list.clear()
Semantically, all method calls work like this:
1. Evaluate the receiver and arguments from left to right.
2. Look up the method on the receiver's [class][].
3. Invoke it, passing in the argument values.
[class]: classes.html
## Signature
Unlike most other dynamically-typed languages, in Wren a class can have multiple
methods with the same *name*, as long as they have different *signatures*. The
signature includes the method's name along with the number of arguments it
takes. In technical terms, this means you can *overload by arity*.
<!-- TODO: Link to Random. -->
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:
:::wren
var random = Random.new()
random.int(3, 10)
random.int(4)
In a language like Python or JavaScript, these would both call a single `int()`
method, which has some kind of "optional" parameter. The body of the method
figures out how many arguments were passed and uses control flow to handle the
two different behaviors. That means first parameter represents "max unless
another parameter was passed, in which case it's min". Kind of gross.
In Wren, these are calls to two entirely separate methods, `int(_,_)` and
`int(_)`. This makes it easier to define "overloads" like this since you don't
need optional parameters or any kind of control flow to handle the different
cases.
It's also faster to execute. Since we know how many arguments are passed at
compile time, we can compile this to directly call the right method and avoid
any "if I got two arguments do this..." logic.
## Getters
Some methods exist to expose some stored or computed property of an object.
These are *getters* and have no parentheses:
:::wren
"string".count //> 6
(1..10).min //> 1
1.23.sin //> 0.9424888019317
[1, 2, 3].isEmpty //> false
Sometimes you have a method doesn't need any parameters, but modifies the object
or has some other side effect. For those, it's better to use empty parentheses:
:::wren
list.clear()
Also, when a method supports multiple arities, it's typical to include the `()`
in the zero-argument case to be consistent with the other versions:
Fiber.yield()
Fiber.yield("value")
A getter is *not* the same as a method with an empty argument list. The `()` is
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:
:::wren
"string".count()
list.clear
## Setters
A getter lets an object expose a public "property" that you can *read*.
Likewise, a *setter* let you write to a property:
:::wren
person.height = 74 // Grew up!
Despite the `=`, this is just another syntax for a method call. From the
language's perspective, the above line is just a call to the `height=(_)`
method, passing in `74`.
Since the `=(_)` is in the setter's signature, an object can have both a getter
and setter with the same name without any collision. This way, you can have
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:
:::wren
! ~ -
They are just method calls on their operand without any other arguments. An
expression like `!possible` means "call the `!` method on `possible`".
We also have a slew of infix operators&mdash;they have operands on both sides.
They are:
:::wren
== != < > <= >= .. ... | & + - * / %
Like prefix operators, they are all funny ways of writing method calls. The left
operand is the receiver, and the right operand gets passed to it. So `a + b` is
semantically interpreted as "invoke the `+(_)` method on `a`, passing it `b`".
Note that `-` is both a prefix and an infix operator. Since they have different
signatures (`-` and `-(_)`), there's no ambiguity between them.
Most of these are probably familiar already. The `..` and `...` operators are
"range" operators. The number type implements those to create [range][]
objects, but they are method calls like other operators.
[range]: values.html#ranges
## Subscripts
Another familiar syntax from math class is *subscripting* using square brackets
(`[]`). It's handy for working with collection-like objects. For example:
:::wren
list[0] // Get the first item in a list.
map["key"] // Get the value associated with "key".
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:
:::wren
matrix[3, 5]
These examples are subscript "getters", and there are also
corresponding *subscript setters*:
:::wren
list[0] = "item"
map["key"] = "value"
These are equivalent to method calls whose signature is `[_]=(_)` and whose
arguments are both the subscript (or subscripts) and the value on the right-hand
side.
<!--
**TODO: Integrate this into the infix expressions when "is" becomes a normal
overridable method.**
## The `is` operator
Wren has one last expression form. You can use the `is` keyword like an infix
operator. It performs a type test. The left operand is an object and the right
operand is a class. It evaluates to `true` if the object is an instance of the
class (or one of its subclasses).
:::wren
System.print(123 is Num) //> true
System.print("s" is Num) //> false
System.print(null is String) //> false
System.print([] is List) //> true
System.print([] is Sequence) //> true
-->
<a class="right" href="control-flow.html">Control Flow &rarr;</a>
<a href="maps.html">&larr; Maps</a>

View File

@ -1,5 +1,5 @@
^title Modules
^category language
^category guide
Once you start writing programs that are more than little toys, you quickly run
into two problems:
@ -283,3 +283,5 @@ Now when we run it, we get:
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.
<a href="error-handling.html">&larr; Error Handling</a>

View File

@ -83,8 +83,10 @@ is that bytecode is a nice trade-off between performance and simplicity. Also:
* Many devices like iPhones and game consoles don't allow executing code
generated at runtime, which rules out just-in-time compilation.
* I think [fibers](fibers.html) are a really powerful tool, and implementing
them is straightforward in a bytecode VM that doesn't use the native stack.
* I think [fibers][] are a really powerful tool, and implementing them is
straightforward in a bytecode VM that doesn't use the native stack.
[fibers]: concurrency.html
## Why is the VM stack-based instead of register-based?

View File

@ -105,7 +105,7 @@ header {
nav {
float: right;
width: 160px;
padding-top: 110px;
padding-top: 109px;
h2 {
color: $gray-30;
@ -121,13 +121,38 @@ nav {
}
li {
font: 16px $body;
font: 15px $body;
color: $gray-30;
list-style-type: none;
margin: 0 0 4px 0;
}
}
nav.small {
// Only show the mobile navigation on small screens.
display: none;
float: none;
width: 100%;
padding: 16px 0 0 0;
margin: 0;
background: $gray-10;
table {
width: 100%;
border-collapse: separate;
border-spacing: 16px 0;
}
h2 {
margin: 16px 0 0 0;
padding: 0 0 1px 0;
border-bottom: solid 1px $gray-20;
}
}
h1 {
padding-top: 30px;
font: 500 36px/60px $header;
@ -235,8 +260,9 @@ footer {
}
}
// link hsl(200, 60%, 50%);
// hsl(210, 80%, 60%);
.right {
float: right;
}
// Syntax highlighting.
.codehilite pre {
@ -432,21 +458,9 @@ table.precedence {
@media only screen and (max-width: 639px) {
.page { width: 100%; }
nav {
float: none;
width: 100%;
padding: 10px 10px;
margin: 0;
background: $gray-10;
text-align: center;
section {
display: inline-block;
vertical-align: top;
text-align: left;
width: 30%;
}
}
// Switch to the mobile navigation.
nav.big { display: none; }
nav.small { display: block; }
.main-column {
padding: 0 20px;

View File

@ -1,5 +1,5 @@
^title Syntax
^category language
^category guide
Wren's syntax is designed to be familiar to people coming from C-like languages
while being a bit simpler and more streamlined.
@ -37,8 +37,8 @@ even if the code already contains block comments.
## Reserved words
Some people like to see all of the reserved words in a programming language in
one lump. If you're one of those folks, here you go:
One way to get a quick feel for a language's style is to see what words it
reserves. Here's what Wren has:
:::wren
break class construct else false for foreign if import
@ -124,3 +124,6 @@ same as doing:
{
return "single expression"
}
<a class="right" href="values.html">Values &rarr;</a>
<a href="getting-started.html">&larr; Getting Started</a>

View File

@ -2,7 +2,7 @@
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>{title} Wren</title>
<title>{title} &ndash; Wren</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
@ -19,30 +19,27 @@
</div>
</header>
<div class="page">
<nav>
<nav class="big">
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="community.html">Community</a></li>
</ul>
<section>
<h2>language</h2>
<h2>language guide</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="expressions.html">Expressions</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modules.html">Modules</a></li>
</ul>
</section>
<section>
<h2>types</h2>
<ul>
<li><a href="values.html">Values</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="fibers.html">Fibers</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modules.html">Modules</a></li>
</ul>
</section>
<section>
@ -51,12 +48,55 @@
<li><a href="core">Core Library</a></li>
<li><a href="embedding-api.html">Embedding API</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="community.html">Community</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="grammar.html">Grammar</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<nav class="small">
<table>
<tr>
<td><a href="getting-started.html">Getting Started</a></td>
<td><a href="contributing.html">Contributing</a></td>
<td><a href="community.html">Community</a></td>
</tr>
<tr>
<td colspan="2"><h2>language guide</h2></td>
<td><h2>reference</h2></td>
</tr>
<tr>
<td>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="values.html">Values</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
<li><a href="method-calls.html">Method Calls</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="variables.html">Variables</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="concurrency.html">Concurrency</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modules.html">Modules</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="core">Core Library</a></li>
<li><a href="embedding-api.html">Embedding API</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="grammar.html">Grammar</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</td>
</tr>
</table>
</nav>
<main>
<h1>{title}</h1>
{html}

View File

@ -1,10 +1,10 @@
^title Values
^category types
^category guide
Values are the built-in object types that all other objects are composed of.
They can be created through *literals*, expressions that evaluate to a value.
All values are *immutable*&mdash;once created, they do not change. The number
`3` is always the number `3`. The string `"frozen"` can never have its
Values are the built-in atomic object types that all other objects are composed
of. They can be created through *literals*, expressions that evaluate to a
value. All values are *immutable*&mdash;once created, they do not change. The
number `3` is always the number `3`. The string `"frozen"` can never have its
character array modified in place.
## Booleans
@ -59,6 +59,12 @@ A `\u` followed by four hex digits can be used to specify a Unicode code point:
:::wren
System.print("\u0041\u0b83\u00DE") //> AஃÞ
A capital `\U` followed by *eight* hex digits allows Unicode code points outside
of the basic multilingual plane, like all-important emoji:
:::wren
System.print("\U0001F64A\U0001F680") //> 🙊🚀
A `\x` followed by two hex digits specifies a single unencoded byte:
:::wren
@ -68,10 +74,11 @@ Strings are instances of class [String](core/string.html).
## Ranges
A range is a little object that represents a consecutive range of numbers.
They don't have their own dedicated literal syntax. Instead, the number class
implements the `..` and `...` [operators](expressions.html#operators) to create
them:
A range is a little object that represents a consecutive range of numbers. They
don't have their own dedicated literal syntax. Instead, the number class
implements the `..` and `...` [operators][] to create them:
[operators]: method-calls.html#operators
:::wren
3..8
@ -102,3 +109,6 @@ Wren has a special value `null`, which is the only instance of the class
`void` in some languages: it indicates the absence of a value. If you call a
method that doesn't return anything and get its returned value, you get `null`
back.
<a class="right" href="lists.html">Lists &rarr;</a>
<a href="syntax.html">&larr; Syntax</a>

View File

@ -1,5 +1,5 @@
^title Variables
^category language
^category guide
Variables are named slots for storing values. You define a new variable in Wren
using a `var` statement, like so:
@ -67,4 +67,12 @@ assigned value.
var a = "before"
System.print(a = "after") //> after
If the left-hand side is some more complex expression than a bare variable name,
then it isn't an assignment. Instead, it's calling a [setter method][].
[setter method]: method-calls.html#setters
**TODO: Top-level names.**
<a class="right" href="functions.html">Functions &rarr;</a>
<a href="control-flow.html">&larr; Control Flow</a>

View File

@ -21,12 +21,16 @@ MARKDOWN_HEADER = re.compile(r'#+ ')
# Clean up a header to be a valid URL.
FORMAT_ANCHOR = re.compile(r'\.|\?|!|:|/|\*')
with codecs.open("doc/site/template.html", encoding="utf-8") as f:
template = f.read()
def load_template():
global template
with codecs.open("doc/site/template.html", encoding="utf-8") as f:
template = f.read()
with codecs.open("doc/site/template-core.html", encoding="utf-8") as f:
template_core = f.read()
def load_core_template():
global template_core
with codecs.open("doc/site/template-core.html", encoding="utf-8") as f:
template_core = f.read()
def ensure_dir(path):
@ -35,15 +39,27 @@ def ensure_dir(path):
def is_up_to_date(path, out_path):
# See if it's up to date.
source_mod = os.path.getmtime(path)
source_mod = max(source_mod, os.path.getmtime('doc/site/template.html'))
dest_mod = 0
if os.path.exists(out_path):
dest_mod = os.path.getmtime(out_path)
# See if the templates have changed.
source_mod = os.path.getmtime('doc/site/template.html')
if source_mod > dest_mod:
load_template()
return False
# See if the templates have changed.
source_mod = os.path.getmtime('doc/site/template-core.html')
if source_mod > dest_mod:
load_core_template()
return False
# See if it's up to date.
source_mod = os.path.getmtime(path)
return source_mod < dest_mod
def format_file(path, skip_up_to_date):
basename = os.path.basename(path)
basename = basename.split('.')[0]
@ -89,7 +105,16 @@ def format_file(path, skip_up_to_date):
contents += '{1} <a href="#{0}" name="{0}" class="header-anchor">#</a>\n'.format(anchor, header)
else:
contents = contents + line
# Forcibly add a space to the end of each line. Works around a bug in
# the smartypants extension that removes some newlines that are needed.
# https://github.com/waylan/Python-Markdown/issues/439
if "//" not in line:
contents = contents + line.rstrip() + ' \n'
else:
# Don't add a trailing space on comment lines since they may be
# output lines which have a trailing ">" which makes the extra space
# visible.
contents += line
html = markdown.markdown(contents, ['def_list', 'codehilite', 'smarty'])
@ -148,6 +173,9 @@ if os.path.exists("build/docs"):
shutil.rmtree("build/docs")
ensure_dir("build/docs")
load_template()
load_core_template()
# Process each markdown file.
format_files(False)