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:
parent
bbd6b827b5
commit
931d9ca4d3
@ -51,7 +51,7 @@ involved][contribute]!
|
|||||||
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
|
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
|
||||||
[perf]: http://munificent.github.io/wren/performance.html
|
[perf]: http://munificent.github.io/wren/performance.html
|
||||||
[classes]: http://munificent.github.io/wren/classes.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
|
[embedding]: http://munificent.github.io/wren/embedding-api.html
|
||||||
[started]: http://munificent.github.io/wren/getting-started.html
|
[started]: http://munificent.github.io/wren/getting-started.html
|
||||||
[browser]: http://ppvk.github.io/wren-nest/
|
[browser]: http://ppvk.github.io/wren-nest/
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
^title Classes
|
^title Classes
|
||||||
^category types
|
^category guide
|
||||||
|
|
||||||
Every value in Wren is an object, and every object is an instance of a class.
|
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
|
Even `true` and `false` are full-featured objects—instances of the
|
||||||
[`Bool`](core/bool.html) class.
|
[`Bool`](core/bool.html) class.
|
||||||
|
|
||||||
Classes contain both *behavior* and *state*. Behavior is defined in *methods*
|
Classes define an objects *behavior* and *state*. Behavior is defined by
|
||||||
which are stored in the class. State is defined in *fields*, whose values are
|
[*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.
|
stored in each instance.
|
||||||
|
|
||||||
|
[method calls]: method-calls.html
|
||||||
|
|
||||||
## Defining a class
|
## Defining a class
|
||||||
|
|
||||||
Classes are created using the `class` keyword, unsurprisingly:
|
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
|
This defines a `prance()` method that takes no arguments. To add parameters, put
|
||||||
parameters, put their names inside the parentheses:
|
their names inside the parentheses:
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
class Unicorn {
|
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
|
[signature]: method-calls.html#signature
|
||||||
methods in a class with the same name, as long as they have a different
|
|
||||||
*signature*. In technical terms, you can *overload by arity*. So this class is
|
|
||||||
fine:
|
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
class Unicorn {
|
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
|
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
|
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
|
operation and have to check for missing optional arguments. In Wren, they are
|
||||||
treats them as different methods that you can implement separately.
|
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
|
### Getters
|
||||||
|
|
||||||
Many methods on a class exist to expose or compute some property of the object.
|
A getter leaves off the parameter list and the parentheses:
|
||||||
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:
|
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
class Unicorn {
|
class Unicorn {
|
||||||
isFancy { true } // Unicorns are always fancy.
|
isFancy { true } // Unicorns are always fancy.
|
||||||
}
|
}
|
||||||
|
|
||||||
Whether or not a method name has parentheses is also part of its signature.
|
### Setters
|
||||||
This lets you distinguish between a method that takes an *empty* argument list
|
|
||||||
(`()`) and no argument list at all:
|
|
||||||
|
|
||||||
:::wren
|
A setter has `=` after the name, followed by a single parenthesized parameter:
|
||||||
class Confusing {
|
|
||||||
method { "no argument list" }
|
|
||||||
method() { "empty argument list" }
|
|
||||||
}
|
|
||||||
|
|
||||||
var confusing = Confusing.new()
|
|
||||||
confusing.method // "no argument list".
|
|
||||||
confusing.method() // "empty argument list".
|
|
||||||
|
|
||||||
Like the example says, having two methods that differ just by an empty set of
|
|
||||||
parentheses is pretty confusing. That's not what this is for. Instead, it
|
|
||||||
ensures that the way you *declare* the method is the way you *call* it.
|
|
||||||
|
|
||||||
Unlike other languages with "optional parentheses", Wren wants to make sure you
|
|
||||||
call a getter like a getter and a `()` method like a `()` method. These don't
|
|
||||||
work:
|
|
||||||
|
|
||||||
:::wren
|
|
||||||
"string".count()
|
|
||||||
list.clear
|
|
||||||
|
|
||||||
Methods that don't need arguments and don't modify the underlying object are
|
|
||||||
usually getters:
|
|
||||||
|
|
||||||
:::wren
|
|
||||||
"string".count
|
|
||||||
(1..10).min
|
|
||||||
1.23.sin
|
|
||||||
[1, 2, 3].isEmpty
|
|
||||||
|
|
||||||
When a method doesn't need any parameters, but does modify the object, it's
|
|
||||||
helpful to draw attention to that by requiring an empty set of parentheses:
|
|
||||||
|
|
||||||
:::wren
|
|
||||||
list.clear()
|
|
||||||
|
|
||||||
Also, when a method supports multiple arities, it's typical to include the `()`
|
|
||||||
in the zero-argument case to be consistent with the other versions:
|
|
||||||
|
|
||||||
Fn.new { "a function" }.call()
|
|
||||||
Fiber.yield()
|
|
||||||
|
|
||||||
### Operators
|
|
||||||
|
|
||||||
Operators are just special syntax for a method call on the left hand operand
|
|
||||||
(or only operand in the case of unary operators like `!` and `~`). In other
|
|
||||||
words, you can think of `a + b` as meaning `a.+(b)`.
|
|
||||||
|
|
||||||
You can define operators in your class like so:
|
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
class Unicorn {
|
class Unicorn {
|
||||||
// Infix:
|
rider=(value) {
|
||||||
+(other) {
|
System.print("I am being ridden by " + value)
|
||||||
System.print("Adding to a unicorn?")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefix:
|
|
||||||
! {
|
|
||||||
System.print("Negating a unicorn?!")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
This can be used to define any of these operators:
|
### Operators
|
||||||
|
|
||||||
|
Prefix operators, like getters, have no parameter list:
|
||||||
|
|
||||||
:::wren
|
:::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
|
:::wren
|
||||||
list, it's the infix one, otherwise, it's prefix. Since Wren supports
|
class Unicorn {
|
||||||
overloading by arity, it's no problem for a class to define both.
|
-(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
|
## Constructors
|
||||||
|
|
||||||
Unicorns can prance around now, but we don't actually *have* any unicorns to do
|
Unicorns can prance around now (as well as a bunch of weird operators that don't
|
||||||
it. To create instances of a class, we need a *constructor*. You can define one
|
make sense outside of these examples), but we don't actually *have* any unicorns
|
||||||
like so:
|
to do it. To create instances of a class, we need a *constructor*. You can
|
||||||
|
define one like so:
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
class Unicorn {
|
class Unicorn {
|
||||||
@ -196,10 +170,10 @@ like so:
|
|||||||
}
|
}
|
||||||
|
|
||||||
The `construct` keyword says we're defining a constructor, and `new` is its
|
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
|
name. In Wren, all constructors have names. The word "new" isn't special to
|
||||||
word "new" isn't special to Wren, it's just a common constructor name.
|
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
|
:::wren
|
||||||
var fred = Unicorn.new("Fred", "palomino")
|
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`.
|
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
|
The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if
|
||||||
`Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will not inherit from
|
`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
|
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 →</a>
|
||||||
|
<a href="functions.html">← Functions</a>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
^title Community
|
^title Community
|
||||||
^category reference
|
|
||||||
|
|
||||||
Like the [bird](https://en.wikipedia.org/wiki/Wren), Wren's community is small,
|
Like the [bird](https://en.wikipedia.org/wiki/Wren), Wren's community is small,
|
||||||
but it exists!
|
but it exists!
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
^title Fibers
|
^title Concurrency
|
||||||
^category types
|
^category guide
|
||||||
|
|
||||||
Fibers are a key part of Wren. They form its execution model, its concurrency
|
Lightweight concurrency is a key feature of Wren and it is expressed using
|
||||||
story, and take the place of exceptions in [error
|
*fibers*. They control how all code is executed, and take the place of
|
||||||
handling](error-handling.html).
|
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.
|
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
|
You don't have to worry about context switches at random times and all of the
|
||||||
headaches those cause.
|
headaches those cause.
|
||||||
|
|
||||||
Fibers are managed entirely by Wren, so they don't use OS thread resources, or
|
Wren takes care of all of the fibers in the VM, so they don't use OS thread
|
||||||
require heavyweight context switches. They just need a bit of memory for their
|
resources, or require heavyweight context switches. Each just needs a bit of
|
||||||
stacks. A fiber will get garbage collected like any other object when not
|
memory for its stack. A fiber will get garbage collected like any other object
|
||||||
referenced any more, so you can create them freely.
|
when not referenced any more, so you can create them freely.
|
||||||
|
|
||||||
They are lightweight enough that you can, for example, have a separate fiber
|
They are lightweight enough that you can, for example, have a separate fiber for
|
||||||
for each entity in a game. Wren can handle thousands of them without any
|
each entity in a game. Wren can handle thousands of them without breaking a
|
||||||
trouble. For example, when you run Wren in interactive mode, it creates a new
|
sweat. For example, when you run Wren in interactive mode, it creates a new
|
||||||
fiber for every line of code you type in.
|
fiber for every line of code you type in.
|
||||||
|
|
||||||
## Creating fibers
|
## 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
|
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
|
transferring back to it, or even calling it. If you don't, execution stops when
|
||||||
the last transferred fiber returns.
|
the last transferred fiber returns.
|
||||||
|
|
||||||
|
<a class="right" href="error-handling.html">Error Handling →</a>
|
||||||
|
<a href="classes.html">← Classes</a>
|
||||||
@ -1,8 +1,7 @@
|
|||||||
^title Contributing
|
^title Contributing
|
||||||
^category reference
|
|
||||||
|
|
||||||
It should be obvious by now that Wren is under active development and there's
|
Wren is under active development and there's lots to do. We'd be delighted to
|
||||||
lots left to do. We'd be delighted to have you participate.
|
have you help!
|
||||||
|
|
||||||
## Getting acquainted
|
## Getting acquainted
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
^title Control Flow
|
^title Control Flow
|
||||||
^category language
|
^category guide
|
||||||
|
|
||||||
Control flow is used to determine which chunks of code are executed and how
|
Control flow is used to determine which chunks of code are executed and how many
|
||||||
many times. *Branching* statements decide whether or not to execute some code
|
times. *Branching* statements and expressions decide whether or not to execute
|
||||||
and *looping* ones execute something more than once.
|
some code and *looping* ones execute something more than once.
|
||||||
|
|
||||||
## Truth
|
## Truth
|
||||||
|
|
||||||
All control flow is based on *deciding* whether or not to do something. This
|
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
|
decision depends on some expression's value. We take the entire universe of
|
||||||
universe of possible values and divide them into two buckets: some we consider
|
possible objects and divide them into two buckets: some we consider "true" and
|
||||||
"true" and the rest are "false". If the expression results in a value in the
|
the rest are "false". If the expression results in a value in the true bucket,
|
||||||
true bucket, we do one thing. Otherwise, we do something else.
|
we do one thing. Otherwise, we do something else.
|
||||||
|
|
||||||
Obviously, the boolean `true` is in the "true" bucket and `false` is in
|
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
|
"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!")
|
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—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
|
## While statements
|
||||||
|
|
||||||
It's hard to write a useful program without executing some chunk of code
|
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
|
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`
|
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.
|
`while` or `for` loop.
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
for (i in [1, 2, 3, 4]) {
|
for (i in [1, 2, 3, 4]) {
|
||||||
System.print(i)
|
System.print(i) //> 1
|
||||||
if (i == 3) break
|
if (i == 3) break //> 2
|
||||||
}
|
} //> 3
|
||||||
|
|
||||||
So this program will print the numbers from 1 to 3, but will not print 4.
|
|
||||||
|
|
||||||
## Numeric ranges
|
## Numeric ranges
|
||||||
|
|
||||||
@ -149,12 +186,13 @@ leave off the last value, use three dots instead of two:
|
|||||||
System.print(i)
|
System.print(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
This looks like some special "range" syntax in the `for` loop, but it's
|
This looks like some special "range" syntax in the `for` loop, but it's actually
|
||||||
actually just a pair of operators. The `..` and `...` syntax are infix "range"
|
just a pair of operators. The `..` and `...` syntax are infix "range" operators.
|
||||||
operators. Like [other operators](expressions.html#operators), they are just
|
Like [other operators][operators], they are special syntax for a regular method
|
||||||
special syntax for a regular method call. The number type implements them and
|
call. The number type implements them and returns a [range object][] that knows
|
||||||
returns a [range object](values.html#ranges) that knows how to iterate over a
|
how to iterate over a series of numbers.
|
||||||
series of numbers.
|
|
||||||
|
[range object]: values.html#ranges
|
||||||
|
|
||||||
## The iterator protocol
|
## 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
|
The built-in [List](lists.html) and [Range](values.html#ranges) types implement
|
||||||
`iterate()` and `iteratorValue()` to walk over their respective sequences. You
|
`iterate()` and `iteratorValue()` to walk over their respective sequences. You
|
||||||
can implement the same methods in your classes to make your own types iterable.
|
can implement the same methods in your classes to make your own types iterable.
|
||||||
|
|
||||||
|
<a class="right" href="variables.html">Variables →</a>
|
||||||
|
<a href="method-calls.html">← Method Calls</a>
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
^title Fiber Class
|
^title Fiber Class
|
||||||
^category core
|
^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)
|
### Fiber.**new**(function)
|
||||||
|
|
||||||
|
|||||||
@ -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
|
code can in turn spawn whatever other fibers it wants. It keeps running fibers
|
||||||
until they all complete.
|
until they all complete.
|
||||||
|
|
||||||
[fiber]: fibers.html
|
[fiber]: concurrency.html
|
||||||
|
|
||||||
If a [runtime error][] occurs (and another fiber doesn't catch it), it will
|
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
|
abort fibers all the way back to the main one and then return
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
^title Error Handling
|
^title Error Handling
|
||||||
^category language
|
^category guide
|
||||||
|
|
||||||
Errors come in a few fun flavors.
|
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
|
solution is to fix the bug. However, sometimes it's useful to be able to handle
|
||||||
them at, uh, runtime.
|
them at, uh, runtime.
|
||||||
|
|
||||||
To keep the language simpler, Wren does not have exception handling. Instead,
|
To keep the language simpler, Wren does not have exception handling. Instead, it
|
||||||
it takes advantage of [fibers](fibers.html) for handling errors. When a runtime
|
takes advantage of [fibers][] for handling errors. When a runtime error occurs,
|
||||||
error occurs, the current fiber is aborted. Normally, Wren will also abort any
|
the current fiber is aborted. Normally, Wren will also abort any fibers that
|
||||||
fibers that invoked that one, all the way to the main fiber, and then exit the
|
invoked that one, all the way to the main fiber, and then exit the VM.
|
||||||
VM.
|
|
||||||
|
[fibers]: concurrency.html
|
||||||
|
|
||||||
However, you can run a fiber using the `try` method. If a runtime error occurs
|
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
|
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
|
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
|
`null` to indicate parsing failed. Since Wren is dynamically typed, it's easy
|
||||||
and natural for a method to return different types of values.
|
and natural for a method to return different types of values.
|
||||||
|
|
||||||
|
<a class="right" href="modules.html">Modules →</a>
|
||||||
|
<a href="concurrency.html">← Concurrency</a>
|
||||||
|
|||||||
@ -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—numbers, strings and friends—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)—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](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—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—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*—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:
|
|
||||||
|
|
||||||
<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><<</code> <code>>></code></td>
|
|
||||||
<td>Left shift, Right shift</td>
|
|
||||||
<td>Left</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>7</td>
|
|
||||||
<td><code><</code> <code><=</code> <code>></code> <code>>=</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>&</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>&&</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>
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
^title Functions
|
^title Functions
|
||||||
^category types
|
^category guide
|
||||||
|
|
||||||
No self-respecting language today can get by without functions—first
|
No self-respecting language today can get by without functions—first
|
||||||
class little bundles of code. Since Wren is object-oriented, most of your code
|
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()) //> 1
|
||||||
System.print(counter.call()) //> 2
|
System.print(counter.call()) //> 2
|
||||||
System.print(counter.call()) //> 3
|
System.print(counter.call()) //> 3
|
||||||
|
|
||||||
|
<a class="right" href="classes.html">Classes →</a>
|
||||||
|
<a href="variables.html">← Variables</a>
|
||||||
|
|||||||
@ -93,9 +93,9 @@ Now run:
|
|||||||
:::sh
|
:::sh
|
||||||
$ ./wren my_script.wren
|
$ ./wren my_script.wren
|
||||||
|
|
||||||
Neat, right? You're a Wren programmer now! The next step is to [read more
|
Neat, right? You're a Wren programmer now! The next step is to [learn the
|
||||||
docs](syntax.html) and learn your way around the language. If you run into
|
language](syntax.html). If you run into bugs, or have ideas or questions, any of
|
||||||
bugs, or have ideas or questions, any of the following work:
|
the following work:
|
||||||
|
|
||||||
* **Ask on the [Wren mailing list][list].**
|
* **Ask on the [Wren mailing list][list].**
|
||||||
* Tell me on twitter at [@munificentbob][twitter].
|
* Tell me on twitter at [@munificentbob][twitter].
|
||||||
|
|||||||
130
doc/site/grammar.markdown
Normal file
130
doc/site/grammar.markdown
Normal 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*—which ones bind
|
||||||
|
more tightly than others—and *associativity*—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><<</code> <code>>></code></td>
|
||||||
|
<td>Left shift, Right shift</td>
|
||||||
|
<td>Left</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>7</td>
|
||||||
|
<td><code><</code> <code><=</code> <code>></code> <code>>=</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>&</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>&&</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>
|
||||||
@ -50,7 +50,7 @@ involved][contribute]!
|
|||||||
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
|
[nan]: https://github.com/munificent/wren/blob/46c1ba92492e9257aba6418403161072d640cb29/src/wren_value.h#L378-L433
|
||||||
[perf]: performance.html
|
[perf]: performance.html
|
||||||
[classes]: classes.html
|
[classes]: classes.html
|
||||||
[fibers]: fibers.html
|
[fibers]: concurrency.html
|
||||||
[embedding]: embedding-api.html
|
[embedding]: embedding-api.html
|
||||||
[started]: getting-started.html
|
[started]: getting-started.html
|
||||||
[browser]: http://ppvk.github.io/wren-nest/
|
[browser]: http://ppvk.github.io/wren-nest/
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
^title Lists
|
^title Lists
|
||||||
^category types
|
^category guide
|
||||||
|
|
||||||
A list is a compound object that holds a collection of elements identified by
|
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
|
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
|
## Accessing elements
|
||||||
|
|
||||||
You can access an element from a list by calling the [subscript
|
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:
|
element you want. Like most languages, indexes start at zero:
|
||||||
|
|
||||||
|
[subscript operator]: method-calls.html#subscripts
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
var hirsute = ["sideburns", "porkchops", "'stache", "goatee"]
|
var hirsute = ["sideburns", "porkchops", "'stache", "goatee"]
|
||||||
hirsute[0] //> sideburns
|
hirsute[0] //> sideburns
|
||||||
@ -109,3 +111,6 @@ If you want to remove everything from the list, you can clear it:
|
|||||||
:::wren
|
:::wren
|
||||||
hirsute.clear()
|
hirsute.clear()
|
||||||
System.print(hirsute) //> []
|
System.print(hirsute) //> []
|
||||||
|
|
||||||
|
<a class="right" href="maps.html">Maps →</a>
|
||||||
|
<a href="values.html">← Values</a>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
^title Maps
|
^title Maps
|
||||||
^category types
|
^category guide
|
||||||
|
|
||||||
A map is an *associative* collection. It holds a set of entries, each of which
|
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
|
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
|
name, or a parenthesized expression. Values can be any expression. Here, we're
|
||||||
using string literals for both keys and values.
|
using string literals for both keys and values.
|
||||||
|
|
||||||
*Semantically*, values can be any object, and multiple keys may map to the
|
*Semantically*, values can be any object, and multiple keys may map to the same
|
||||||
same value. Keys have a few limitations. They must be one of the immutable
|
value. Keys have a few limitations. They must be one of the immutable built-in
|
||||||
built-in [value types](values.html) in Wren. That means a number, string,
|
[value types][] in Wren. That means a number, string, range, bool, or `null`.
|
||||||
range, bool, or `null`. You can also use a [class object](classes.html) as a
|
You can also use a [class object][] as a key.
|
||||||
key.
|
|
||||||
|
|
||||||
In addition, even though they aren't strictly immutable, [fibers](fibers.html)
|
[value types]: values.html
|
||||||
can be used as map keys. This is handy for storing data that's roughly
|
[class object]: classes.html
|
||||||
"thread-local" by using the current fiber as a map key.
|
|
||||||
|
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—and the reason maps are called "*hash*
|
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
|
tables" in other languages—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][]:
|
You add new key-value pairs to the map by using the [subscript operator][]:
|
||||||
|
|
||||||
|
[subscript operator]: method-calls.html#subscripts
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
var capitals = {}
|
var capitals = {}
|
||||||
capitals["Georgia"] = "Atlanta"
|
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
|
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.
|
value. If the key is already there, this just replaces its value.
|
||||||
|
|
||||||
[subscript operator]: expressions.html#subscript-operators
|
|
||||||
|
|
||||||
## Looking up values
|
## Looking up values
|
||||||
|
|
||||||
To find the value associated with some key, again you use your friend the
|
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
|
If you want to remove *everything* from the map, just like with [lists][], you
|
||||||
can just call `clear()`:
|
can just call `clear()`:
|
||||||
|
|
||||||
|
[lists]: lists.html
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
capitals.clear()
|
capitals.clear()
|
||||||
System.print(capitals.count) //> 0
|
System.print(capitals.count) //> 0
|
||||||
|
|
||||||
[lists]: lists.html
|
|
||||||
|
|
||||||
## Iterating over the contents
|
## Iterating over the contents
|
||||||
|
|
||||||
The subscript operator works well for finding values when you know the key
|
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
|
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
|
keys and values will be iterated in when you use these methods. All it promises
|
||||||
is that every entry will appear exactly once.
|
is that every entry will appear exactly once.
|
||||||
|
|
||||||
|
<a class="right" href="method-calls.html">Method Calls →</a>
|
||||||
|
<a href="lists.html">← Lists</a>
|
||||||
|
|||||||
190
doc/site/method-calls.markdown
Normal file
190
doc/site/method-calls.markdown
Normal 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—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 →</a>
|
||||||
|
<a href="maps.html">← Maps</a>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
^title Modules
|
^title Modules
|
||||||
^category language
|
^category guide
|
||||||
|
|
||||||
Once you start writing programs that are more than little toys, you quickly run
|
Once you start writing programs that are more than little toys, you quickly run
|
||||||
into two problems:
|
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
|
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
|
general. The key point here is that Wren *can* handle them in the rare cases
|
||||||
where you need them.
|
where you need them.
|
||||||
|
|
||||||
|
<a href="error-handling.html">← Error Handling</a>
|
||||||
|
|||||||
@ -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
|
* Many devices like iPhones and game consoles don't allow executing code
|
||||||
generated at runtime, which rules out just-in-time compilation.
|
generated at runtime, which rules out just-in-time compilation.
|
||||||
|
|
||||||
* I think [fibers](fibers.html) are a really powerful tool, and implementing
|
* I think [fibers][] are a really powerful tool, and implementing them is
|
||||||
them is straightforward in a bytecode VM that doesn't use the native stack.
|
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?
|
## Why is the VM stack-based instead of register-based?
|
||||||
|
|
||||||
|
|||||||
@ -105,7 +105,7 @@ header {
|
|||||||
nav {
|
nav {
|
||||||
float: right;
|
float: right;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
padding-top: 110px;
|
padding-top: 109px;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
color: $gray-30;
|
color: $gray-30;
|
||||||
@ -121,13 +121,38 @@ nav {
|
|||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
font: 16px $body;
|
font: 15px $body;
|
||||||
color: $gray-30;
|
color: $gray-30;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin: 0 0 4px 0;
|
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 {
|
h1 {
|
||||||
padding-top: 30px;
|
padding-top: 30px;
|
||||||
font: 500 36px/60px $header;
|
font: 500 36px/60px $header;
|
||||||
@ -235,8 +260,9 @@ footer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// link hsl(200, 60%, 50%);
|
.right {
|
||||||
// hsl(210, 80%, 60%);
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
// Syntax highlighting.
|
// Syntax highlighting.
|
||||||
.codehilite pre {
|
.codehilite pre {
|
||||||
@ -432,21 +458,9 @@ table.precedence {
|
|||||||
@media only screen and (max-width: 639px) {
|
@media only screen and (max-width: 639px) {
|
||||||
.page { width: 100%; }
|
.page { width: 100%; }
|
||||||
|
|
||||||
nav {
|
// Switch to the mobile navigation.
|
||||||
float: none;
|
nav.big { display: none; }
|
||||||
width: 100%;
|
nav.small { display: block; }
|
||||||
padding: 10px 10px;
|
|
||||||
margin: 0;
|
|
||||||
background: $gray-10;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
section {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
text-align: left;
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-column {
|
.main-column {
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
^title Syntax
|
^title Syntax
|
||||||
^category language
|
^category guide
|
||||||
|
|
||||||
Wren's syntax is designed to be familiar to people coming from C-like languages
|
Wren's syntax is designed to be familiar to people coming from C-like languages
|
||||||
while being a bit simpler and more streamlined.
|
while being a bit simpler and more streamlined.
|
||||||
@ -37,8 +37,8 @@ even if the code already contains block comments.
|
|||||||
|
|
||||||
## Reserved words
|
## Reserved words
|
||||||
|
|
||||||
Some people like to see all of the reserved words in a programming language in
|
One way to get a quick feel for a language's style is to see what words it
|
||||||
one lump. If you're one of those folks, here you go:
|
reserves. Here's what Wren has:
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
break class construct else false for foreign if import
|
break class construct else false for foreign if import
|
||||||
@ -124,3 +124,6 @@ same as doing:
|
|||||||
{
|
{
|
||||||
return "single expression"
|
return "single expression"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<a class="right" href="values.html">Values →</a>
|
||||||
|
<a href="getting-started.html">← Getting Started</a>
|
||||||
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
|
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
|
||||||
<title>{title} – Wren</title>
|
<title>{title} – Wren</title>
|
||||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||||
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
|
<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
|
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
|
||||||
@ -19,30 +19,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<nav>
|
<nav class="big">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="getting-started.html">Getting Started</a></li>
|
<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>
|
</ul>
|
||||||
<section>
|
<section>
|
||||||
<h2>language</h2>
|
<h2>language guide</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="syntax.html">Syntax</a></li>
|
<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="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="lists.html">Lists</a></li>
|
||||||
<li><a href="maps.html">Maps</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>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
@ -51,12 +48,55 @@
|
|||||||
<li><a href="core">Core Library</a></li>
|
<li><a href="core">Core Library</a></li>
|
||||||
<li><a href="embedding-api.html">Embedding API</a></li>
|
<li><a href="embedding-api.html">Embedding API</a></li>
|
||||||
<li><a href="performance.html">Performance</a></li>
|
<li><a href="performance.html">Performance</a></li>
|
||||||
<li><a href="community.html">Community</a></li>
|
<li><a href="grammar.html">Grammar</a></li>
|
||||||
<li><a href="contributing.html">Contributing</a></li>
|
|
||||||
<li><a href="qa.html">Q & A</a></li>
|
<li><a href="qa.html">Q & A</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</nav>
|
</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 & A</a></li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</nav>
|
||||||
<main>
|
<main>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
{html}
|
{html}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
^title Values
|
^title Values
|
||||||
^category types
|
^category guide
|
||||||
|
|
||||||
Values are the built-in object types that all other objects are composed of.
|
Values are the built-in atomic object types that all other objects are composed
|
||||||
They can be created through *literals*, expressions that evaluate to a value.
|
of. They can be created through *literals*, expressions that evaluate to a
|
||||||
All values are *immutable*—once created, they do not change. The number
|
value. All values are *immutable*—once created, they do not change. The
|
||||||
`3` is always the number `3`. The string `"frozen"` can never have its
|
number `3` is always the number `3`. The string `"frozen"` can never have its
|
||||||
character array modified in place.
|
character array modified in place.
|
||||||
|
|
||||||
## Booleans
|
## Booleans
|
||||||
@ -59,6 +59,12 @@ A `\u` followed by four hex digits can be used to specify a Unicode code point:
|
|||||||
:::wren
|
:::wren
|
||||||
System.print("\u0041\u0b83\u00DE") //> AஃÞ
|
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:
|
A `\x` followed by two hex digits specifies a single unencoded byte:
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
@ -68,10 +74,11 @@ Strings are instances of class [String](core/string.html).
|
|||||||
|
|
||||||
## Ranges
|
## Ranges
|
||||||
|
|
||||||
A range is a little object that represents a consecutive range of numbers.
|
A range is a little object that represents a consecutive range of numbers. They
|
||||||
They don't have their own dedicated literal syntax. Instead, the number class
|
don't have their own dedicated literal syntax. Instead, the number class
|
||||||
implements the `..` and `...` [operators](expressions.html#operators) to create
|
implements the `..` and `...` [operators][] to create them:
|
||||||
them:
|
|
||||||
|
[operators]: method-calls.html#operators
|
||||||
|
|
||||||
:::wren
|
:::wren
|
||||||
3..8
|
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
|
`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`
|
method that doesn't return anything and get its returned value, you get `null`
|
||||||
back.
|
back.
|
||||||
|
|
||||||
|
<a class="right" href="lists.html">Lists →</a>
|
||||||
|
<a href="syntax.html">← Syntax</a>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
^title Variables
|
^title Variables
|
||||||
^category language
|
^category guide
|
||||||
|
|
||||||
Variables are named slots for storing values. You define a new variable in Wren
|
Variables are named slots for storing values. You define a new variable in Wren
|
||||||
using a `var` statement, like so:
|
using a `var` statement, like so:
|
||||||
@ -67,4 +67,12 @@ assigned value.
|
|||||||
var a = "before"
|
var a = "before"
|
||||||
System.print(a = "after") //> after
|
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.**
|
**TODO: Top-level names.**
|
||||||
|
|
||||||
|
<a class="right" href="functions.html">Functions →</a>
|
||||||
|
<a href="control-flow.html">← Control Flow</a>
|
||||||
|
|||||||
@ -21,12 +21,16 @@ MARKDOWN_HEADER = re.compile(r'#+ ')
|
|||||||
# Clean up a header to be a valid URL.
|
# Clean up a header to be a valid URL.
|
||||||
FORMAT_ANCHOR = re.compile(r'\.|\?|!|:|/|\*')
|
FORMAT_ANCHOR = re.compile(r'\.|\?|!|:|/|\*')
|
||||||
|
|
||||||
with codecs.open("doc/site/template.html", encoding="utf-8") as f:
|
def load_template():
|
||||||
template = f.read()
|
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:
|
def load_core_template():
|
||||||
template_core = f.read()
|
global template_core
|
||||||
|
with codecs.open("doc/site/template-core.html", encoding="utf-8") as f:
|
||||||
|
template_core = f.read()
|
||||||
|
|
||||||
|
|
||||||
def ensure_dir(path):
|
def ensure_dir(path):
|
||||||
@ -35,15 +39,27 @@ def ensure_dir(path):
|
|||||||
|
|
||||||
|
|
||||||
def is_up_to_date(path, out_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
|
dest_mod = 0
|
||||||
if os.path.exists(out_path):
|
if os.path.exists(out_path):
|
||||||
dest_mod = os.path.getmtime(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
|
return source_mod < dest_mod
|
||||||
|
|
||||||
|
|
||||||
def format_file(path, skip_up_to_date):
|
def format_file(path, skip_up_to_date):
|
||||||
basename = os.path.basename(path)
|
basename = os.path.basename(path)
|
||||||
basename = basename.split('.')[0]
|
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)
|
contents += '{1} <a href="#{0}" name="{0}" class="header-anchor">#</a>\n'.format(anchor, header)
|
||||||
|
|
||||||
else:
|
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'])
|
html = markdown.markdown(contents, ['def_list', 'codehilite', 'smarty'])
|
||||||
|
|
||||||
@ -148,6 +173,9 @@ if os.path.exists("build/docs"):
|
|||||||
shutil.rmtree("build/docs")
|
shutil.rmtree("build/docs")
|
||||||
ensure_dir("build/docs")
|
ensure_dir("build/docs")
|
||||||
|
|
||||||
|
load_template()
|
||||||
|
load_core_template()
|
||||||
|
|
||||||
# Process each markdown file.
|
# Process each markdown file.
|
||||||
format_files(False)
|
format_files(False)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user