Add hacks to extract and compile tutorial code
Not included in the build by default, since it's fragile and kludgy. Do something like this to run it: cd doc/tutorial RUSTC=../../build/stage2/bin/rustc bash test.sh Closes #1143
This commit is contained in:
parent
1b8b0b8584
commit
fedb775fbb
@ -22,6 +22,8 @@ other tasks, and that most data is immutable.
|
|||||||
|
|
||||||
Take the following program:
|
Take the following program:
|
||||||
|
|
||||||
|
# fn get_really_big_record() -> int { 1 }
|
||||||
|
# fn myfunc(a: int) {}
|
||||||
let x = get_really_big_record();
|
let x = get_really_big_record();
|
||||||
myfunc(x);
|
myfunc(x);
|
||||||
|
|
||||||
@ -32,6 +34,9 @@ existing value as the argument, without copying.
|
|||||||
|
|
||||||
There are more involved cases. The call could look like this:
|
There are more involved cases. The call could look like this:
|
||||||
|
|
||||||
|
# fn myfunc(a: int, b: block()) {}
|
||||||
|
# fn get_another_record() -> int { 1 }
|
||||||
|
# let x = 1;
|
||||||
myfunc(x, {|| x = get_another_record(); });
|
myfunc(x, {|| x = get_another_record(); });
|
||||||
|
|
||||||
Now, if `myfunc` first calls its second argument and then accesses its
|
Now, if `myfunc` first calls its second argument and then accesses its
|
||||||
|
@ -4,7 +4,15 @@ require("./lib/codemirror-rust");
|
|||||||
|
|
||||||
md.Markdown.dialects.Maruku.block.code = function code(block, next) {
|
md.Markdown.dialects.Maruku.block.code = function code(block, next) {
|
||||||
if (block.match(/^ /)) {
|
if (block.match(/^ /)) {
|
||||||
var text = block.replace(/(^|\n) /g, "$1"), accum = [], curstr = "", curstyle = null;
|
var text = String(block);
|
||||||
|
while (next.length && next[0].match(/^ /)) text += "\n" + String(next.shift());
|
||||||
|
var leaveAlone, accum = [], curstr = "", curstyle = null;
|
||||||
|
text = text.split("\n").map(function(line) {
|
||||||
|
line = line.slice(4);
|
||||||
|
if (line == "## notrust") leaveAlone = true;
|
||||||
|
return line;
|
||||||
|
}).filter(function(x) { return !/^##? /.test(x); }).join("\n");
|
||||||
|
if (leaveAlone) return [["pre", {}, text]];
|
||||||
function add(str, style) {
|
function add(str, style) {
|
||||||
if (style != curstyle) {
|
if (style != curstyle) {
|
||||||
if (curstyle) accum.push(["span", {"class": "cm-" + curstyle}, curstr]);
|
if (curstyle) accum.push(["span", {"class": "cm-" + curstyle}, curstr]);
|
||||||
|
@ -38,6 +38,7 @@ Rust's `alt` construct is a generalized, cleaned-up version of C's
|
|||||||
each labelled with a pattern, and it will execute the arm that matches
|
each labelled with a pattern, and it will execute the arm that matches
|
||||||
the value.
|
the value.
|
||||||
|
|
||||||
|
# let my_number = 1;
|
||||||
alt my_number {
|
alt my_number {
|
||||||
0 { std::io::println("zero"); }
|
0 { std::io::println("zero"); }
|
||||||
1 | 2 { std::io::println("one or two"); }
|
1 | 2 { std::io::println("one or two"); }
|
||||||
@ -89,6 +90,7 @@ To a limited extent, it is possible to use destructuring patterns when
|
|||||||
declaring a variable with `let`. For example, you can say this to
|
declaring a variable with `let`. For example, you can say this to
|
||||||
extract the fields from a tuple:
|
extract the fields from a tuple:
|
||||||
|
|
||||||
|
# fn get_tuple_of_two_ints() -> (int, int) { (1, 1) }
|
||||||
let (a, b) = get_tuple_of_two_ints();
|
let (a, b) = get_tuple_of_two_ints();
|
||||||
|
|
||||||
This will introduce two new variables, `a` and `b`, bound to the
|
This will introduce two new variables, `a` and `b`, bound to the
|
||||||
@ -118,6 +120,8 @@ it finds one that can be divided by five.
|
|||||||
There's also `while`'s ugly cousin, `do`/`while`, which does not check
|
There's also `while`'s ugly cousin, `do`/`while`, which does not check
|
||||||
its condition on the first iteration, using traditional syntax:
|
its condition on the first iteration, using traditional syntax:
|
||||||
|
|
||||||
|
# fn eat_cake() {}
|
||||||
|
# fn any_cake_left() -> bool { false }
|
||||||
do {
|
do {
|
||||||
eat_cake();
|
eat_cake();
|
||||||
} while any_cake_left();
|
} while any_cake_left();
|
||||||
|
@ -56,6 +56,7 @@ Records can be destructured on in `alt` patterns. The basic syntax is
|
|||||||
omitted as a shorthand for simply binding the variable with the same
|
omitted as a shorthand for simply binding the variable with the same
|
||||||
name as the field.
|
name as the field.
|
||||||
|
|
||||||
|
# let mypoint = {x: 0f, y: 0f};
|
||||||
alt mypoint {
|
alt mypoint {
|
||||||
{x: 0f, y: y_name} { /* Provide sub-patterns for fields */ }
|
{x: 0f, y: y_name} { /* Provide sub-patterns for fields */ }
|
||||||
{x, y} { /* Simply bind the fields */ }
|
{x, y} { /* Simply bind the fields */ }
|
||||||
@ -71,6 +72,7 @@ the fields of a record, a record pattern may end with `, _` (as in
|
|||||||
Tags [FIXME terminology] are datatypes that have several different
|
Tags [FIXME terminology] are datatypes that have several different
|
||||||
representations. For example, the type shown earlier:
|
representations. For example, the type shown earlier:
|
||||||
|
|
||||||
|
# type point = {x: float, y: float};
|
||||||
tag shape {
|
tag shape {
|
||||||
circle(point, float);
|
circle(point, float);
|
||||||
rectangle(point, point);
|
rectangle(point, point);
|
||||||
@ -96,7 +98,7 @@ equivalent to an `enum` in C:
|
|||||||
east;
|
east;
|
||||||
south;
|
south;
|
||||||
west;
|
west;
|
||||||
};
|
}
|
||||||
|
|
||||||
This will define `north`, `east`, `south`, and `west` as constants,
|
This will define `north`, `east`, `south`, and `west` as constants,
|
||||||
all of which have type `direction`.
|
all of which have type `direction`.
|
||||||
@ -116,6 +118,7 @@ That is a shorthand for this:
|
|||||||
Tag types like this can have their content extracted with the
|
Tag types like this can have their content extracted with the
|
||||||
dereference (`*`) unary operator:
|
dereference (`*`) unary operator:
|
||||||
|
|
||||||
|
# tag gizmo_id = int;
|
||||||
let my_gizmo_id = gizmo_id(10);
|
let my_gizmo_id = gizmo_id(10);
|
||||||
let id_int: int = *my_gizmo_id;
|
let id_int: int = *my_gizmo_id;
|
||||||
|
|
||||||
@ -125,6 +128,8 @@ For tag types with multiple variants, destructuring is the only way to
|
|||||||
get at their contents. All variant constructors can be used as
|
get at their contents. All variant constructors can be used as
|
||||||
patterns, as in this definition of `area`:
|
patterns, as in this definition of `area`:
|
||||||
|
|
||||||
|
# type point = {x: float, y: float};
|
||||||
|
# tag shape { circle(point, float); rectangle(point, point); }
|
||||||
fn area(sh: shape) -> float {
|
fn area(sh: shape) -> float {
|
||||||
alt sh {
|
alt sh {
|
||||||
circle(_, size) { std::math::pi * size * size }
|
circle(_, size) { std::math::pi * size * size }
|
||||||
@ -136,6 +141,8 @@ For variants without arguments, you have to write `variantname.` (with
|
|||||||
a dot at the end) to match them in a pattern. This to prevent
|
a dot at the end) to match them in a pattern. This to prevent
|
||||||
ambiguity between matching a variant name and binding a new variable.
|
ambiguity between matching a variant name and binding a new variable.
|
||||||
|
|
||||||
|
# type point = {x: float, y: float};
|
||||||
|
# tag direction { north; east; south; west; }
|
||||||
fn point_from_direction(dir: direction) -> point {
|
fn point_from_direction(dir: direction) -> point {
|
||||||
alt dir {
|
alt dir {
|
||||||
north. { {x: 0f, y: 1f} }
|
north. { {x: 0f, y: 1f} }
|
||||||
@ -295,6 +302,7 @@ strings. They are always immutable.
|
|||||||
|
|
||||||
Resources are data types that have a destructor associated with them.
|
Resources are data types that have a destructor associated with them.
|
||||||
|
|
||||||
|
# fn close_file_desc(x: int) {}
|
||||||
resource file_desc(fd: int) {
|
resource file_desc(fd: int) {
|
||||||
close_file_desc(fd);
|
close_file_desc(fd);
|
||||||
}
|
}
|
||||||
|
42
doc/tutorial/extract.js
Normal file
42
doc/tutorial/extract.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
var fs = require("fs"), md = require("./lib/markdown");
|
||||||
|
|
||||||
|
// Runs markdown.js over the tutorial, to find the code blocks in it.
|
||||||
|
// Uses the #-markers in those code blocks, along with some vague
|
||||||
|
// heuristics, to turn them into compilable files. Outputs these files
|
||||||
|
// to fragments/.
|
||||||
|
//
|
||||||
|
// '##ignore' means don't test this block
|
||||||
|
// '##notrust' means the block isn't rust code
|
||||||
|
// (used by build.js to not highlight it)
|
||||||
|
// '# code' means insert the given code to complete the fragment
|
||||||
|
// (build.js strips out such lines)
|
||||||
|
|
||||||
|
var curFile, curFrag;
|
||||||
|
md.Markdown.dialects.Maruku.block.code = function code(block, next) {
|
||||||
|
if (block.match(/^ /)) {
|
||||||
|
var ignore, text = String(block);
|
||||||
|
while (next.length && next[0].match(/^ /)) text += "\n" + String(next.shift());
|
||||||
|
text = text.split("\n").map(function(line) {
|
||||||
|
line = line.slice(4);
|
||||||
|
if (line == "## ignore" || line == "## notrust") { ignore = true; line = ""; }
|
||||||
|
if (/^# /.test(line)) line = line.slice(2);
|
||||||
|
return line;
|
||||||
|
}).join("\n");
|
||||||
|
if (ignore) return;
|
||||||
|
if (!/\bfn main\b/.test(text)) {
|
||||||
|
if (/(^|\n) *(native|use|mod|import|export)\b/.test(text))
|
||||||
|
text += "\nfn main() {}\n";
|
||||||
|
else text = "fn main() {\n" + text + "\n}\n";
|
||||||
|
}
|
||||||
|
if (!/\buse std\b/.test(text)) text = "use std;\n" + text;
|
||||||
|
fs.writeFileSync("fragments/" + curFile + "_" + (++curFrag) + ".rs", text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.readFileSync("order", "utf8").split("\n").filter(id).forEach(handle);
|
||||||
|
|
||||||
|
function id(x) { return x; }
|
||||||
|
function handle(file) {
|
||||||
|
curFile = file; curFrag = 0;
|
||||||
|
md.parse(fs.readFileSync(file + ".md", "utf8"), "Maruku");
|
||||||
|
}
|
@ -67,6 +67,7 @@ most notably the Windows API, use other calling conventions, so Rust
|
|||||||
provides a way to to hint to the compiler which is expected by using
|
provides a way to to hint to the compiler which is expected by using
|
||||||
the `"abi"` attribute:
|
the `"abi"` attribute:
|
||||||
|
|
||||||
|
#[cfg(target_os = "win32")]
|
||||||
#[abi = "stdcall"]
|
#[abi = "stdcall"]
|
||||||
native mod kernel32 {
|
native mod kernel32 {
|
||||||
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
|
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
|
||||||
@ -81,7 +82,9 @@ or `"stdcall"`. Other conventions may be defined in the future.
|
|||||||
The native `SHA1` function is declared to take three arguments, and
|
The native `SHA1` function is declared to take three arguments, and
|
||||||
return a pointer.
|
return a pointer.
|
||||||
|
|
||||||
|
# native mod crypto {
|
||||||
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
|
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
|
||||||
|
# }
|
||||||
|
|
||||||
When declaring the argument types to a foreign function, the Rust
|
When declaring the argument types to a foreign function, the Rust
|
||||||
compiler has no way to check whether your declaration is correct, so
|
compiler has no way to check whether your declaration is correct, so
|
||||||
@ -106,6 +109,9 @@ null pointers.
|
|||||||
|
|
||||||
The `sha1` function is the most obscure part of the program.
|
The `sha1` function is the most obscure part of the program.
|
||||||
|
|
||||||
|
# import std::{str, vec};
|
||||||
|
# mod crypto { fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out } }
|
||||||
|
# fn as_hex(data: [u8]) -> str { "hi" }
|
||||||
fn sha1(data: str) -> str unsafe {
|
fn sha1(data: str) -> str unsafe {
|
||||||
let bytes = str::bytes(data);
|
let bytes = str::bytes(data);
|
||||||
let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes),
|
let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes),
|
||||||
@ -141,10 +147,15 @@ Rust's safety mechanisms.
|
|||||||
|
|
||||||
Let's look at our `sha1` function again.
|
Let's look at our `sha1` function again.
|
||||||
|
|
||||||
|
# import std::{str, vec};
|
||||||
|
# mod crypto { fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out } }
|
||||||
|
# fn as_hex(data: [u8]) -> str { "hi" }
|
||||||
|
# fn x(data: str) -> str unsafe {
|
||||||
let bytes = str::bytes(data);
|
let bytes = str::bytes(data);
|
||||||
let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes),
|
let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes),
|
||||||
vec::len(bytes), std::ptr::null());
|
vec::len(bytes), std::ptr::null());
|
||||||
ret as_hex(vec::unsafe::from_buf(hash, 20u));
|
ret as_hex(vec::unsafe::from_buf(hash, 20u));
|
||||||
|
# }
|
||||||
|
|
||||||
The `str::bytes` function is perfectly safe, it converts a string to
|
The `str::bytes` function is perfectly safe, it converts a string to
|
||||||
an `[u8]`. This byte array is then fed to `vec::unsafe::to_ptr`, which
|
an `[u8]`. This byte array is then fed to `vec::unsafe::to_ptr`, which
|
||||||
|
@ -19,6 +19,10 @@ This helps the compiler avoid spurious error messages. For example,
|
|||||||
the following code would be a type error if `dead_end` would be
|
the following code would be a type error if `dead_end` would be
|
||||||
expected to return.
|
expected to return.
|
||||||
|
|
||||||
|
# fn can_go_left() -> bool { true }
|
||||||
|
# fn can_go_right() -> bool { true }
|
||||||
|
# tag dir { left; right; }
|
||||||
|
# fn dead_end() -> ! { fail; }
|
||||||
let dir = if can_go_left() { left }
|
let dir = if can_go_left() { left }
|
||||||
else if can_go_right() { right }
|
else if can_go_right() { right }
|
||||||
else { dead_end(); };
|
else { dead_end(); };
|
||||||
@ -96,12 +100,14 @@ of integers backwards:
|
|||||||
|
|
||||||
To run such an iteration, you could do this:
|
To run such an iteration, you could do this:
|
||||||
|
|
||||||
|
# fn for_rev(v: [int], act: block(int)) {}
|
||||||
for_rev([1, 2, 3], {|n| log n; });
|
for_rev([1, 2, 3], {|n| log n; });
|
||||||
|
|
||||||
But Rust allows a more pleasant syntax for this situation, with the
|
But Rust allows a more pleasant syntax for this situation, with the
|
||||||
loop block moved out of the parenthesis and the final semicolon
|
loop block moved out of the parenthesis and the final semicolon
|
||||||
omitted:
|
omitted:
|
||||||
|
|
||||||
|
# fn for_rev(v: [int], act: block(int)) {}
|
||||||
for_rev([1, 2, 3]) {|n|
|
for_rev([1, 2, 3]) {|n|
|
||||||
log n;
|
log n;
|
||||||
}
|
}
|
||||||
|
@ -55,16 +55,17 @@ dereferences become impossible.
|
|||||||
Rust's type inferrer works very well with generics, but there are
|
Rust's type inferrer works very well with generics, but there are
|
||||||
programs that just can't be typed.
|
programs that just can't be typed.
|
||||||
|
|
||||||
let n = none;
|
let n = std::option::none;
|
||||||
|
# n = std::option::some(1);
|
||||||
|
|
||||||
If you never do anything else with `n`, the compiler will not be able
|
If you never do anything else with `n`, the compiler will not be able
|
||||||
to assign a type to it. (The same goes for `[]`, in fact.) If you
|
to assign a type to it. (The same goes for `[]`, in fact.) If you
|
||||||
really want to have such a statement, you'll have to write it like
|
really want to have such a statement, you'll have to write it like
|
||||||
this:
|
this:
|
||||||
|
|
||||||
let n2: option::t<int> = none;
|
let n2: std::option::t<int> = std::option::none;
|
||||||
// or
|
// or
|
||||||
let n = none::<int>;
|
let n = std::option::none::<int>;
|
||||||
|
|
||||||
Note that, in a value expression, `<` already has a meaning as a
|
Note that, in a value expression, `<` already has a meaning as a
|
||||||
comparison operator, so you'll have to write `::<T>` to explicitly
|
comparison operator, so you'll have to write `::<T>` to explicitly
|
||||||
@ -120,6 +121,7 @@ take sendable types.
|
|||||||
|
|
||||||
If you try this program:
|
If you try this program:
|
||||||
|
|
||||||
|
# fn map(f: block(int) -> int, v: [int]) {}
|
||||||
fn plus1(x: int) -> int { x + 1 }
|
fn plus1(x: int) -> int { x + 1 }
|
||||||
map(plus1, [1, 2, 3]);
|
map(plus1, [1, 2, 3]);
|
||||||
|
|
||||||
@ -131,6 +133,7 @@ way to pass integers, which is by value. To get around this issue, you
|
|||||||
have to explicitly mark the arguments to a function that you want to
|
have to explicitly mark the arguments to a function that you want to
|
||||||
pass to a generic higher-order function as being passed by pointer:
|
pass to a generic higher-order function as being passed by pointer:
|
||||||
|
|
||||||
|
# fn map<T, U>(f: block(T) -> U, v: [T]) {}
|
||||||
fn plus1(&&x: int) -> int { x + 1 }
|
fn plus1(&&x: int) -> int { x + 1 }
|
||||||
map(plus1, [1, 2, 3]);
|
map(plus1, [1, 2, 3]);
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ It is also possible to include multiple files in a crate. For this
|
|||||||
purpose, you create a `.rc` crate file, which references any number of
|
purpose, you create a `.rc` crate file, which references any number of
|
||||||
`.rs` code files. A crate file could look like this:
|
`.rs` code files. A crate file could look like this:
|
||||||
|
|
||||||
|
## ignore
|
||||||
#[link(name = "farm", vers = "2.5", author = "mjh")];
|
#[link(name = "farm", vers = "2.5", author = "mjh")];
|
||||||
mod cow;
|
mod cow;
|
||||||
mod chicken;
|
mod chicken;
|
||||||
@ -52,6 +53,7 @@ in a moment.
|
|||||||
To have a nested directory structure for your source files, you can
|
To have a nested directory structure for your source files, you can
|
||||||
nest mods in your `.rc` file:
|
nest mods in your `.rc` file:
|
||||||
|
|
||||||
|
## ignore
|
||||||
mod poultry {
|
mod poultry {
|
||||||
mod chicken;
|
mod chicken;
|
||||||
mod turkey;
|
mod turkey;
|
||||||
@ -79,6 +81,7 @@ OS X.
|
|||||||
It is possible to provide more specific information when using an
|
It is possible to provide more specific information when using an
|
||||||
external crate.
|
external crate.
|
||||||
|
|
||||||
|
## ignore
|
||||||
use myfarm (name = "farm", vers = "2.7");
|
use myfarm (name = "farm", vers = "2.7");
|
||||||
|
|
||||||
When a comma-separated list of name/value pairs is given after `use`,
|
When a comma-separated list of name/value pairs is given after `use`,
|
||||||
@ -90,6 +93,7 @@ local name `myfarm`.
|
|||||||
|
|
||||||
Our example crate declared this set of `link` attributes:
|
Our example crate declared this set of `link` attributes:
|
||||||
|
|
||||||
|
## ignore
|
||||||
#[link(name = "farm", vers = "2.5", author = "mjh")];
|
#[link(name = "farm", vers = "2.5", author = "mjh")];
|
||||||
|
|
||||||
The version does not match the one provided in the `use` directive, so
|
The version does not match the one provided in the `use` directive, so
|
||||||
@ -105,12 +109,14 @@ these two files:
|
|||||||
#[link(name = "mylib", vers = "1.0")];
|
#[link(name = "mylib", vers = "1.0")];
|
||||||
fn world() -> str { "world" }
|
fn world() -> str { "world" }
|
||||||
|
|
||||||
|
## ignore
|
||||||
// main.rs
|
// main.rs
|
||||||
use mylib;
|
use mylib;
|
||||||
fn main() { log_err "hello " + mylib::world(); }
|
fn main() { log_err "hello " + mylib::world(); }
|
||||||
|
|
||||||
Now compile and run like this (adjust to your platform if necessary):
|
Now compile and run like this (adjust to your platform if necessary):
|
||||||
|
|
||||||
|
## notrust
|
||||||
> rustc --lib mylib.rs
|
> rustc --lib mylib.rs
|
||||||
> rustc main.rs -L .
|
> rustc main.rs -L .
|
||||||
> ./main
|
> ./main
|
||||||
@ -147,8 +153,8 @@ restricted with `export` directives at the top of the module or file.
|
|||||||
mod enc {
|
mod enc {
|
||||||
export encrypt, decrypt;
|
export encrypt, decrypt;
|
||||||
const super_secret_number: int = 10;
|
const super_secret_number: int = 10;
|
||||||
fn encrypt(n: int) { n + super_secret_number }
|
fn encrypt(n: int) -> int { n + super_secret_number }
|
||||||
fn decrypt(n: int) { n - super_secret_number }
|
fn decrypt(n: int) -> int { n - super_secret_number }
|
||||||
}
|
}
|
||||||
|
|
||||||
This defines a rock-solid encryption algorithm. Code outside of the
|
This defines a rock-solid encryption algorithm. Code outside of the
|
||||||
|
@ -21,6 +21,7 @@ If you modify the program to make it invalid (for example, remove the
|
|||||||
`use std` line), and then compile it, you'll see an error message like
|
`use std` line), and then compile it, you'll see an error message like
|
||||||
this:
|
this:
|
||||||
|
|
||||||
|
## notrust
|
||||||
hello.rs:2:4: 2:20 error: unresolved modulename: std
|
hello.rs:2:4: 2:20 error: unresolved modulename: std
|
||||||
hello.rs:2 std::io::println("hello world!");
|
hello.rs:2 std::io::println("hello world!");
|
||||||
^~~~~~~~~~~~~~~~
|
^~~~~~~~~~~~~~~~
|
||||||
|
@ -21,6 +21,7 @@ statements and expressions is C-like. Function calls are written
|
|||||||
precedence that they have in C, comments look the same, and constructs
|
precedence that they have in C, comments look the same, and constructs
|
||||||
like `if` and `while` are available:
|
like `if` and `while` are available:
|
||||||
|
|
||||||
|
# fn call_a_function(_a: int) {}
|
||||||
fn main() {
|
fn main() {
|
||||||
if 1 < 2 {
|
if 1 < 2 {
|
||||||
while false { call_a_function(10 * 4); }
|
while false { call_a_function(10 * 4); }
|
||||||
@ -39,10 +40,13 @@ of languages. A lot of thing that are statements in C are expressions
|
|||||||
in Rust. This allows for useless things like this (which passes
|
in Rust. This allows for useless things like this (which passes
|
||||||
nil—the void type—to a function):
|
nil—the void type—to a function):
|
||||||
|
|
||||||
|
# fn a_function(_a: ()) {}
|
||||||
a_function(while false {});
|
a_function(while false {});
|
||||||
|
|
||||||
But also useful things like this:
|
But also useful things like this:
|
||||||
|
|
||||||
|
# fn the_stars_align() -> bool { false }
|
||||||
|
# fn something_else() -> bool { true }
|
||||||
let x = if the_stars_align() { 4 }
|
let x = if the_stars_align() { 4 }
|
||||||
else if something_else() { 3 }
|
else if something_else() { 3 }
|
||||||
else { 0 };
|
else { 0 };
|
||||||
@ -125,6 +129,7 @@ annotation:
|
|||||||
|
|
||||||
// The type of this vector will be inferred based on its use.
|
// The type of this vector will be inferred based on its use.
|
||||||
let x = [];
|
let x = [];
|
||||||
|
# x = [3];
|
||||||
// Explicitly say this is a vector of integers.
|
// Explicitly say this is a vector of integers.
|
||||||
let y: [int] = [];
|
let y: [int] = [];
|
||||||
|
|
||||||
@ -272,6 +277,7 @@ The comparison operators are the traditional `==`, `!=`, `<`, `>`,
|
|||||||
|
|
||||||
Rust has a ternary conditional operator `?:`, as in:
|
Rust has a ternary conditional operator `?:`, as in:
|
||||||
|
|
||||||
|
let badness = 12;
|
||||||
let message = badness < 10 ? "error" : "FATAL ERROR";
|
let message = badness < 10 ? "error" : "FATAL ERROR";
|
||||||
|
|
||||||
For type casting, Rust uses the binary `as` operator, which has a
|
For type casting, Rust uses the binary `as` operator, which has a
|
||||||
@ -311,19 +317,14 @@ followed by a comma-separated list of nested attributes, as in the
|
|||||||
`cfg` example above, or in this [crate](mod.html) metadata
|
`cfg` example above, or in this [crate](mod.html) metadata
|
||||||
declaration:
|
declaration:
|
||||||
|
|
||||||
|
## ignore
|
||||||
#[link(name = "std",
|
#[link(name = "std",
|
||||||
vers = "0.1",
|
vers = "0.1",
|
||||||
url = "http://rust-lang.org/src/std")];
|
url = "http://rust-lang.org/src/std")];
|
||||||
|
|
||||||
An attribute without a semicolon following it applies to the
|
An attribute without a semicolon following it applies to the
|
||||||
definition that follows it. When terminated with a semicolon, it
|
definition that follows it. When terminated with a semicolon, it
|
||||||
applies to the current context. The above example could also be
|
applies to the module or crate.
|
||||||
written like this:
|
|
||||||
|
|
||||||
fn register_win_service() {
|
|
||||||
#[cfg(target_os = "win32")];
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
## Syntax extensions
|
## Syntax extensions
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ When you compile the program normally, the `test_twice` function will
|
|||||||
not be used. To actually run the tests, compile with the `--test`
|
not be used. To actually run the tests, compile with the `--test`
|
||||||
flag:
|
flag:
|
||||||
|
|
||||||
|
## notrust
|
||||||
> rustc --lib twice.rs
|
> rustc --lib twice.rs
|
||||||
> ./twice
|
> ./twice
|
||||||
running 1 tests
|
running 1 tests
|
||||||
@ -30,6 +31,7 @@ flag:
|
|||||||
Or, if we change the file to fail, for example by replacing `x + x`
|
Or, if we change the file to fail, for example by replacing `x + x`
|
||||||
with `x + 1`:
|
with `x + 1`:
|
||||||
|
|
||||||
|
## notrust
|
||||||
running 1 tests
|
running 1 tests
|
||||||
test test_twice ... FAILED
|
test test_twice ... FAILED
|
||||||
failures:
|
failures:
|
||||||
|
8
doc/tutorial/test.sh
Normal file
8
doc/tutorial/test.sh
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
rm -f fragments/*.rs
|
||||||
|
mkdir -p fragments
|
||||||
|
node extract.js
|
||||||
|
for F in `ls fragments/*.rs`; do
|
||||||
|
$RUSTC $F > /dev/null
|
||||||
|
if [[ $? != 0 ]] ; then echo $F; fi
|
||||||
|
done
|
@ -2485,22 +2485,12 @@ fn parse_crate_directive(p: parser, first_outer_attr: [ast::attribute]) ->
|
|||||||
_ { none }
|
_ { none }
|
||||||
};
|
};
|
||||||
alt p.peek() {
|
alt p.peek() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// mod x = "foo.rs";
|
// mod x = "foo.rs";
|
||||||
token::SEMI. {
|
token::SEMI. {
|
||||||
let hi = p.get_hi_pos();
|
let hi = p.get_hi_pos();
|
||||||
p.bump();
|
p.bump();
|
||||||
ret spanned(lo, hi, ast::cdir_src_mod(id, file_opt, outer_attrs));
|
ret spanned(lo, hi, ast::cdir_src_mod(id, file_opt, outer_attrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// mod x = "foo_dir" { ...directives... }
|
// mod x = "foo_dir" { ...directives... }
|
||||||
token::LBRACE. {
|
token::LBRACE. {
|
||||||
p.bump();
|
p.bump();
|
||||||
|
Loading…
Reference in New Issue
Block a user