diff --git a/README.md b/README.md index 0607365b..6c5ef58a 100644 --- a/README.md +++ b/README.md @@ -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/ diff --git a/doc/site/classes.markdown b/doc/site/classes.markdown index d1ab6aed..a38c9b68 100644 --- a/doc/site/classes.markdown +++ b/doc/site/classes.markdown @@ -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 + } + } + +Concurrency → +← Functions diff --git a/doc/site/community.markdown b/doc/site/community.markdown index f9ec694a..e3a1edee 100644 --- a/doc/site/community.markdown +++ b/doc/site/community.markdown @@ -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! diff --git a/doc/site/fibers.markdown b/doc/site/concurrency.markdown similarity index 85% rename from doc/site/fibers.markdown rename to doc/site/concurrency.markdown index c886ffb2..e4b4d475 100644 --- a/doc/site/fibers.markdown +++ b/doc/site/concurrency.markdown @@ -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. + +Error Handling → +← Classes diff --git a/doc/site/contributing.markdown b/doc/site/contributing.markdown index 1d31bc5b..b2577a97 100644 --- a/doc/site/contributing.markdown +++ b/doc/site/contributing.markdown @@ -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 diff --git a/doc/site/control-flow.markdown b/doc/site/control-flow.markdown index c1f10c53..33bcf68e 100644 --- a/doc/site/control-flow.markdown +++ b/doc/site/control-flow.markdown @@ -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—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. + +Variables → +← Method Calls diff --git a/doc/site/core/fiber.markdown b/doc/site/core/fiber.markdown index e8d0167a..a3aca2aa 100644 --- a/doc/site/core/fiber.markdown +++ b/doc/site/core/fiber.markdown @@ -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) diff --git a/doc/site/embedding-api.markdown b/doc/site/embedding-api.markdown index 2363614b..f3784e03 100644 --- a/doc/site/embedding-api.markdown +++ b/doc/site/embedding-api.markdown @@ -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 diff --git a/doc/site/error-handling.markdown b/doc/site/error-handling.markdown index 624ba0cc..a916bd2f 100644 --- a/doc/site/error-handling.markdown +++ b/doc/site/error-handling.markdown @@ -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. + +Modules → +← Concurrency diff --git a/doc/site/expressions.markdown b/doc/site/expressions.markdown deleted file mode 100644 index a50d8421..00000000 --- a/doc/site/expressions.markdown +++ /dev/null @@ -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: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PrecOperatorDescriptionAssoc
1() [] .Grouping, Subscript, Method callLeft
2- ! ~Negate, Not, ComplementRight
3* / %Multiply, Divide, ModuloLeft
4+ -Add, SubtractLeft
5.. ...Inclusive range, Exclusive rangeLeft
6<< >>Left shift, Right shiftLeft
7< <= > >=ComparisonLeft
8==EqualsLeft
8!=Not equalLeft
9&Bitwise andLeft
10^Bitwise xorLeft
11|Bitwise orLeft
12isType testLeft
13&&Logical andLeft
14||Logical orLeft
15?:ConditionalRight
16=AssignRight
diff --git a/doc/site/functions.markdown b/doc/site/functions.markdown index 7caf071f..13981506 100644 --- a/doc/site/functions.markdown +++ b/doc/site/functions.markdown @@ -1,5 +1,5 @@ ^title Functions -^category types +^category guide 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 @@ -161,3 +161,6 @@ to`i`: System.print(counter.call()) //> 1 System.print(counter.call()) //> 2 System.print(counter.call()) //> 3 + +Classes → +← Variables diff --git a/doc/site/getting-started.markdown b/doc/site/getting-started.markdown index 20bc33ab..c8535fa0 100644 --- a/doc/site/getting-started.markdown +++ b/doc/site/getting-started.markdown @@ -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]. diff --git a/doc/site/grammar.markdown b/doc/site/grammar.markdown new file mode 100644 index 00000000..206a8305 --- /dev/null +++ b/doc/site/grammar.markdown @@ -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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PrecOperatorDescriptionAssoc
1() [] .Grouping, Subscript, Method callLeft
2- ! ~Negate, Not, ComplementRight
3* / %Multiply, Divide, ModuloLeft
4+ -Add, SubtractLeft
5.. ...Inclusive range, Exclusive rangeLeft
6<< >>Left shift, Right shiftLeft
7< <= > >=ComparisonLeft
8==EqualsLeft
8!=Not equalLeft
9&Bitwise andLeft
10^Bitwise xorLeft
11|Bitwise orLeft
12isType testLeft
13&&Logical andLeft
14||Logical orLeft
15?:ConditionalRight
16=AssignRight
diff --git a/doc/site/index.markdown b/doc/site/index.markdown index fecf65f5..47285817 100644 --- a/doc/site/index.markdown +++ b/doc/site/index.markdown @@ -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/ diff --git a/doc/site/lists.markdown b/doc/site/lists.markdown index 86c4c305..ab0c915a 100644 --- a/doc/site/lists.markdown +++ b/doc/site/lists.markdown @@ -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) //> [] + +Maps → +← Values diff --git a/doc/site/maps.markdown b/doc/site/maps.markdown index 72dce161..30c483f3 100644 --- a/doc/site/maps.markdown +++ b/doc/site/maps.markdown @@ -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—and the reason maps are called "*hash* 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][]: +[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. + +Method Calls → +← Lists diff --git a/doc/site/method-calls.markdown b/doc/site/method-calls.markdown new file mode 100644 index 00000000..85158243 --- /dev/null +++ b/doc/site/method-calls.markdown @@ -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*. + + + +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. + + + +Control Flow → +← Maps diff --git a/doc/site/modules.markdown b/doc/site/modules.markdown index 21942b9d..7ce0bdce 100644 --- a/doc/site/modules.markdown +++ b/doc/site/modules.markdown @@ -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. + +← Error Handling diff --git a/doc/site/qa.markdown b/doc/site/qa.markdown index 6a995ea8..17848eb4 100644 --- a/doc/site/qa.markdown +++ b/doc/site/qa.markdown @@ -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? diff --git a/doc/site/style.scss b/doc/site/style.scss index b8be801e..250bea1e 100644 --- a/doc/site/style.scss +++ b/doc/site/style.scss @@ -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; diff --git a/doc/site/syntax.markdown b/doc/site/syntax.markdown index aab5c8b1..e71919ab 100644 --- a/doc/site/syntax.markdown +++ b/doc/site/syntax.markdown @@ -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" } + +Values → +← Getting Started \ No newline at end of file diff --git a/doc/site/template.html b/doc/site/template.html index 58549fd4..eccda9f6 100644 --- a/doc/site/template.html +++ b/doc/site/template.html @@ -2,7 +2,7 @@ -{title} – Wren +{title} – Wren