diff --git a/configure b/configure index 8cc6f02c7db..632768a5f86 100755 --- a/configure +++ b/configure @@ -505,6 +505,9 @@ do make_dir $h/test/perf make_dir $h/test/pretty make_dir $h/test/doc-tutorial + make_dir $h/test/doc-tutorial-ffi + make_dir $h/test/doc-tutorial-macros + make_dir $h/test/doc-tutorial-borrowed-ptr make_dir $h/test/doc-ref done diff --git a/doc/tutorial-borrowed-ptr.md b/doc/tutorial-borrowed-ptr.md index 34e3bfb1947..4c187ca622c 100644 --- a/doc/tutorial-borrowed-ptr.md +++ b/doc/tutorial-borrowed-ptr.md @@ -40,6 +40,7 @@ example, in this code, each of these three local variables contains a point, but allocated in a different place: ~~~ +# type point = {x: float, y: float}; let on_the_stack : point = {x: 3.0, y: 4.0}; let shared_box : @point = @{x: 5.0, y: 1.0}; let unique_box : ~point = ~{x: 7.0, y: 9.0}; @@ -58,6 +59,8 @@ define a function that takes the points by pointer. We can use borrowed pointers to do this: ~~~ +# type point = {x: float, y: float}; +# fn sqrt(f: float) -> float { 0f } fn compute_distance(p1: &point, p2: &point) -> float { let x_d = p1.x - p2.x; let y_d = p1.y - p2.y; @@ -67,7 +70,12 @@ fn compute_distance(p1: &point, p2: &point) -> float { Now we can call `compute_distance()` in various ways: -~~~ +~~~ {.xfail-test} +# type point = {x: float, y: float}; +# let on_the_stack : point = {x: 3.0, y: 4.0}; +# let shared_box : @point = @{x: 5.0, y: 1.0}; +# let unique_box : ~point = ~{x: 7.0, y: 9.0}; +# fn compute_distance(p1: &point, p2: &point) -> float { 0f } compute_distance(&on_the_stack, shared_box) compute_distance(shared_box, unique_box) ~~~ @@ -100,6 +108,7 @@ it again. In the previous example, the value `on_the_stack` was defined like so: ~~~ +# type point = {x: float, y: float}; let on_the_stack : point = {x: 3.0, y: 4.0}; ~~~ @@ -109,6 +118,7 @@ pointer. Sometimes however it is more convenient to move the & operator into the definition of `on_the_stack`: ~~~ +# type point = {x: float, y: float}; let on_the_stack2 : &point = &{x: 3.0, y: 4.0}; ~~~ @@ -116,6 +126,7 @@ Applying `&` to an rvalue (non-assignable location) is just a convenient shorthand for creating a temporary and taking its address: ~~~ +# type point = {x: float, y: float}; let tmp = {x: 3.0, y: 4.0}; let on_the_stack2 : &point = &tmp; ~~~ @@ -144,7 +155,14 @@ let rect_unique = ~{origin: {x: 5, y: 6}, size: {w: 3, h: 4}}; In each case I can use the `&` operator to extact out individual subcomponents. For example, I could write: -~~~ +~~~ {.xfail-test} +# type point = {x: float, y: float}; +# type size = {w: float, h: float}; // as before +# type rectangle = {origin: point, size: size}; +# let rect_stack = &{origin: {x: 1, y: 2}, size: {w: 3, h: 4}}; +# let rect_shared = @{origin: {x: 3, y: 4}, size: {w: 3, h: 4}}; +# let rect_unique = ~{origin: {x: 5, y: 6}, size: {w: 3, h: 4}}; +# fn compute_distance(p1: &point, p2: &point) -> float { 0f } compute_distance(&rect_stack.origin, &rect_shared.origin); ~~~ @@ -238,14 +256,16 @@ mean that the unique box is stored in immutable memory. For example, the following function is legal: ~~~ +# fn some_condition() -> bool { true } fn example3() -> int { let mut x = ~{f: 3}; - if some_condition { + if some_condition() { let y = &x.f; // -+ L - ret *y; // | + return *y; // | } // -+ x = ~{f: 4}; ... +# return 0; } ~~~ @@ -261,7 +281,7 @@ _as soon as their owning reference is changed or goes out of scope_. Therefore, a program like this is illegal (and would be rejected by the compiler): -~~~ +~~~ {.xfail-test} fn example3() -> int { let mut x = ~{f: 3}; let y = &x.f; @@ -308,7 +328,7 @@ frame_. So we could modify the previous example to introduce additional unique pointers and records, and the compiler will still be able to detect possible mutations: -~~~ +~~~ {.xfail-test} fn example3() -> int { let mut x = ~{mut f: ~{g: 3}}; let y = &x.f.g; @@ -326,8 +346,8 @@ Things get tricker when the unique box is not uniquely owned by the stack frame (or when the compiler doesn’t know who the owner is). Consider a program like this: -~~~ -fn example5a(x: @{mut f: ~{g: int}}, ...) -> int { +~~~ {.xfail-test} +fn example5a(x: @{mut f: ~{g: int}} ...) -> int { let y = &x.f.g; // Error reported here. ... } @@ -359,9 +379,10 @@ unique found in aliasable memory is to ensure that it is stored within unique fields, as in the following example: ~~~ -fn example5b(x: @{f: ~{g: int}}, ...) -> int { +fn example5b(x: @{f: ~{g: int}}) -> int { let y = &x.f.g; ... +# return 0; } ~~~ @@ -373,13 +394,15 @@ If you do have a unique box in a mutable field, and you wish to borrow it, one option is to use the swap operator to bring that unique box onto your stack: -~~~ -fn example5c(x: @{mut f: ~int}, ...) -> int { +~~~ {.xfail-test} +fn example5c(x: @{mut f: ~int}) -> int { let mut v = ~0; v <-> x.f; // Swap v and x.f let y = &v; ... x.f <- v; // Replace x.f + ... +# return 0; } ~~~ @@ -412,8 +435,15 @@ function takes a borrowed pointer to a shape to avoid the need of copying them. ~~~ +# type point = {x: float, y: float}; // as before +# type size = {w: float, h: float}; // as before +# enum shape { +# circle(point, float), // origin, radius +# rectangle(point, size) // upper-left, dimensions +# } +# const tau: float = 6.28f; fn compute_area(shape: &shape) -> float { - alt *shape { + match *shape { circle(_, radius) => 0.5 * tau * radius * radius, rectangle(_, ref size) => size.w * size.h } @@ -502,7 +532,7 @@ but as we’ll see this is more limited. For example, we could write a subroutine like this: -~~~ +~~~ {.xfail-test} type point = {x: float, y: float}; fn get_x(p: &point) -> &float { &p.x } ~~~ @@ -535,7 +565,7 @@ the compiler is satisfied with the function `get_x()`. To drill in this point, let’s look at a variation on the example, this time one which does not compile: -~~~ +~~~ {.xfail-test} type point = {x: float, y: float}; fn get_x_sh(p: @point) -> &float { &p.x // Error reported here @@ -574,7 +604,14 @@ pointer. However, sometimes if a function takes many parameters, it is useful to be able to group those parameters by lifetime. For example, consider this function: -~~~ +~~~ {.xfail-test} +# type point = {x: float, y: float}; // as before +# type size = {w: float, h: float}; // as before +# enum shape { +# circle(point, float), // origin, radius +# rectangle(point, size) // upper-left, dimensions +# } +# fn compute_area(shape: &shape) -> float { 0f } fn select(shape: &shape, threshold: float, a: &T, b: &T) -> &T { if compute_area(shape) > threshold {a} else {b} @@ -588,7 +625,19 @@ lifetime of the returned value will be the intersection of the lifetime of the three region parameters. This may be overloy conservative, as in this example: -~~~ +~~~ {.xfail-test} +# type point = {x: float, y: float}; // as before +# type size = {w: float, h: float}; // as before +# enum shape { +# circle(point, float), // origin, radius +# rectangle(point, size) // upper-left, dimensions +# } +# fn compute_area(shape: &shape) -> float { 0f } +# fn select(shape: &shape, threshold: float, +# a: &T, b: &T) -> &T { +# if compute_area(shape) > threshold {a} else {b} +# } + // -+ L fn select_based_on_unit_circle( // |-+ B threshold: float, a: &T, b: &T) -> &T { // | | @@ -618,7 +667,14 @@ second lifetime parameter for the function; named lifetime parameters do not need to be declared, you just use them. Here is how the new `select()` might look: -~~~ +~~~ {.xfail-test} +# type point = {x: float, y: float}; // as before +# type size = {w: float, h: float}; // as before +# enum shape { +# circle(point, float), // origin, radius +# rectangle(point, size) // upper-left, dimensions +# } +# fn compute_area(shape: &shape) -> float { 0f } fn select(shape: &tmp/shape, threshold: float, a: &T, b: &T) -> &T { if compute_area(shape) > threshold {a} else {b} @@ -632,7 +688,14 @@ lifetime parameter. You could also write `select()` using all named lifetime parameters, which might look like: -~~~ +~~~ {.xfail-test} +# type point = {x: float, y: float}; // as before +# type size = {w: float, h: float}; // as before +# enum shape { +# circle(point, float), // origin, radius +# rectangle(point, size) // upper-left, dimensions +# } +# fn compute_area(shape: &shape) -> float { 0f } fn select(shape: &tmp/shape, threshold: float, a: &r/T, b: &r/T) -> &r/T { if compute_area(shape) > threshold {a} else {b} @@ -658,7 +721,7 @@ a unique box found in an aliasable, mutable location, only now we’ve replaced the `...` with some specific code: ~~~ -fn example5a(x: @{mut f: ~{g: int}}, ...) -> int { +fn example5a(x: @{mut f: ~{g: int}} ...) -> int { let y = &x.f.g; // Unsafe *y + 1 } @@ -676,8 +739,9 @@ fn add_one(x: &int) -> int { *x + 1 } We can now update `example5a()` to use `add_one()`: -~~~ -fn example5a(x: @{mut f: ~{g: int}}, ...) -> int { +~~~ {.xfail-test} +# fn add_one(x: &int) -> int { *x + 1 } +fn example5a(x: @{mut f: ~{g: int}} ...) -> int { let y = &x.f.g; add_one(y) // Error reported here } diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index c9e0c1a4fc6..c51d12aff8d 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -28,9 +28,9 @@ fn as_hex(data: ~[u8]) -> ~str { fn sha1(data: ~str) -> ~str unsafe { let bytes = str::to_bytes(data); - let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes), + let hash = crypto::SHA1(vec::raw::to_ptr(bytes), vec::len(bytes) as c_uint, ptr::null()); - return as_hex(vec::unsafe::from_buf(hash, 20u)); + return as_hex(vec::raw::from_buf(hash, 20u)); } fn main(args: ~[~str]) { @@ -128,9 +128,9 @@ The `sha1` function is the most obscure part of the program. fn sha1(data: ~str) -> ~str { unsafe { let bytes = str::to_bytes(data); - let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes), + let hash = crypto::SHA1(vec::raw::to_ptr(bytes), vec::len(bytes), ptr::null()); - return as_hex(vec::unsafe::from_buf(hash, 20u)); + return as_hex(vec::raw::from_buf(hash, 20u)); } } ~~~~ @@ -171,15 +171,15 @@ Let's look at our `sha1` function again. # fn x(data: ~str) -> ~str { # unsafe { let bytes = str::to_bytes(data); -let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes), +let hash = crypto::SHA1(vec::raw::to_ptr(bytes), vec::len(bytes), ptr::null()); -return as_hex(vec::unsafe::from_buf(hash, 20u)); +return as_hex(vec::raw::from_buf(hash, 20u)); # } # } ~~~~ The `str::to_bytes` function is perfectly safe: it converts a string to -a `[u8]`. This byte array is then fed to `vec::unsafe::to_ptr`, which +a `[u8]`. This byte array is then fed to `vec::raw::to_ptr`, which returns an unsafe pointer to its contents. This pointer will become invalid as soon as the vector it points into @@ -193,7 +193,7 @@ unsafe null pointer of the correct type (Rust generics are awesome like that—they can take the right form depending on the type that they are expected to return). -Finally, `vec::unsafe::from_buf` builds up a new `[u8]` from the +Finally, `vec::raw::from_buf` builds up a new `[u8]` from the unsafe pointer that was returned by `SHA1`. SHA1 digests are always twenty bytes long, so we can pass `20u` for the length of the new vector. diff --git a/mk/tests.mk b/mk/tests.mk index 851c5b85d52..3b092833cad 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -164,6 +164,21 @@ doc-tutorial-extract$(1): $$(Q)rm -f $(1)/test/doc-tutorial/*.rs $$(Q)$$(EXTRACT_TESTS) $$(S)doc/tutorial.md $(1)/test/doc-tutorial +doc-tutorial-ffi-extract$(1): + @$$(call E, extract: tutorial-ffi tests) + $$(Q)rm -f $(1)/test/doc-tutorial-ffi/*.rs + $$(Q)$$(EXTRACT_TESTS) $$(S)doc/tutorial-ffi.md $(1)/test/doc-tutorial-ffi + +doc-tutorial-macros-extract$(1): + @$$(call E, extract: tutorial-macros tests) + $$(Q)rm -f $(1)/test/doc-tutorial-macros/*.rs + $$(Q)$$(EXTRACT_TESTS) $$(S)doc/tutorial-macros.md $(1)/test/doc-tutorial-macros + +doc-tutorial-borrowed-ptr-extract$(1): + @$$(call E, extract: tutorial-borrowed-ptr tests) + $$(Q)rm -f $(1)/test/doc-tutorial-borrowed-ptr/*.rs + $$(Q)$$(EXTRACT_TESTS) $$(S)doc/tutorial-borrowed-ptr.md $(1)/test/doc-tutorial-borrowed-ptr + doc-ref-extract$(1): @$$(call E, extract: ref tests) $$(Q)rm -f $(1)/test/doc-ref/*.rs @@ -211,6 +226,9 @@ check-stage$(1)-T-$(2)-H-$(3): \ check-stage$(1)-T-$(2)-H-$(3)-rustdoc \ check-stage$(1)-T-$(2)-H-$(3)-cargo \ check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial \ + check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-ffi \ + check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-macros \ + check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr \ check-stage$(1)-T-$(2)-H-$(3)-doc-ref check-stage$(1)-T-$(2)-H-$(3)-core: \ @@ -271,6 +289,15 @@ check-stage$(1)-T-$(2)-H-$(3)-cargo: \ check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial: \ check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-dummy +check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-ffi: \ + check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-ffi-dummy + +check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-macros: \ + check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-macros-dummy + +check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr: \ + check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr-dummy + check-stage$(1)-T-$(2)-H-$(3)-doc-ref: \ check-stage$(1)-T-$(2)-H-$(3)-doc-ref-dummy @@ -440,6 +467,24 @@ DOC_TUTORIAL_ARGS$(1)-T-$(2)-H-$(3) := \ --build-base $(3)/test/doc-tutorial/ \ --mode run-pass +DOC_TUTORIAL_FFI_ARGS$(1)-T-$(2)-H-$(3) := \ + $$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \ + --src-base $(3)/test/doc-tutorial-ffi/ \ + --build-base $(3)/test/doc-tutorial-ffi/ \ + --mode run-pass + +DOC_TUTORIAL_MACROS_ARGS$(1)-T-$(2)-H-$(3) := \ + $$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \ + --src-base $(3)/test/doc-tutorial-macros/ \ + --build-base $(3)/test/doc-tutorial-macros/ \ + --mode run-pass + +DOC_TUTORIAL_BORROWED_PTR_ARGS$(1)-T-$(2)-H-$(3) := \ + $$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \ + --src-base $(3)/test/doc-tutorial-borrowed-ptr/ \ + --build-base $(3)/test/doc-tutorial-borrowed-ptr/ \ + --mode run-pass + DOC_REF_ARGS$(1)-T-$(2)-H-$(3) := \ $$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \ --src-base $(3)/test/doc-ref/ \ @@ -542,6 +587,30 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-dummy: \ $$(DOC_TUTORIAL_ARGS$(1)-T-$(2)-H-$(3)) \ --logfile tmp/check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial.log +check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-ffi-dummy: \ + $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ + doc-tutorial-ffi-extract$(3) + @$$(call E, run doc-tutorial-ffi: $$<) + $$(Q)$$(call CFG_RUN_CTEST,$(1),$$<,$(3)) \ + $$(DOC_TUTORIAL_FFI_ARGS$(1)-T-$(2)-H-$(3)) \ + --logfile tmp/check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-ffi.log + +check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-macros-dummy: \ + $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ + doc-tutorial-macros-extract$(3) + @$$(call E, run doc-tutorial-macros: $$<) + $$(Q)$$(call CFG_RUN_CTEST,$(1),$$<,$(3)) \ + $$(DOC_TUTORIAL_MACROS_ARGS$(1)-T-$(2)-H-$(3)) \ + --logfile tmp/check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-macros.log + +check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr-dummy: \ + $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ + doc-tutorial-borrowed-ptr-extract$(3) + @$$(call E, run doc-tutorial-borrowed-ptr: $$<) + $$(Q)$$(call CFG_RUN_CTEST,$(1),$$<,$(3)) \ + $$(DOC_TUTORIAL_BORROWED_PTR_ARGS$(1)-T-$(2)-H-$(3)) \ + --logfile tmp/check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr.log + check-stage$(1)-T-$(2)-H-$(3)-doc-ref-dummy: \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ doc-ref-extract$(3) @@ -670,6 +739,15 @@ check-stage$(1)-H-$(2)-cargo: \ check-stage$(1)-H-$(2)-doc-tutorial: \ $$(foreach target,$$(CFG_TARGET_TRIPLES), \ check-stage$(1)-T-$$(target)-H-$(2)-doc-tutorial) +check-stage$(1)-H-$(2)-doc-tutorial-ffi: \ + $$(foreach target,$$(CFG_TARGET_TRIPLES), \ + check-stage$(1)-T-$$(target)-H-$(2)-doc-tutorial-ffi) +check-stage$(1)-H-$(2)-doc-tutorial-macros: \ + $$(foreach target,$$(CFG_TARGET_TRIPLES), \ + check-stage$(1)-T-$$(target)-H-$(2)-doc-tutorial-macros) +check-stage$(1)-H-$(2)-doc-tutorial-borrowed-ptr: \ + $$(foreach target,$$(CFG_TARGET_TRIPLES), \ + check-stage$(1)-T-$$(target)-H-$(2)-doc-tutorial-borrowed-ptr) check-stage$(1)-H-$(2)-doc-ref: \ $$(foreach target,$$(CFG_TARGET_TRIPLES), \ check-stage$(1)-T-$$(target)-H-$(2)-doc-ref) @@ -778,6 +856,9 @@ check-stage$(1)-pretty-pretty: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-pretty-pret check-stage$(1)-rustdoc: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-rustdoc check-stage$(1)-cargo: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-cargo check-stage$(1)-doc-tutorial: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial +check-stage$(1)-doc-tutorial-ffi: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-ffi +check-stage$(1)-doc-tutorial-macros: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-macros +check-stage$(1)-doc-tutorial-borrowed-ptr: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-borrowed-ptr check-stage$(1)-doc-ref: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-ref endef diff --git a/src/etc/extract-tests.py b/src/etc/extract-tests.py index 0e8792c244b..9308bf6d5ee 100644 --- a/src/etc/extract-tests.py +++ b/src/etc/extract-tests.py @@ -47,7 +47,11 @@ while cur < len(lines): if re.match("~~~", line): break else: - block += re.sub("^# ", "", line) + # Lines beginning with '# ' are turned into valid code + line = re.sub("^# ", "", line) + # Allow elipses in code snippets + line = re.sub("\.\.\.", "/*...*/", line) + block += line if not ignore: if not re.search(r"\bfn main\b", block): block = "fn main() {\n" + block + "\n}\n"