Skip to content

Commit fedb775

Browse files
committed
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
1 parent 1b8b0b8 commit fedb775

File tree

14 files changed

+119
-24
lines changed

14 files changed

+119
-24
lines changed

doc/tutorial/args.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ other tasks, and that most data is immutable.
2222

2323
Take the following program:
2424

25+
# fn get_really_big_record() -> int { 1 }
26+
# fn myfunc(a: int) {}
2527
let x = get_really_big_record();
2628
myfunc(x);
2729

@@ -32,6 +34,9 @@ existing value as the argument, without copying.
3234

3335
There are more involved cases. The call could look like this:
3436

37+
# fn myfunc(a: int, b: block()) {}
38+
# fn get_another_record() -> int { 1 }
39+
# let x = 1;
3540
myfunc(x, {|| x = get_another_record(); });
3641

3742
Now, if `myfunc` first calls its second argument and then accesses its

doc/tutorial/build.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@ require("./lib/codemirror-rust");
44

55
md.Markdown.dialects.Maruku.block.code = function code(block, next) {
66
if (block.match(/^ /)) {
7-
var text = block.replace(/(^|\n) /g, "$1"), accum = [], curstr = "", curstyle = null;
7+
var text = String(block);
8+
while (next.length && next[0].match(/^ /)) text += "\n" + String(next.shift());
9+
var leaveAlone, accum = [], curstr = "", curstyle = null;
10+
text = text.split("\n").map(function(line) {
11+
line = line.slice(4);
12+
if (line == "## notrust") leaveAlone = true;
13+
return line;
14+
}).filter(function(x) { return !/^##? /.test(x); }).join("\n");
15+
if (leaveAlone) return [["pre", {}, text]];
816
function add(str, style) {
917
if (style != curstyle) {
1018
if (curstyle) accum.push(["span", {"class": "cm-" + curstyle}, curstr]);

doc/tutorial/control.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Rust's `alt` construct is a generalized, cleaned-up version of C's
3838
each labelled with a pattern, and it will execute the arm that matches
3939
the value.
4040

41+
# let my_number = 1;
4142
alt my_number {
4243
0 { std::io::println("zero"); }
4344
1 | 2 { std::io::println("one or two"); }
@@ -89,6 +90,7 @@ To a limited extent, it is possible to use destructuring patterns when
8990
declaring a variable with `let`. For example, you can say this to
9091
extract the fields from a tuple:
9192

93+
# fn get_tuple_of_two_ints() -> (int, int) { (1, 1) }
9294
let (a, b) = get_tuple_of_two_ints();
9395

9496
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.
118120
There's also `while`'s ugly cousin, `do`/`while`, which does not check
119121
its condition on the first iteration, using traditional syntax:
120122

123+
# fn eat_cake() {}
124+
# fn any_cake_left() -> bool { false }
121125
do {
122126
eat_cake();
123127
} while any_cake_left();

doc/tutorial/data.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Records can be destructured on in `alt` patterns. The basic syntax is
5656
omitted as a shorthand for simply binding the variable with the same
5757
name as the field.
5858

59+
# let mypoint = {x: 0f, y: 0f};
5960
alt mypoint {
6061
{x: 0f, y: y_name} { /* Provide sub-patterns for fields */ }
6162
{x, y} { /* Simply bind the fields */ }
@@ -71,6 +72,7 @@ the fields of a record, a record pattern may end with `, _` (as in
7172
Tags [FIXME terminology] are datatypes that have several different
7273
representations. For example, the type shown earlier:
7374

75+
# type point = {x: float, y: float};
7476
tag shape {
7577
circle(point, float);
7678
rectangle(point, point);
@@ -96,7 +98,7 @@ equivalent to an `enum` in C:
9698
east;
9799
south;
98100
west;
99-
};
101+
}
100102

101103
This will define `north`, `east`, `south`, and `west` as constants,
102104
all of which have type `direction`.
@@ -116,6 +118,7 @@ That is a shorthand for this:
116118
Tag types like this can have their content extracted with the
117119
dereference (`*`) unary operator:
118120

121+
# tag gizmo_id = int;
119122
let my_gizmo_id = gizmo_id(10);
120123
let id_int: int = *my_gizmo_id;
121124

@@ -125,6 +128,8 @@ For tag types with multiple variants, destructuring is the only way to
125128
get at their contents. All variant constructors can be used as
126129
patterns, as in this definition of `area`:
127130

131+
# type point = {x: float, y: float};
132+
# tag shape { circle(point, float); rectangle(point, point); }
128133
fn area(sh: shape) -> float {
129134
alt sh {
130135
circle(_, size) { std::math::pi * size * size }
@@ -136,6 +141,8 @@ For variants without arguments, you have to write `variantname.` (with
136141
a dot at the end) to match them in a pattern. This to prevent
137142
ambiguity between matching a variant name and binding a new variable.
138143

144+
# type point = {x: float, y: float};
145+
# tag direction { north; east; south; west; }
139146
fn point_from_direction(dir: direction) -> point {
140147
alt dir {
141148
north. { {x: 0f, y: 1f} }
@@ -295,6 +302,7 @@ strings. They are always immutable.
295302

296303
Resources are data types that have a destructor associated with them.
297304

305+
# fn close_file_desc(x: int) {}
298306
resource file_desc(fd: int) {
299307
close_file_desc(fd);
300308
}

doc/tutorial/extract.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
var fs = require("fs"), md = require("./lib/markdown");
2+
3+
// Runs markdown.js over the tutorial, to find the code blocks in it.
4+
// Uses the #-markers in those code blocks, along with some vague
5+
// heuristics, to turn them into compilable files. Outputs these files
6+
// to fragments/.
7+
//
8+
// '##ignore' means don't test this block
9+
// '##notrust' means the block isn't rust code
10+
// (used by build.js to not highlight it)
11+
// '# code' means insert the given code to complete the fragment
12+
// (build.js strips out such lines)
13+
14+
var curFile, curFrag;
15+
md.Markdown.dialects.Maruku.block.code = function code(block, next) {
16+
if (block.match(/^ /)) {
17+
var ignore, text = String(block);
18+
while (next.length && next[0].match(/^ /)) text += "\n" + String(next.shift());
19+
text = text.split("\n").map(function(line) {
20+
line = line.slice(4);
21+
if (line == "## ignore" || line == "## notrust") { ignore = true; line = ""; }
22+
if (/^# /.test(line)) line = line.slice(2);
23+
return line;
24+
}).join("\n");
25+
if (ignore) return;
26+
if (!/\bfn main\b/.test(text)) {
27+
if (/(^|\n) *(native|use|mod|import|export)\b/.test(text))
28+
text += "\nfn main() {}\n";
29+
else text = "fn main() {\n" + text + "\n}\n";
30+
}
31+
if (!/\buse std\b/.test(text)) text = "use std;\n" + text;
32+
fs.writeFileSync("fragments/" + curFile + "_" + (++curFrag) + ".rs", text);
33+
}
34+
};
35+
36+
fs.readFileSync("order", "utf8").split("\n").filter(id).forEach(handle);
37+
38+
function id(x) { return x; }
39+
function handle(file) {
40+
curFile = file; curFrag = 0;
41+
md.parse(fs.readFileSync(file + ".md", "utf8"), "Maruku");
42+
}

doc/tutorial/ffi.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ most notably the Windows API, use other calling conventions, so Rust
6767
provides a way to to hint to the compiler which is expected by using
6868
the `"abi"` attribute:
6969

70+
#[cfg(target_os = "win32")]
7071
#[abi = "stdcall"]
7172
native mod kernel32 {
7273
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
@@ -81,7 +82,9 @@ or `"stdcall"`. Other conventions may be defined in the future.
8182
The native `SHA1` function is declared to take three arguments, and
8283
return a pointer.
8384

85+
# native mod crypto {
8486
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
87+
# }
8588

8689
When declaring the argument types to a foreign function, the Rust
8790
compiler has no way to check whether your declaration is correct, so
@@ -106,6 +109,9 @@ null pointers.
106109

107110
The `sha1` function is the most obscure part of the program.
108111

112+
# import std::{str, vec};
113+
# mod crypto { fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out } }
114+
# fn as_hex(data: [u8]) -> str { "hi" }
109115
fn sha1(data: str) -> str unsafe {
110116
let bytes = str::bytes(data);
111117
let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes),
@@ -141,10 +147,15 @@ Rust's safety mechanisms.
141147

142148
Let's look at our `sha1` function again.
143149

150+
# import std::{str, vec};
151+
# mod crypto { fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out } }
152+
# fn as_hex(data: [u8]) -> str { "hi" }
153+
# fn x(data: str) -> str unsafe {
144154
let bytes = str::bytes(data);
145155
let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes),
146156
vec::len(bytes), std::ptr::null());
147157
ret as_hex(vec::unsafe::from_buf(hash, 20u));
158+
# }
148159

149160
The `str::bytes` function is perfectly safe, it converts a string to
150161
an `[u8]`. This byte array is then fed to `vec::unsafe::to_ptr`, which

doc/tutorial/func.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ This helps the compiler avoid spurious error messages. For example,
1919
the following code would be a type error if `dead_end` would be
2020
expected to return.
2121

22+
# fn can_go_left() -> bool { true }
23+
# fn can_go_right() -> bool { true }
24+
# tag dir { left; right; }
25+
# fn dead_end() -> ! { fail; }
2226
let dir = if can_go_left() { left }
2327
else if can_go_right() { right }
2428
else { dead_end(); };
@@ -96,12 +100,14 @@ of integers backwards:
96100

97101
To run such an iteration, you could do this:
98102

103+
# fn for_rev(v: [int], act: block(int)) {}
99104
for_rev([1, 2, 3], {|n| log n; });
100105

101106
But Rust allows a more pleasant syntax for this situation, with the
102107
loop block moved out of the parenthesis and the final semicolon
103108
omitted:
104109

110+
# fn for_rev(v: [int], act: block(int)) {}
105111
for_rev([1, 2, 3]) {|n|
106112
log n;
107113
}

doc/tutorial/generic.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,17 @@ dereferences become impossible.
5555
Rust's type inferrer works very well with generics, but there are
5656
programs that just can't be typed.
5757

58-
let n = none;
58+
let n = std::option::none;
59+
# n = std::option::some(1);
5960

6061
If you never do anything else with `n`, the compiler will not be able
6162
to assign a type to it. (The same goes for `[]`, in fact.) If you
6263
really want to have such a statement, you'll have to write it like
6364
this:
6465

65-
let n2: option::t<int> = none;
66+
let n2: std::option::t<int> = std::option::none;
6667
// or
67-
let n = none::<int>;
68+
let n = std::option::none::<int>;
6869

6970
Note that, in a value expression, `<` already has a meaning as a
7071
comparison operator, so you'll have to write `::<T>` to explicitly
@@ -120,6 +121,7 @@ take sendable types.
120121

121122
If you try this program:
122123

124+
# fn map(f: block(int) -> int, v: [int]) {}
123125
fn plus1(x: int) -> int { x + 1 }
124126
map(plus1, [1, 2, 3]);
125127

@@ -131,6 +133,7 @@ way to pass integers, which is by value. To get around this issue, you
131133
have to explicitly mark the arguments to a function that you want to
132134
pass to a generic higher-order function as being passed by pointer:
133135

136+
# fn map<T, U>(f: block(T) -> U, v: [T]) {}
134137
fn plus1(&&x: int) -> int { x + 1 }
135138
map(plus1, [1, 2, 3]);
136139

doc/tutorial/mod.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ It is also possible to include multiple files in a crate. For this
3535
purpose, you create a `.rc` crate file, which references any number of
3636
`.rs` code files. A crate file could look like this:
3737

38+
## ignore
3839
#[link(name = "farm", vers = "2.5", author = "mjh")];
3940
mod cow;
4041
mod chicken;
@@ -52,6 +53,7 @@ in a moment.
5253
To have a nested directory structure for your source files, you can
5354
nest mods in your `.rc` file:
5455

56+
## ignore
5557
mod poultry {
5658
mod chicken;
5759
mod turkey;
@@ -79,6 +81,7 @@ OS X.
7981
It is possible to provide more specific information when using an
8082
external crate.
8183

84+
## ignore
8285
use myfarm (name = "farm", vers = "2.7");
8386

8487
When a comma-separated list of name/value pairs is given after `use`,
@@ -90,6 +93,7 @@ local name `myfarm`.
9093

9194
Our example crate declared this set of `link` attributes:
9295

96+
## ignore
9397
#[link(name = "farm", vers = "2.5", author = "mjh")];
9498

9599
The version does not match the one provided in the `use` directive, so
@@ -105,12 +109,14 @@ these two files:
105109
#[link(name = "mylib", vers = "1.0")];
106110
fn world() -> str { "world" }
107111

112+
## ignore
108113
// main.rs
109114
use mylib;
110115
fn main() { log_err "hello " + mylib::world(); }
111116

112117
Now compile and run like this (adjust to your platform if necessary):
113118

119+
## notrust
114120
> rustc --lib mylib.rs
115121
> rustc main.rs -L .
116122
> ./main
@@ -147,8 +153,8 @@ restricted with `export` directives at the top of the module or file.
147153
mod enc {
148154
export encrypt, decrypt;
149155
const super_secret_number: int = 10;
150-
fn encrypt(n: int) { n + super_secret_number }
151-
fn decrypt(n: int) { n - super_secret_number }
156+
fn encrypt(n: int) -> int { n + super_secret_number }
157+
fn decrypt(n: int) -> int { n - super_secret_number }
152158
}
153159

154160
This defines a rock-solid encryption algorithm. Code outside of the

doc/tutorial/setup.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ If you modify the program to make it invalid (for example, remove the
2121
`use std` line), and then compile it, you'll see an error message like
2222
this:
2323

24+
## notrust
2425
hello.rs:2:4: 2:20 error: unresolved modulename: std
2526
hello.rs:2 std::io::println("hello world!");
2627
^~~~~~~~~~~~~~~~

doc/tutorial/syntax.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ statements and expressions is C-like. Function calls are written
2121
precedence that they have in C, comments look the same, and constructs
2222
like `if` and `while` are available:
2323

24+
# fn call_a_function(_a: int) {}
2425
fn main() {
2526
if 1 < 2 {
2627
while false { call_a_function(10 * 4); }
@@ -39,10 +40,13 @@ of languages. A lot of thing that are statements in C are expressions
3940
in Rust. This allows for useless things like this (which passes
4041
nil—the void type—to a function):
4142

43+
# fn a_function(_a: ()) {}
4244
a_function(while false {});
4345

4446
But also useful things like this:
4547

48+
# fn the_stars_align() -> bool { false }
49+
# fn something_else() -> bool { true }
4650
let x = if the_stars_align() { 4 }
4751
else if something_else() { 3 }
4852
else { 0 };
@@ -125,6 +129,7 @@ annotation:
125129

126130
// The type of this vector will be inferred based on its use.
127131
let x = [];
132+
# x = [3];
128133
// Explicitly say this is a vector of integers.
129134
let y: [int] = [];
130135

@@ -272,6 +277,7 @@ The comparison operators are the traditional `==`, `!=`, `<`, `>`,
272277

273278
Rust has a ternary conditional operator `?:`, as in:
274279

280+
let badness = 12;
275281
let message = badness < 10 ? "error" : "FATAL ERROR";
276282

277283
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
311317
`cfg` example above, or in this [crate](mod.html) metadata
312318
declaration:
313319

320+
## ignore
314321
#[link(name = "std",
315322
vers = "0.1",
316323
url = "http://rust-lang.org/src/std")];
317324

318325
An attribute without a semicolon following it applies to the
319326
definition that follows it. When terminated with a semicolon, it
320-
applies to the current context. The above example could also be
321-
written like this:
322-
323-
fn register_win_service() {
324-
#[cfg(target_os = "win32")];
325-
/* ... */
326-
}
327+
applies to the module or crate.
327328

328329
## Syntax extensions
329330

0 commit comments

Comments
 (0)