From b2941cbbb6f65442dd9405d08e9a1e646527850a Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Tue, 8 Apr 2014 21:18:17 -0700 Subject: [PATCH] Docs for operators and some other stuff. --- doc/site/branching.markdown | 2 +- doc/site/classes.markdown | 49 +++++++++++++++++++++++++++++++------ doc/site/style.scss | 2 +- doc/site/syntax.markdown | 24 ++++++++++++++++++ test/method/operators.wren | 2 ++ 5 files changed, 70 insertions(+), 9 deletions(-) diff --git a/doc/site/branching.markdown b/doc/site/branching.markdown index ca895fd0..f4df520f 100644 --- a/doc/site/branching.markdown +++ b/doc/site/branching.markdown @@ -21,7 +21,7 @@ The simplest branching statement, `if` lets you conditionally skip a chunk of co :::wren if (ready) IO.print("go!") -That evaluates the parenthesized expression after `if`. If it's true, then the statement after the condition is evaluated. Otherwise it is skipped. Instead of a statement, you can have a block: +That evaluates the parenthesized expression after `if`. If it's true, then the statement after the condition is evaluated. Otherwise it is skipped. Instead of a statement, you can have a [block](syntax.html#blocks): :::wren if (ready) { diff --git a/doc/site/classes.markdown b/doc/site/classes.markdown index d3322c47..5c19b9de 100644 --- a/doc/site/classes.markdown +++ b/doc/site/classes.markdown @@ -1,7 +1,5 @@ ^title Classes -**TODO: Refactor `method-calls` and `classes` into using and creating classes.** - 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` class. @@ -55,10 +53,6 @@ Unlike most other dynamically-typed languages, in Wren you can have multiple met When you [call](method-calls.html) the `prance` method, it selects the right one based on how many arguments you pass it. -**TODO: Defining operators and setters.** - -**TODO: `static` methods.** - ## Constructors To create a new instance of a class, you use the `new` keyword. We can make a unicorn like so: @@ -68,14 +62,16 @@ To create a new instance of a class, you use the `new` keyword. We can make a un You almost always want to define some state or do some other initialization on a new object. For that, you'll want to define a constructor, like so: + :::dart class Unicorn { new { IO.print("I am a constructor!") } } -When you create an instance with `new`, its constructor will be invoked. Like methods, you can pass arguments to the constructor by adding a parenthesized parameter list after `new`: +When you create an instance with `new`, its constructor will be invoked. It's just a method with a special name. Like methods, you can pass arguments to the constructor by adding a parenthesized parameter list after `new`: + :::dart class Unicorn { new(name, color) { IO.print("My name is " + name + " and I am " + color + ".") @@ -84,8 +80,47 @@ When you create an instance with `new`, its constructor will be invoked. Like me Values are passed to the constructor like so: + :::dart new Unicorn("Flicker", "purple") +Like other methods, you can overload constructors by arity. + +## Operators + +Operators are just special syntax for regular [method calls](method-calls.html) on the left hand operand (or only operand in the case of unary operators like `!` and `~`). You can define them like so: + + :::dart + class Unicorn { + // Infix: + +(other) { + IO.print("Adding to a unicorn?") + } + + // Prefix: + ! { + IO.print("Negating a unicorn?!") + } + } + +This can be used to define any of these operators: + + :::dart + // Infix: + + - * / % < > <= >= == != & | + + // Prefix: + ! ~ - + +Note that `-` can be both a prefix and infix operator. If there's a parameter list, it's the infix one, otherwise, it's prefix. Since Wren supports overloading by arity, it's no problem for a class to define both. + +Operator overloading is really useful for types like vectors and complex numbers where the reader knows what the operators will do, but can make code deeply confusing if overused. When in doubt, use a real name. + +## Setters + +[Assignment](variables.html) *cannot* be overloaded. It isn't an operator, and its semantics are built right into the language. + +**TODO: ...** + ## Fields **TODO** diff --git a/doc/site/style.scss b/doc/site/style.scss index c6a7041c..2e1e0037 100644 --- a/doc/site/style.scss +++ b/doc/site/style.scss @@ -159,7 +159,7 @@ pre { font: 15px $body; font-weight: 400; list-style-type: none; - margin: 0 0 6px 0; + margin: 0 0 4px 0; } } diff --git a/doc/site/syntax.markdown b/doc/site/syntax.markdown index dbc788fd..691accf0 100644 --- a/doc/site/syntax.markdown +++ b/doc/site/syntax.markdown @@ -50,6 +50,30 @@ Everywhere else, a newline is treated just like a `;`. Note that this is a very different system from how JavaScript handles semicolons. If you've been burned there, don't worry, you should be fine here. +## Blocks + +Wren uses curly braces to define *blocks*. Things like [control flow](branching.html) allow block bodies. [Method](method-calls.html) and [function](functions.html) bodies are also blocks. For example: + + :::dart + if (happy && knowIt) { + hands.clap + } else IO.print("sad") + +Here we have a block for the then case, and just a single expression for the else. Blocks have two similar but not identical forms. If a there is a newline after the opening `{`, then the body contains a series of statements: + + { + IO.print("one") + IO.print("two") + IO.print("three") + } + +If there is no newline, the block may only contain a single expression: + + { "this is fine" } + { while (this) "is an error" } + +These are useful when defining method and function bodies. A normal block body implicitly returns `null`. If you want your method or function to return something different, you need an explicit `return` statement. However, a single-expression block with no newline after the `{` implicitly returns the result of that expression. This is a nice convenience for short methods and functions that just evaluate and return an expression. + ## Names Identifiers are similar to other programming languages. They start with a letter or underscore and may contain letters, digits, and underscores. Case is sensitive. diff --git a/test/method/operators.wren b/test/method/operators.wren index 4e9c6059..b3aff324 100644 --- a/test/method/operators.wren +++ b/test/method/operators.wren @@ -14,6 +14,7 @@ class Foo { |(other) { "infix | " + other } ! { "prefix !" } + ~ { "prefix ~" } - { "prefix -" } } @@ -32,4 +33,5 @@ IO.print(foo != "a") // expect: infix != a IO.print(foo & "a") // expect: infix & a IO.print(foo | "a") // expect: infix | a IO.print(!foo) // expect: prefix ! +IO.print(~foo) // expect: prefix ~ IO.print(-foo) // expect: prefix -