Added all files
Getty Ritter
11 years ago
| 1 | Rust Examples | |
| 2 | ============= | |
| 3 | ||
| 4 | These are small snippets of the Rust, in varying degrees of elaborateness, | |
| 5 | meant to accompany the presentation given in `presentation/rust.pdf`. I am not | |
| 6 | a particularly experienced Rust programmer, so these programs may differ | |
| 7 | significantly from conventional Rust style or idiom, or may be written in | |
| 8 | a suboptimal way. | |
| 9 | ||
| 10 | Right now, the examples include: | |
| 11 | ||
| 12 | - An interpreter for the untyped lambda-calculus | |
| 13 | - A regular-expression matcher | |
| 14 | ||
| 15 | Build System | |
| 16 | ------------ | |
| 17 | ||
| 18 | These programs are built using [`redo`](https://github.com/apenwarr/redo), | |
| 19 | which is my preferred build system for small projects. I understand that not | |
| 20 | everyone has `redo`, so I've included `do`, which is a small shell | |
| 21 | implementation of `redo` that rebuilds everything rather than doing clever | |
| 22 | dependency-tracking like `redo` proper. You can build any of these projects with | |
| 23 | ||
| 24 | $ cd project-dir | |
| 25 | $ ../do | |
| 26 | ||
| 27 | and clean any of them with | |
| 28 | ||
| 29 | $ cd project-dir | |
| 30 | $ ../do clean | |
| 31 | ||
| 32 | The only project that really _needs_ a build script is the presentation, | |
| 33 | which gets built with [`pandoc`](http://johnmacfarlane.net/pandoc/) and | |
| 34 | then compiled with `xelatex`, but each one has a build script in case | |
| 35 | you want to poke at the commands used to build the projects. |
| 1 | #!/bin/sh | |
| 2 | # | |
| 3 | # A minimal alternative to djb redo that doesn't support incremental builds. | |
| 4 | # For the full version, visit http://github.com/apenwarr/redo | |
| 5 | # | |
| 6 | # The author disclaims copyright to this source file and hereby places it in | |
| 7 | # the public domain. (2010 12 14) | |
| 8 | # | |
| 9 | ||
| 10 | # By default, no output coloring. | |
| 11 | green="" | |
| 12 | bold="" | |
| 13 | plain="" | |
| 14 | ||
| 15 | if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then | |
| 16 | green="$(printf '\033[32m')" | |
| 17 | bold="$(printf '\033[1m')" | |
| 18 | plain="$(printf '\033[m')" | |
| 19 | fi | |
| 20 | ||
| 21 | _dirsplit() | |
| 22 | { | |
| 23 | base=${1##*/} | |
| 24 | dir=${1%$base} | |
| 25 | } | |
| 26 | ||
| 27 | dirname() | |
| 28 | ( | |
| 29 | _dirsplit "$1" | |
| 30 | dir=${dir%/} | |
| 31 | echo "${dir:-.}" | |
| 32 | ) | |
| 33 | ||
| 34 | _dirsplit "$0" | |
| 35 | export REDO=$(cd "${dir:-.}" && echo "$PWD/$base") | |
| 36 | ||
| 37 | DO_TOP= | |
| 38 | if [ -z "$DO_BUILT" ]; then | |
| 39 | DO_TOP=1 | |
| 40 | [ -n "$*" ] || set all # only toplevel redo has a default target | |
| 41 | export DO_BUILT=$PWD/.do_built | |
| 42 | : >>"$DO_BUILT" | |
| 43 | echo "Removing previously built files..." >&2 | |
| 44 | sort -u "$DO_BUILT" | tee "$DO_BUILT.new" | | |
| 45 | while read f; do printf "%s\0%s.did\0" "$f" "$f"; done | | |
| 46 | xargs -0 rm -f 2>/dev/null | |
| 47 | mv "$DO_BUILT.new" "$DO_BUILT" | |
| 48 | DO_PATH=$DO_BUILT.dir | |
| 49 | export PATH=$DO_PATH:$PATH | |
| 50 | rm -rf "$DO_PATH" | |
| 51 | mkdir "$DO_PATH" | |
| 52 | for d in redo redo-ifchange; do | |
| 53 | ln -s "$REDO" "$DO_PATH/$d"; | |
| 54 | done | |
| 55 | [ -e /bin/true ] && TRUE=/bin/true || TRUE=/usr/bin/true | |
| 56 | for d in redo-ifcreate redo-stamp redo-always; do | |
| 57 | ln -s $TRUE "$DO_PATH/$d"; | |
| 58 | done | |
| 59 | fi | |
| 60 | ||
| 61 | ||
| 62 | _find_dofile_pwd() | |
| 63 | { | |
| 64 | dofile=default.$1.do | |
| 65 | while :; do | |
| 66 | dofile=default.${dofile#default.*.} | |
| 67 | [ -e "$dofile" -o "$dofile" = default.do ] && break | |
| 68 | done | |
| 69 | ext=${dofile#default} | |
| 70 | ext=${ext%.do} | |
| 71 | base=${1%$ext} | |
| 72 | } | |
| 73 | ||
| 74 | ||
| 75 | _find_dofile() | |
| 76 | { | |
| 77 | local prefix= | |
| 78 | while :; do | |
| 79 | _find_dofile_pwd "$1" | |
| 80 | [ -e "$dofile" ] && break | |
| 81 | [ "$PWD" = "/" ] && break | |
| 82 | target=${PWD##*/}/$target | |
| 83 | tmp=${PWD##*/}/$tmp | |
| 84 | prefix=${PWD##*/}/$prefix | |
| 85 | cd .. | |
| 86 | done | |
| 87 | base=$prefix$base | |
| 88 | } | |
| 89 | ||
| 90 | ||
| 91 | _run_dofile() | |
| 92 | { | |
| 93 | export DO_DEPTH="$DO_DEPTH " | |
| 94 | export REDO_TARGET=$PWD/$target | |
| 95 | local line1 | |
| 96 | set -e | |
| 97 | read line1 <"$PWD/$dofile" || true | |
| 98 | cmd=${line1#"#!/"} | |
| 99 | if [ "$cmd" != "$line1" ]; then | |
| 100 | /$cmd "$PWD/$dofile" "$@" >"$tmp.tmp2" | |
| 101 | else | |
| 102 | :; . "$PWD/$dofile" >"$tmp.tmp2" | |
| 103 | fi | |
| 104 | } | |
| 105 | ||
| 106 | ||
| 107 | _do() | |
| 108 | { | |
| 109 | local dir=$1 target=$2 tmp=$3 | |
| 110 | if [ ! -e "$target" ] || [ -d "$target" -a ! -e "$target.did" ]; then | |
| 111 | printf '%sdo %s%s%s%s\n' \ | |
| 112 | "$green" "$DO_DEPTH" "$bold" "$dir$target" "$plain" >&2 | |
| 113 | echo "$PWD/$target" >>"$DO_BUILT" | |
| 114 | dofile=$target.do | |
| 115 | base=$target | |
| 116 | ext= | |
| 117 | [ -e "$target.do" ] || _find_dofile "$target" | |
| 118 | if [ ! -e "$dofile" ]; then | |
| 119 | echo "do: $target: no .do file" >&2 | |
| 120 | return 1 | |
| 121 | fi | |
| 122 | [ ! -e "$DO_BUILT" ] || [ ! -d "$(dirname "$target")" ] || | |
| 123 | : >>"$target.did" | |
| 124 | ( _run_dofile "$target" "$base" "$tmp.tmp" ) | |
| 125 | rv=$? | |
| 126 | if [ $rv != 0 ]; then | |
| 127 | printf "do: %s%s\n" "$DO_DEPTH" \ | |
| 128 | "$dir$target: got exit code $rv" >&2 | |
| 129 | rm -f "$tmp.tmp" "$tmp.tmp2" | |
| 130 | return $rv | |
| 131 | fi | |
| 132 | mv "$tmp.tmp" "$target" 2>/dev/null || | |
| 133 | ! test -s "$tmp.tmp2" || | |
| 134 | mv "$tmp.tmp2" "$target" 2>/dev/null | |
| 135 | rm -f "$tmp.tmp2" | |
| 136 | else | |
| 137 | echo "do $DO_DEPTH$target exists." >&2 | |
| 138 | fi | |
| 139 | } | |
| 140 | ||
| 141 | ||
| 142 | # Make corrections for directories that don't actually exist yet. | |
| 143 | _dir_shovel() | |
| 144 | { | |
| 145 | local dir base | |
| 146 | xdir=$1 xbase=$2 xbasetmp=$2 | |
| 147 | while [ ! -d "$xdir" -a -n "$xdir" ]; do | |
| 148 | _dirsplit "${xdir%/}" | |
| 149 | xbasetmp=${base}__$xbase | |
| 150 | xdir=$dir xbase=$base/$xbase | |
| 151 | echo "xbasetmp='$xbasetmp'" >&2 | |
| 152 | done | |
| 153 | } | |
| 154 | ||
| 155 | ||
| 156 | _redo() | |
| 157 | { | |
| 158 | set +e | |
| 159 | for i in "$@"; do | |
| 160 | _dirsplit "$i" | |
| 161 | _dir_shovel "$dir" "$base" | |
| 162 | dir=$xdir base=$xbase basetmp=$xbasetmp | |
| 163 | ( cd "$dir" && _do "$dir" "$base" "$basetmp" ) | |
| 164 | [ "$?" = 0 ] || return 1 | |
| 165 | done | |
| 166 | } | |
| 167 | ||
| 168 | ||
| 169 | _redo "$@" | |
| 170 | [ "$?" = 0 ] || exit 1 | |
| 171 | ||
| 172 | if [ -n "$DO_TOP" ]; then | |
| 173 | echo "Removing stamp files..." >&2 | |
| 174 | [ ! -e "$DO_BUILT" ] || | |
| 175 | while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" | | |
| 176 | xargs -0 rm -f 2>/dev/null | |
| 177 | fi |
| 1 | if [ -e lcalc ]; then rm lcalc; fi |
| 1 | redo-ifchange lcalc |
| 1 | use std::str::eq_slice; | |
| 2 | ||
| 3 | #[deriving(Eq,Clone)] | |
| 4 | enum Term { | |
| 5 | Num(int), | |
| 6 | Var(~str), | |
| 7 | Lam(~str, ~Term), | |
| 8 | App(~Term, ~Term), | |
| 9 | Let(~str, ~Term, ~Term), | |
| 10 | } | |
| 11 | ||
| 12 | #[deriving(Eq,Clone)] | |
| 13 | enum Val { | |
| 14 | VNum(int), | |
| 15 | VLam(~str, ~Term, ~Env), | |
| 16 | } | |
| 17 | ||
| 18 | #[deriving(Eq,Clone)] | |
| 19 | enum Env { | |
| 20 | Empty, | |
| 21 | Binding(~str, ~Val, ~Env), | |
| 22 | } | |
| 23 | ||
| 24 | fn lookup(s: &str, e: &Env) -> ~Val { | |
| 25 | match *e { | |
| 26 | Empty => { fail!(format!("Couldn't find {} in environment", s)) } | |
| 27 | Binding(ref n, ref v, ref p) => { | |
| 28 | if eq_slice(*n, s) { | |
| 29 | v.clone() | |
| 30 | } else { | |
| 31 | lookup(s, *p) | |
| 32 | } | |
| 33 | } | |
| 34 | } | |
| 35 | } | |
| 36 | ||
| 37 | fn eval(t: &Term, e: &Env) -> ~Val { | |
| 38 | match t { | |
| 39 | &Num(num) => { ~VNum(num) } | |
| 40 | &Var(ref str) => { lookup(*str, e) } | |
| 41 | &Lam(ref s, ref b) => { ~VLam(s.clone(), b.clone(), ~e.clone()) } | |
| 42 | &App(ref f, ref x) => { | |
| 43 | match (*eval(*f, e)) { | |
| 44 | VLam(ref arg, ref body, ref env) => { | |
| 45 | let newEnv = Binding(arg.clone(), | |
| 46 | eval(*x, e), | |
| 47 | env.clone()); | |
| 48 | eval(*body, &newEnv) | |
| 49 | } | |
| 50 | _ => fail!() | |
| 51 | } | |
| 52 | } | |
| 53 | &Let(ref s, ref t, ref b) => { | |
| 54 | let newEnv = Binding(s.clone(), | |
| 55 | eval(*t, e), | |
| 56 | ~e.clone()); | |
| 57 | eval(*b, &newEnv) | |
| 58 | } | |
| 59 | } | |
| 60 | } | |
| 61 | ||
| 62 | fn main() { | |
| 63 | // (λx.λy.x)(5)(6) | |
| 64 | let s1 = ~App(~App(~Lam(~"x",~Lam(~"y", ~Var(~"x"))),~Num(5)),~Num(8)); | |
| 65 | // let f = (λx.λy.x)(2) in f 4 | |
| 66 | let s2 = ~Let( ~"f", | |
| 67 | ~App(~Lam(~"x",~Lam(~"y", ~Var(~"x"))),~Num(2)), | |
| 68 | ~App(~Var(~"f"),~Num(4)) | |
| 69 | ); | |
| 70 | let e = Empty; | |
| 71 | println!("s1: {:?}", eval(s1, &e)); | |
| 72 | println!("s2: {:?}", eval(s2, &e)); | |
| 73 | } |
| 1 | redo-ifchange rust.pdf |
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
| 1 | <?xml version="1.0" encoding="ISO-8859-1"?> | |
| 2 | <!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |
| 3 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |
| 4 | <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="144px" height="144px" viewBox="19 19 106 106" style="enable-background:new 0 0 144 144;" xml:space="preserve"> | |
| 5 | <path d="M122.631,69.716l-4.394-2.72c-0.037-0.428-0.079-0.855-0.125-1.28l3.776-3.522c0.384-0.358,0.556-0.888,0.452-1.401 c-0.101-0.515-0.462-0.939-0.953-1.122l-4.827-1.805c-0.121-0.418-0.248-0.833-0.378-1.246l3.011-4.182 c0.307-0.425,0.37-0.978,0.17-1.463c-0.2-0.483-0.637-0.829-1.154-0.914l-5.09-0.828c-0.198-0.386-0.404-0.766-0.612-1.143 l2.139-4.695c0.219-0.478,0.174-1.034-0.118-1.468c-0.291-0.436-0.784-0.691-1.31-0.671l-5.166,0.18 c-0.267-0.334-0.539-0.665-0.816-0.99l1.187-5.032c0.12-0.511-0.031-1.046-0.403-1.417c-0.369-0.37-0.905-0.523-1.416-0.403 l-5.031,1.186c-0.326-0.276-0.657-0.549-0.992-0.816l0.181-5.166c0.02-0.523-0.235-1.02-0.671-1.31 c-0.437-0.292-0.99-0.336-1.467-0.119l-4.694,2.14c-0.379-0.208-0.759-0.414-1.143-0.613l-0.83-5.091 c-0.084-0.516-0.43-0.954-0.914-1.154c-0.483-0.201-1.037-0.136-1.462,0.17l-4.185,3.011c-0.412-0.131-0.826-0.257-1.244-0.377 l-1.805-4.828c-0.183-0.492-0.607-0.853-1.122-0.955c-0.514-0.101-1.043,0.07-1.4,0.452l-3.522,3.779 c-0.425-0.047-0.853-0.09-1.28-0.125l-2.72-4.395c-0.275-0.445-0.762-0.716-1.286-0.716s-1.011,0.271-1.285,0.716l-2.72,4.395 c-0.428,0.035-0.856,0.078-1.281,0.125l-3.523-3.779c-0.357-0.382-0.887-0.553-1.4-0.452c-0.515,0.103-0.939,0.463-1.122,0.955 l-1.805,4.828c-0.418,0.12-0.832,0.247-1.245,0.377l-4.184-3.011c-0.425-0.307-0.979-0.372-1.463-0.17 c-0.483,0.2-0.83,0.638-0.914,1.154l-0.83,5.091c-0.384,0.199-0.764,0.404-1.143,0.613l-4.694-2.14 c-0.477-0.218-1.033-0.173-1.467,0.119c-0.436,0.29-0.691,0.787-0.671,1.31l0.18,5.166c-0.334,0.267-0.665,0.54-0.992,0.816 l-5.031-1.186c-0.511-0.119-1.047,0.033-1.417,0.403c-0.372,0.371-0.523,0.906-0.403,1.417l1.185,5.032 c-0.275,0.326-0.547,0.656-0.814,0.99l-5.166-0.18c-0.521-0.015-1.019,0.235-1.31,0.671c-0.292,0.434-0.336,0.99-0.119,1.468 l2.14,4.695c-0.208,0.377-0.414,0.757-0.613,1.143l-5.09,0.828c-0.517,0.084-0.953,0.43-1.154,0.914 c-0.2,0.485-0.135,1.038,0.17,1.463l3.011,4.182c-0.131,0.413-0.258,0.828-0.378,1.246l-4.828,1.805 c-0.49,0.183-0.851,0.607-0.953,1.122c-0.102,0.514,0.069,1.043,0.452,1.401l3.777,3.522c-0.047,0.425-0.089,0.853-0.125,1.28 l-4.394,2.72c-0.445,0.275-0.716,0.761-0.716,1.286s0.271,1.011,0.716,1.285l4.394,2.72c0.036,0.428,0.078,0.855,0.125,1.28 l-3.777,3.523c-0.383,0.357-0.554,0.887-0.452,1.4c0.102,0.515,0.463,0.938,0.953,1.122l4.828,1.805 c0.12,0.418,0.247,0.833,0.378,1.246l-3.011,4.183c-0.306,0.426-0.371,0.979-0.17,1.462c0.201,0.485,0.638,0.831,1.155,0.914 l5.089,0.828c0.199,0.386,0.403,0.766,0.613,1.145l-2.14,4.693c-0.218,0.477-0.173,1.032,0.119,1.468 c0.292,0.437,0.789,0.692,1.31,0.671l5.164-0.181c0.269,0.336,0.54,0.665,0.816,0.992l-1.185,5.033 c-0.12,0.51,0.031,1.043,0.403,1.414c0.369,0.373,0.906,0.522,1.417,0.402l5.031-1.185c0.327,0.278,0.658,0.548,0.992,0.814 l-0.18,5.167c-0.02,0.523,0.235,1.019,0.671,1.311c0.434,0.291,0.99,0.335,1.467,0.117l4.694-2.139 c0.378,0.21,0.758,0.414,1.143,0.613l0.83,5.088c0.084,0.518,0.43,0.956,0.914,1.155c0.483,0.201,1.038,0.136,1.463-0.169 l4.182-3.013c0.413,0.131,0.828,0.259,1.246,0.379l1.805,4.826c0.183,0.49,0.607,0.853,1.122,0.953 c0.514,0.104,1.043-0.068,1.4-0.452l3.523-3.777c0.425,0.049,0.853,0.09,1.281,0.128l2.72,4.394 c0.274,0.443,0.761,0.716,1.285,0.716s1.011-0.272,1.286-0.716l2.72-4.394c0.428-0.038,0.855-0.079,1.28-0.128l3.522,3.777 c0.357,0.384,0.887,0.556,1.4,0.452c0.515-0.101,0.939-0.463,1.122-0.953l1.805-4.826c0.418-0.12,0.833-0.248,1.246-0.379 l4.183,3.013c0.425,0.305,0.979,0.37,1.462,0.169c0.484-0.199,0.83-0.638,0.914-1.155l0.83-5.088 c0.384-0.199,0.764-0.406,1.143-0.613l4.694,2.139c0.477,0.218,1.032,0.174,1.467-0.117c0.436-0.292,0.69-0.787,0.671-1.311 l-0.18-5.167c0.334-0.267,0.665-0.536,0.991-0.814l5.031,1.185c0.511,0.12,1.047-0.029,1.416-0.402 c0.372-0.371,0.523-0.904,0.403-1.414l-1.185-5.033c0.276-0.327,0.548-0.656,0.814-0.992l5.166,0.181 c0.521,0.021,1.019-0.234,1.31-0.671c0.292-0.436,0.337-0.991,0.118-1.468l-2.139-4.693c0.209-0.379,0.414-0.759,0.612-1.145 l5.09-0.828c0.518-0.083,0.954-0.429,1.154-0.914c0.2-0.483,0.137-1.036-0.17-1.462l-3.011-4.183 c0.13-0.413,0.257-0.828,0.378-1.246l4.827-1.805c0.491-0.184,0.853-0.607,0.953-1.122c0.104-0.514-0.068-1.043-0.452-1.4 l-3.776-3.523c0.046-0.425,0.088-0.853,0.125-1.28l4.394-2.72c0.445-0.274,0.716-0.761,0.716-1.285S123.076,69.991,122.631,69.716z M93.222,106.167c-1.678-0.362-2.745-2.016-2.385-3.699c0.359-1.681,2.012-2.751,3.689-2.389c1.678,0.359,2.747,2.016,2.387,3.696 S94.899,106.526,93.222,106.167z M91.729,96.069c-1.531-0.328-3.037,0.646-3.365,2.18l-1.56,7.28 c-4.814,2.185-10.16,3.399-15.79,3.399c-5.759,0-11.221-1.274-16.121-3.552l-1.559-7.28c-0.328-1.532-1.834-2.508-3.364-2.179 l-6.427,1.38c-1.193-1.228-2.303-2.536-3.323-3.917h31.272c0.354,0,0.59-0.064,0.59-0.386V81.932c0-0.322-0.236-0.386-0.59-0.386 h-9.146v-7.012h9.892c0.903,0,4.828,0.258,6.083,5.275c0.393,1.543,1.256,6.562,1.846,8.169c0.588,1.802,2.982,5.402,5.533,5.402 h15.583c0.177,0,0.366-0.02,0.565-0.056c-1.081,1.469-2.267,2.859-3.544,4.158L91.729,96.069z M48.477,106.015 c-1.678,0.362-3.33-0.708-3.691-2.389c-0.359-1.684,0.708-3.337,2.386-3.699c1.678-0.359,3.331,0.711,3.691,2.392 C51.222,103.999,50.154,105.655,48.477,106.015z M36.614,57.91c0.696,1.571-0.012,3.412-1.581,4.107 c-1.569,0.697-3.405-0.012-4.101-1.584c-0.696-1.572,0.012-3.41,1.581-4.107C34.083,55.63,35.918,56.338,36.614,57.91z M32.968,66.553l6.695-2.975c1.43-0.635,2.076-2.311,1.441-3.744l-1.379-3.118h5.423V81.16H34.207 c-0.949-3.336-1.458-6.857-1.458-10.496C32.749,69.275,32.824,67.902,32.968,66.553z M62.348,64.179v-7.205h12.914 c0.667,0,4.71,0.771,4.71,3.794c0,2.51-3.101,3.41-5.651,3.41H62.348z M109.28,70.664c0,0.956-0.035,1.902-0.105,2.841h-3.926 c-0.393,0-0.551,0.258-0.551,0.643v1.803c0,4.244-2.393,5.167-4.49,5.402c-1.997,0.225-4.211-0.836-4.484-2.058 c-1.178-6.626-3.141-8.041-6.241-10.486c3.847-2.443,7.85-6.047,7.85-10.871c0-5.209-3.571-8.49-6.005-10.099 c-3.415-2.251-7.196-2.702-8.216-2.702H42.509c5.506-6.145,12.968-10.498,21.408-12.082l4.786,5.021 c1.082,1.133,2.874,1.175,4.006,0.092l5.355-5.122c11.221,2.089,20.721,9.074,26.196,18.657l-3.666,8.28 c-0.633,1.433,0.013,3.109,1.442,3.744l7.058,3.135C109.216,68.115,109.28,69.381,109.28,70.664z M68.705,28.784 c1.24-1.188,3.207-1.141,4.394,0.101c1.185,1.245,1.14,3.214-0.103,4.401c-1.24,1.188-3.207,1.142-4.394-0.102 C67.418,31.941,67.463,29.972,68.705,28.784z M105.085,58.061c0.695-1.571,2.531-2.28,4.1-1.583 c1.569,0.696,2.277,2.536,1.581,4.107c-0.695,1.572-2.531,2.281-4.101,1.584C105.098,61.473,104.39,59.634,105.085,58.061z"/> | |
| 6 | </svg>⏎ |
| 1 | % The Rust Programming Language | |
| 2 | % G.D. Ritter | |
| 3 | % March 2014 | |
| 4 | ||
| 5 | # The Rust Programming Language | |
| 6 | ||
| 7 |  | |
| 8 | ||
| 9 | A new systems programming language being developed by Mozilla Research, with | |
| 10 | an emphasis on correctness while still allowing for very low-level programing | |
| 11 | by emphasizing _zero-cost abstractions_. | |
| 12 | ||
| 13 | # Low-Level Programming | |
| 14 | ||
| 15 | # Low-Level Programming | |
| 16 | ||
| 17 | \begin{center} | |
| 18 | \includegraphics[width=.9\textwidth]{imgs/kanye-water-bottle-01.png} | |
| 19 | \end{center} | |
| 20 | ||
| 21 | # Low-Level Programming | |
| 22 | ||
| 23 | \begin{center} | |
| 24 | \includegraphics[width=.9\textwidth]{imgs/kanye-water-bottle-02.png} | |
| 25 | \end{center} | |
| 26 | ||
| 27 | # Systems Programming Languages | |
| 28 | ||
| 29 | > System software is computer software designed to operate and control the | |
| 30 | > computer hardware and to provide a platform for running application | |
| 31 | > software, and includes such things as operating systems, utility software, | |
| 32 | > device drivers, compilers, and linkers. | |
| 33 | > | |
| 34 | > —Wikipedia | |
| 35 | ||
| 36 | > "Systems programs" means "programs where the constant factors are important". | |
| 37 | > | |
| 38 | > —Comment by `neelk` on Lambda the Ultimate | |
| 39 | ||
| 40 | # Systems Programming Languages | |
| 41 | ||
| 42 | ## Example Program | |
| 43 | ||
| 44 | ~~~~{.haskell} | |
| 45 | data Point = { x, y : Int } | |
| 46 | ||
| 47 | addPoint : Point -> Point -> Point | |
| 48 | addPoint p1 p2 = { x = p1.x + p2.x, y = p1.y + p2.y } | |
| 49 | ||
| 50 | main : () | |
| 51 | main = { let a = { x = 1, y = 2 } | |
| 52 | ; let b = malloc { x = 4, y = 3} | |
| 53 | ; print (addPoint a (deref b)) | |
| 54 | ; free(b) | |
| 55 | } | |
| 56 | ~~~~ | |
| 57 | ||
| 58 | # Systems Programming Languages | |
| 59 | ||
| 60 | ## C | |
| 61 | ||
| 62 | ~~~~{.c} | |
| 63 | typedef struct { int x, y; } point; | |
| 64 | ||
| 65 | point add(point a, point b) { | |
| 66 | point result = { a.x + b.x, a.y + b.y }; | |
| 67 | return result; | |
| 68 | } | |
| 69 | ||
| 70 | void main(int argc, char* argv[]) { | |
| 71 | point a = { 1, 2 }; | |
| 72 | point* b = malloc(sizeof(point)); | |
| 73 | b->x = 4; b->y = 3; | |
| 74 | point c = add(a, *b); | |
| 75 | printf("{.x = %d, .y = %d}\n", c.x, c.y); | |
| 76 | free(b); | |
| 77 | } | |
| 78 | ~~~~ | |
| 79 | ||
| 80 | # Systems Programming Languages | |
| 81 | ||
| 82 | ## C++ | |
| 83 | ||
| 84 | ~~~~{.cpp} | |
| 85 | struct point { | |
| 86 | int x, y; | |
| 87 | point(int _x, int _y) { x = _x; y = _y; } | |
| 88 | point add(point other) { | |
| 89 | return point(x + other.x, y + other.y); | |
| 90 | } | |
| 91 | }; | |
| 92 | int main(int argc, char* argv[]) { | |
| 93 | point a(1, 2); | |
| 94 | point* b = new point(4, 3); | |
| 95 | point c = a.add(*b); | |
| 96 | std::cout << "{ .x = " << c.x; | |
| 97 | std::cout << ", .y = " << c.y << " }" << std::endl; | |
| 98 | delete b; | |
| 99 | } | |
| 100 | ~~~~ | |
| 101 | ||
| 102 | # Systems Programming Languages | |
| 103 | ||
| 104 | ## Go | |
| 105 | ||
| 106 | ~~~~{.go} | |
| 107 | type Point struct { X, Y int } | |
| 108 | ||
| 109 | func (a Point) add(b Point) Point { | |
| 110 | return Point{ a.X + b.X, a.Y + b.Y } | |
| 111 | } | |
| 112 | ||
| 113 | func main() { | |
| 114 | a := Point{1, 2} | |
| 115 | b := new(Point) | |
| 116 | b.X, b.Y = 4, 3 | |
| 117 | fmt.Println(a.add(*b)) | |
| 118 | // No free, because Go is garbage-collected | |
| 119 | } | |
| 120 | ~~~~ | |
| 121 | ||
| 122 | # Systems Programming Languages | |
| 123 | ||
| 124 | ## D | |
| 125 | ||
| 126 | ~~~~{.d} | |
| 127 | struct Point { | |
| 128 | int x, y; | |
| 129 | Point add(Point other) { | |
| 130 | return Point(this.x + other.x, this.y + other.y); | |
| 131 | } | |
| 132 | } | |
| 133 | ||
| 134 | void main() { | |
| 135 | Point a = Point(1, 2); | |
| 136 | Point* b = cast(Point*)GC.malloc(Point.sizeof); | |
| 137 | b.x = 4; b.y = 3; | |
| 138 | writeln(a.add(*b)); | |
| 139 | GC.free(b); | |
| 140 | } | |
| 141 | ~~~~ | |
| 142 | ||
| 143 | # Systems Programming Languages | |
| 144 | ||
| 145 | ## Nimrod | |
| 146 | ||
| 147 | ~~~~ | |
| 148 | type Point = tuple[x: int, y: int] | |
| 149 | ||
| 150 | proc add(a: Point, b: Point): Point = | |
| 151 | (x: a.x + b.x, y: a.y + b.y) | |
| 152 | ||
| 153 | var a : Point | |
| 154 | var b : ptr Point | |
| 155 | ||
| 156 | a = (x: 1, y: 2) | |
| 157 | b = cast[ptr Point](alloc(sizeof(Point))) | |
| 158 | b.x = 4 | |
| 159 | b.y = 3 | |
| 160 | echo(add(a, b[])) | |
| 161 | dealloc(b) | |
| 162 | ~~~~ | |
| 163 | ||
| 164 | # Systems Programming Languages | |
| 165 | ||
| 166 | ## Rust | |
| 167 | ||
| 168 | ~~~~{.rust} | |
| 169 | struct Point { x: int, y: int } | |
| 170 | ||
| 171 | impl Point { | |
| 172 | fn add(self, other: Point) -> Point { | |
| 173 | Point { x: self.x + other.x, | |
| 174 | y: self.y + other.y } | |
| 175 | } | |
| 176 | } | |
| 177 | ||
| 178 | fn main() { | |
| 179 | let a = Point { x: 1, y: 2 }; | |
| 180 | let b = ~Point { x: 4, y: 3 }; | |
| 181 | println!("{:?}", a.add(*b)); | |
| 182 | } | |
| 183 | ~~~~ | |
| 184 | ||
| 185 | # Basics of Rust | |
| 186 | ||
| 187 | # Basics of Rust | |
| 188 | ||
| 189 | > It's like C++ grew up, went to grad school, started dating Haskell, and | |
| 190 | > is sharing an office with Erlang... | |
| 191 | > | |
| 192 | > —Michael Sullivan | |
| 193 | ||
| 194 | # Basics of Rust | |
| 195 | ||
| 196 | ## Recursive Factorial | |
| 197 | ||
| 198 | ~~~~{.rust} | |
| 199 | fn fact1(n: int) -> int { | |
| 200 | if n <= 0 { | |
| 201 | 1 | |
| 202 | } else { | |
| 203 | n * fact1(n-1) | |
| 204 | } | |
| 205 | } | |
| 206 | ~~~~ | |
| 207 | ||
| 208 | ## Another Recursive Factorial | |
| 209 | ||
| 210 | ~~~~{.rust} | |
| 211 | fn fact2(n: int) -> int { | |
| 212 | match n { | |
| 213 | 0 => { 1 } | |
| 214 | _ => { n * fact2(n-1) } | |
| 215 | } | |
| 216 | } | |
| 217 | ~~~~ | |
| 218 | ||
| 219 | # Basics of Rust | |
| 220 | ||
| 221 | ## An Imperative Factorial | |
| 222 | ||
| 223 | ~~~~{.rust} | |
| 224 | fn fact3(mut n: int) -> int { | |
| 225 | let mut res = 1; | |
| 226 | while (n > 0) { | |
| 227 | res *= n; | |
| 228 | n -= 1; | |
| 229 | } | |
| 230 | res | |
| 231 | } | |
| 232 | ~~~~ | |
| 233 | ||
| 234 | ## One More Imperative Factorial | |
| 235 | ||
| 236 | ~~~~{.rust} | |
| 237 | fn fact4(mut n: int) -> int { | |
| 238 | for i in range(1, n) { n *= i; } | |
| 239 | return n; | |
| 240 | } | |
| 241 | ~~~~ | |
| 242 | ||
| 243 | # Basics of Rust | |
| 244 | ||
| 245 | ## Tuples | |
| 246 | ||
| 247 | ~~~~{.rust} | |
| 248 | { | |
| 249 | let t: (int, int, int) = (1,2,3); | |
| 250 | let (a,b,c) = t; | |
| 251 | let r = match t { (a,b,c) => a + b + c }; | |
| 252 | } | |
| 253 | ~~~~ | |
| 254 | ||
| 255 | ## Tuple Structs (i.e. named tuples) | |
| 256 | ||
| 257 | ~~~~{.rust} | |
| 258 | struct T(bool, int); | |
| 259 | fn f(t: T) -> int { | |
| 260 | let T(myBool, myInt) = t; | |
| 261 | return if myBool { myInt } else { -myInt }; | |
| 262 | } | |
| 263 | ~~~~ | |
| 264 | ||
| 265 | # Basics of Rust | |
| 266 | ||
| 267 | ## Structs | |
| 268 | ||
| 269 | ~~~~{.rust} | |
| 270 | struct Point { x: f64, y: f64 } | |
| 271 | ||
| 272 | fn isOrigin1 (p: Point) -> bool { | |
| 273 | p.x == 0.0 && p.y == 0.0 | |
| 274 | } | |
| 275 | ~~~~ | |
| 276 | ||
| 277 | ~~~~{.rust} | |
| 278 | fn isOrigin2 (p: Point) -> bool { | |
| 279 | match p { | |
| 280 | Point { x: 0.0, y: 0.0 } => true, | |
| 281 | _ => false | |
| 282 | } | |
| 283 | } | |
| 284 | ~~~~ | |
| 285 | ||
| 286 | # Basics of Rust | |
| 287 | ||
| 288 | ## Enums | |
| 289 | ||
| 290 | ~~~~{.rust} | |
| 291 | enum Color { Red, Green, Blue } | |
| 292 | ||
| 293 | enum Shape { | |
| 294 | Circle(Point, f64), | |
| 295 | Rectangle(Point, Point), | |
| 296 | } | |
| 297 | ||
| 298 | fn area(s: Shape) -> f64 { | |
| 299 | match s { | |
| 300 | Circle(_, sz) => f64::consts::pi * sz * sz, | |
| 301 | Rectangle(p1, p2) => (p2.x - p1.x) * (p2.y - p1.y) | |
| 302 | } | |
| 303 | } | |
| 304 | ~~~~ | |
| 305 | ||
| 306 | # Pointers and Memory | |
| 307 | ||
| 308 | # Pointers and Memory | |
| 309 | ||
| 310 | \begin{center} | |
| 311 | \includegraphics[width=.9\textwidth]{imgs/dawkins-owned.png} | |
| 312 | \end{center} | |
| 313 | ||
| 314 | # Pointers and Memory | |
| 315 | ||
| 316 | ## "Owned" Pointers | |
| 317 | ||
| 318 | ~~~~{.rust} | |
| 319 | fn main() { | |
| 320 | let x: ~[int] = ~[1,2,3]; | |
| 321 | /* x in scope */ | |
| 322 | { | |
| 323 | let y: ~[int] = ~[4,5,6]; | |
| 324 | /* x, y in scope */ | |
| 325 | } | |
| 326 | /* x in scope */ | |
| 327 | } | |
| 328 | ~~~~ | |
| 329 | ||
| 330 | # Pointers and Memory | |
| 331 | ||
| 332 | ## "Owned" Pointers | |
| 333 | ||
| 334 | ~~~~{.rust} | |
| 335 | fn main() { | |
| 336 | let x: ~[int] = ~[1,2,3]; // malloc |----+ | |
| 337 | /* ... */ // | | |
| 338 | { // | | |
| 339 | let y: ~[int] = ~[4,5,6]; // malloc |-+ | | |
| 340 | /* ... */ // | | | |
| 341 | } // free <---+ | | |
| 342 | /* ... */ // | | |
| 343 | } // free <------+ | |
| 344 | ~~~~ | |
| 345 | ||
| 346 | # Pointers and Memory | |
| 347 | ||
| 348 | ## "Owned" Pointers | |
| 349 | ||
| 350 | ~~~~{.rust} | |
| 351 | fn f0() -> ~[int] { | |
| 352 | return ~[1,2,3]; // returning ownership | |
| 353 | } | |
| 354 | fn f1() -> ~[int] { | |
| 355 | let a = ~[1,2,3]; | |
| 356 | let b = a; | |
| 357 | return a; // error: use of moved value: `a` | |
| 358 | } | |
| 359 | fn f2() -> ~[int] { | |
| 360 | let a = ~[1,2,3]; | |
| 361 | let b = a.clone(); | |
| 362 | return a; // fine now; `a` and `b` both valid | |
| 363 | } | |
| 364 | ~~~~ | |
| 365 | ||
| 366 | # Pointers and Memory | |
| 367 | ||
| 368 | ## "Owned" Pointers | |
| 369 | ||
| 370 | ~~~~{.rust} | |
| 371 | #[deriving(Clone)] | |
| 372 | enum List<T> { Cons(T, ~List<T>), Nil } | |
| 373 | ||
| 374 | fn f3() -> ~List<int> { | |
| 375 | let mut a = ~Cons(1, ~Cons(2, ~Nil)) | |
| 376 | /* a is mutable */ | |
| 377 | let b = a; | |
| 378 | /* can no longer use a, b is immutable */ | |
| 379 | let mut c = b.clone(); | |
| 380 | /* can use both b and c */ | |
| 381 | return b; | |
| 382 | } | |
| 383 | ~~~~ | |
| 384 | ||
| 385 | # Pointers and Memory | |
| 386 | ||
| 387 | ## Dispreferred Style | |
| 388 | ||
| 389 | ~~~~{.rust} | |
| 390 | type t8 = (u32,u32,u32,u32,u32,u32,u32,u32); | |
| 391 | ||
| 392 | fn eight_nums() -> ~t8 { | |
| 393 | ~(1,2,3,4,5,6,7,8) | |
| 394 | } | |
| 395 | ||
| 396 | fn main() { | |
| 397 | let t: ~t8 = eight_nums(); | |
| 398 | /* ... */ | |
| 399 | } | |
| 400 | ~~~~ | |
| 401 | ||
| 402 | # Pointers and Memory | |
| 403 | ||
| 404 | ## Preferred Style | |
| 405 | ||
| 406 | ~~~~{.rust} | |
| 407 | type t8 = (u32,u32,u32,u32,u32,u32,u32,u32); | |
| 408 | ||
| 409 | fn eight_nums() -> t8 { | |
| 410 | (1,2,3,4,5,6,7,8) | |
| 411 | } | |
| 412 | ||
| 413 | fn main() { | |
| 414 | let t: ~t8 = ~eight_nums(); | |
| 415 | /* ... */ | |
| 416 | } | |
| 417 | ~~~~ | |
| 418 | ||
| 419 | # Pointers and Memory | |
| 420 | ||
| 421 | ## References | |
| 422 | ||
| 423 | ~~~~{.rust} | |
| 424 | { | |
| 425 | let p = Point { x: 1.2, y: 3.4 }; | |
| 426 | let q = & p; | |
| 427 | // both p and q usable | |
| 428 | } | |
| 429 | { | |
| 430 | let q = & Point { x: 1.2, y: 3.4 }; | |
| 431 | } | |
| 432 | { | |
| 433 | let p = Point { x: 1.2, y: 3.4 }; | |
| 434 | let r = & p.x; | |
| 435 | } | |
| 436 | ~~~~ | |
| 437 | ||
| 438 | # Pointers and Memory | |
| 439 | ||
| 440 | ## References | |
| 441 | ||
| 442 | ~~~~{.rust} | |
| 443 | fn eq(xl: ~List<int>, yl: ~List<int>) -> bool { | |
| 444 | /* elided */ | |
| 445 | } | |
| 446 | ||
| 447 | fn main() { | |
| 448 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
| 449 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
| 450 | println!("{}", eq(l1, l2)); | |
| 451 | println!("{:?}", l1); | |
| 452 | } | |
| 453 | ~~~~ | |
| 454 | ||
| 455 | # Pointers and Memory | |
| 456 | ||
| 457 | ## References | |
| 458 | ||
| 459 | ~~~~{.rust} | |
| 460 | fn eq(xl: ~List<int>, yl: ~List<int>) -> bool { | |
| 461 | /* elided */ | |
| 462 | } | |
| 463 | ||
| 464 | fn main() { | |
| 465 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
| 466 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
| 467 | println!("{}", eq(l1, l2)); // ownership of l1 and l2 | |
| 468 | // moves to eq function | |
| 469 | println!("{:?}", l1); // error: use of moved value! | |
| 470 | } | |
| 471 | ~~~~ | |
| 472 | ||
| 473 | # Pointers and Memory | |
| 474 | ||
| 475 | ## References | |
| 476 | ||
| 477 | ~~~~{.rust} | |
| 478 | fn eq(xl: ~List<int>, yl: ~List<int>) -> bool { | |
| 479 | /* elided */ | |
| 480 | } | |
| 481 | ||
| 482 | fn main() { | |
| 483 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
| 484 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
| 485 | println!("{}", eq(l1.clone(), l2.clone())); | |
| 486 | println!("{:?}", l1); | |
| 487 | } | |
| 488 | ~~~~ | |
| 489 | ||
| 490 | # Pointers and Memory | |
| 491 | ||
| 492 | ## References | |
| 493 | ||
| 494 | ~~~~{.rust} | |
| 495 | fn eq(xl: &List<int>, yl: &List<int>) -> bool { | |
| 496 | /* elided */ | |
| 497 | } | |
| 498 | ||
| 499 | fn main() { | |
| 500 | let l1 = ~Cons(1, ~Cons (2, ~Nil)); | |
| 501 | let l2 = ~Cons(3, ~Cons (4, ~Nil)); | |
| 502 | println!("{}", eq(l1, l2)); | |
| 503 | println!("{:?}", l1); | |
| 504 | } | |
| 505 | ~~~~ | |
| 506 | ||
| 507 | # Pointers and Memory | |
| 508 | ||
| 509 | ## References | |
| 510 | ||
| 511 | ~~~~{.rust} | |
| 512 | fn eq(xl: &List<int>, yl: &List<int>) -> bool { | |
| 513 | match (xl, yl) { | |
| 514 | (&Nil, &Nil) => true, | |
| 515 | (&Cons(x, ~ref xs), &Cons(y, ~ref ys)) | |
| 516 | if x == y => eq(xs, ys), | |
| 517 | (_, _) => false | |
| 518 | } | |
| 519 | } | |
| 520 | ~~~~ | |
| 521 | ||
| 522 | # Pointers and Memory | |
| 523 | ||
| 524 | ## References | |
| 525 | ||
| 526 | ~~~~{.rust} | |
| 527 | fn eq<T: Eq>(xl: &List<T>, yl: &List<T>) -> bool { | |
| 528 | match (xl, yl) { | |
| 529 | (&Nil, &Nil) => true, | |
| 530 | (&Cons(x, ~ref xs), &Cons(y, ~ref ys)) | |
| 531 | if x == y => eq(xs, ys), | |
| 532 | (_, _) => false | |
| 533 | } | |
| 534 | } | |
| 535 | ~~~~ | |
| 536 | ||
| 537 | # Pointers and Memory | |
| 538 | ||
| 539 | ## References and Lifetimes | |
| 540 | ||
| 541 | ~~~~{.rust} | |
| 542 | { | |
| 543 | let a = ~5; | |
| 544 | let mut p = &a; | |
| 545 | { | |
| 546 | let b = ~8; | |
| 547 | p = &b; | |
| 548 | } | |
| 549 | println!("{}", **p) | |
| 550 | } | |
| 551 | ~~~~ | |
| 552 | ||
| 553 | ||
| 554 | # Pointers and Memory | |
| 555 | ||
| 556 | ## References and Lifetimes | |
| 557 | ||
| 558 | ~~~~{.rust} | |
| 559 | { | |
| 560 | let a = ~5; // malloc |---+ | |
| 561 | let mut p = &a; // | | |
| 562 | { // | | |
| 563 | let b = ~8; // malloc |-+ | | |
| 564 | p = &b; // | | | |
| 565 | } // free <---+ | | |
| 566 | println!("{}", **p) // | | |
| 567 | } // free <-----+ | |
| 568 | ~~~~ | |
| 569 | ||
| 570 | ||
| 571 | # Pointers and Memory | |
| 572 | ||
| 573 | ## References and Lifetimes | |
| 574 | ||
| 575 | ~~~~{.rust} | |
| 576 | { | |
| 577 | let a = ~5; | |
| 578 | let mut p = &a; | |
| 579 | { | |
| 580 | let b = ~8; | |
| 581 | p = &b; // error: borrowed value does | |
| 582 | // not live long enough | |
| 583 | } | |
| 584 | println!("{}", **p) | |
| 585 | } | |
| 586 | ~~~~ | |
| 587 | # Pointers and Memory | |
| 588 | ||
| 589 | ## References, Pointers, Mutability | |
| 590 | ||
| 591 | ~~~~{.rust} | |
| 592 | { | |
| 593 | let mut x = ~5; | |
| 594 | *x = *x + 1; | |
| 595 | { | |
| 596 | let y = &x; | |
| 597 | /* x is not mutable for the rest of this block */ | |
| 598 | } | |
| 599 | /* x regains mutability */ | |
| 600 | } | |
| 601 | ~~~~ | |
| 602 | ||
| 603 | # Pointers and Memory | |
| 604 | ||
| 605 | ## References, Pointers, Mutability | |
| 606 | ||
| 607 | ~~~~{.rust} | |
| 608 | enum IntList { | |
| 609 | Cons { head: int, tail: ~IntList }, | |
| 610 | Nil, | |
| 611 | } | |
| 612 | { | |
| 613 | let mut lst = ~Cons { head: 5, tail: ~Nil }; | |
| 614 | { | |
| 615 | let y = &(lst.head); // or &((*lst).head) | |
| 616 | lst = ~Nil; | |
| 617 | println!("{}", y); | |
| 618 | } | |
| 619 | } | |
| 620 | ~~~~ | |
| 621 | ||
| 622 | # Pointers and Memory | |
| 623 | ||
| 624 | ## References, Pointers, Mutability | |
| 625 | ||
| 626 | ~~~~{.rust} | |
| 627 | enum IntList { | |
| 628 | Cons { head: int, tail: ~IntList }, | |
| 629 | Nil, | |
| 630 | } | |
| 631 | { | |
| 632 | let mut lst = ~Cons { head: 5, tail: ~Nil }; | |
| 633 | { | |
| 634 | let y = &(lst.head); | |
| 635 | lst = ~Nil; | |
| 636 | println!("{}", y); // BAD | |
| 637 | } | |
| 638 | } | |
| 639 | ~~~~ | |
| 640 | ||
| 641 | # Pointers and Memory | |
| 642 | ||
| 643 | ## Named Lifetimes | |
| 644 | ||
| 645 | ~~~~{.rust} | |
| 646 | fn tail<T>(lst: &List<T>) -> &List<T> { | |
| 647 | match *lst { | |
| 648 | Nil => &Nil, | |
| 649 | Cons(_, ~ref xs) => xs | |
| 650 | } | |
| 651 | } | |
| 652 | ~~~~ | |
| 653 | ||
| 654 | # Pointers and Memory | |
| 655 | ||
| 656 | ## Named Lifetimes | |
| 657 | ||
| 658 | ~~~~{.rust} | |
| 659 | fn tail<'s, T>(lst: &'s List<T>) -> &'s List<T> { | |
| 660 | match *lst { | |
| 661 | Nil => &Nil, | |
| 662 | Cons(_, ~ref xs) => xs | |
| 663 | } | |
| 664 | } | |
| 665 | ~~~~ | |
| 666 | ||
| 667 | # Pointers and Memory | |
| 668 | ||
| 669 | ## Reference Counting | |
| 670 | ||
| 671 | ~~~~{.rust} | |
| 672 | use std::rc::Rc; | |
| 673 | { | |
| 674 | let x = Rc::new([1,2,3]); | |
| 675 | let y = x.clone(); // two references, one vector | |
| 676 | assert!(x.ptr_eq(y)); | |
| 677 | assert!(*y.borrow() == [1,2,3]); | |
| 678 | } | |
| 679 | ~~~~ | |
| 680 | ||
| 681 | ## Garbage Collection | |
| 682 | ||
| 683 | ~~~~{.rust} | |
| 684 | use std::gc::Gc; | |
| 685 | { | |
| 686 | let x = Gc::new([1,2,3]); | |
| 687 | // etc. | |
| 688 | } | |
| 689 | ~~~~ | |
| 690 | ||
| 691 | # Pointers and Memory | |
| 692 | ||
| 693 | ## C Pointers | |
| 694 | ||
| 695 | ~~~~{.rust} | |
| 696 | use std::ptr::RawPtr; | |
| 697 | ||
| 698 | #[link(name="foo")] | |
| 699 | extern { | |
| 700 | fn unsafe_get() -> *int; | |
| 701 | } | |
| 702 | ||
| 703 | fn safe_get() -> Option<int> { | |
| 704 | unsafe { | |
| 705 | let i = unsafe_get(); | |
| 706 | i.to_option() | |
| 707 | } | |
| 708 | } | |
| 709 | ~~~~ | |
| 710 | ||
| 711 | # Closures | |
| 712 | ||
| 713 | # Closures | |
| 714 | ||
| 715 | > [...] Lambdas are relegated to relative obscurity until Java makes them | |
| 716 | > popular by not having them. | |
| 717 | > | |
| 718 | > —James Iry, "A Brief, Incomplete, and Mostly Wrong History of Programming | |
| 719 | > Languages" | |
| 720 | ||
| 721 | # Closures | |
| 722 | ||
| 723 | ## Functions | |
| 724 | ||
| 725 | ~~~~{.rust} | |
| 726 | fn main() { | |
| 727 | let x = 5; | |
| 728 | fn inner(y: int) -> int { | |
| 729 | return x + y; | |
| 730 | } | |
| 731 | println!("{}", inner(1)); | |
| 732 | } | |
| 733 | ~~~~ | |
| 734 | ||
| 735 | # Closures | |
| 736 | ||
| 737 | ## Functions Do NOT Close Over Env | |
| 738 | ||
| 739 | ~~~~{.rust} | |
| 740 | fn main() { | |
| 741 | let x = 5; | |
| 742 | fn inner(y: int) -> int { | |
| 743 | return x + y; // error: can't capture dynamic env | |
| 744 | } | |
| 745 | println!("{}", inner(1)); | |
| 746 | } | |
| 747 | ~~~~ | |
| 748 | ||
| 749 | # Closures | |
| 750 | ||
| 751 | ## Stack Closure | |
| 752 | ||
| 753 | ~~~~{.rust} | |
| 754 | fn main() { | |
| 755 | let x = 5; | |
| 756 | let inner = |y| x + y; | |
| 757 | println!("{}", inner(1)); | |
| 758 | } | |
| 759 | ~~~~ | |
| 760 | ||
| 761 | ## Stack Closure with Type Annotations | |
| 762 | ||
| 763 | ~~~~{.rust} | |
| 764 | fn main() { | |
| 765 | let x = 5; | |
| 766 | let inner = |y: int| -> int { x + y }; | |
| 767 | println!("{}", inner(1)); | |
| 768 | } | |
| 769 | ~~~~ | |
| 770 | ||
| 771 | # Closures | |
| 772 | ||
| 773 | ## Stack Closures | |
| 774 | ||
| 775 | ~~~~{.rust} | |
| 776 | fn my_map<A,B>(f: |&A|->B, l: &List<A>) -> List<B> { | |
| 777 | match *l { | |
| 778 | Nil => Nil, | |
| 779 | Cons(ref x, ~ref xs) => | |
| 780 | Cons(f(x)), ~my_map(f, xs)) | |
| 781 | } | |
| 782 | } | |
| 783 | ||
| 784 | fn main() { | |
| 785 | fn incr(x: &int) -> int { x + 1 } | |
| 786 | let l = ~Cons(1, ~Cons(2, ~Cons(3, ~Nil))); | |
| 787 | println!("{:?}", my_map(|x| x + 1, l)); | |
| 788 | println!("{:?}", my_map(incr, l)); | |
| 789 | } | |
| 790 | ~~~~ | |
| 791 | ||
| 792 | # Closures | |
| 793 | ||
| 794 | ## Owned Closures | |
| 795 | ||
| 796 | ~~~~{.rust} | |
| 797 | use std::task::spawn; | |
| 798 | ||
| 799 | fn main() { | |
| 800 | let x = ~5; | |
| 801 | spawn(proc() { | |
| 802 | println!("{}", x); | |
| 803 | }); | |
| 804 | // x is now owned by the proc above | |
| 805 | } | |
| 806 | ~~~~ | |
| 807 | ||
| 808 | # Methods | |
| 809 | ||
| 810 | ## Methods on a Struct | |
| 811 | ||
| 812 | ~~~~{.rust} | |
| 813 | use std::f64::{sqrt,pow}; | |
| 814 | struct Point { x: f64, y: f64 } | |
| 815 | impl Point { | |
| 816 | fn magnitude(&self) -> f64 { | |
| 817 | sqrt(pow(self.x,2.0)+pow(self.y,2.0)) | |
| 818 | } | |
| 819 | fn new((my_x, my_y): (f64, f64)) -> Point { | |
| 820 | Point { x: my_x, y: my_y } | |
| 821 | } | |
| 822 | } | |
| 823 | fn main() { | |
| 824 | let p = Point::new((2.0,4.0)); | |
| 825 | println!("{}", p.magnitude()); | |
| 826 | } | |
| 827 | ~~~~ | |
| 828 | ||
| 829 | # Methods | |
| 830 | ||
| 831 | ## Methods on an Enum | |
| 832 | ||
| 833 | ~~~~{.rust} | |
| 834 | impl<T> List<T> { | |
| 835 | fn is_empty(&self) -> bool { | |
| 836 | match self { | |
| 837 | &Nil => true, | |
| 838 | &Cons(_, _) => false, | |
| 839 | } | |
| 840 | } | |
| 841 | } | |
| 842 | ~~~~ | |
| 843 | ||
| 844 | # Traits | |
| 845 | ||
| 846 | ## Head of a List By Reference | |
| 847 | ~~~~{.rust} | |
| 848 | fn head<'a, T>(lst: &'a List<T>) -> Option<&'a T> { | |
| 849 | match lst { | |
| 850 | &Nil => None, | |
| 851 | &Cons(ref hd, _) => Some(hd) | |
| 852 | } | |
| 853 | } | |
| 854 | ~~~~ | |
| 855 | ||
| 856 | # Traits | |
| 857 | ||
| 858 | ## Head of a List By Value | |
| 859 | ~~~~{.rust} | |
| 860 | fn head<T>(lst: &List<T>) -> Option<T> { | |
| 861 | match lst { | |
| 862 | &Nil => None, | |
| 863 | &Cons(ref hd, _) => Some(*hd) | |
| 864 | } | |
| 865 | } | |
| 866 | ~~~~ | |
| 867 | ||
| 868 | # Traits | |
| 869 | ||
| 870 | ## Head of a List By Value | |
| 871 | ~~~~{.rust} | |
| 872 | fn head<T>(lst: &List<T>) -> Option<T> { | |
| 873 | match lst { | |
| 874 | &Nil => None, | |
| 875 | &Cons(ref hd, _) => Some(*hd) | |
| 876 | // cannot move out of dereference of & pointer | |
| 877 | } | |
| 878 | } | |
| 879 | ~~~~ | |
| 880 | ||
| 881 | # Traits | |
| 882 | ||
| 883 | ## Head of a List By Value | |
| 884 | ~~~~{.rust} | |
| 885 | fn head<T: Clone>(lst: &List<T>) -> Option<T> { | |
| 886 | match lst { | |
| 887 | &Nil => None, | |
| 888 | &Cons(ref hd, _) => Some(hd.clone()) | |
| 889 | } | |
| 890 | } | |
| 891 | ~~~~ | |
| 892 | ||
| 893 | # Traits | |
| 894 | ||
| 895 | ## Declaring Traits | |
| 896 | ~~~~{.rust} | |
| 897 | trait Printable { | |
| 898 | fn print(&self); | |
| 899 | } | |
| 900 | ||
| 901 | impl Printable for int { | |
| 902 | fn print(&self) { println!("{}", *self) } | |
| 903 | } | |
| 904 | ||
| 905 | impl Printable for bool { | |
| 906 | fn print(&self) { println!("{}", *self) } | |
| 907 | } | |
| 908 | ||
| 909 | fn main() { | |
| 910 | 5.print(); true.print(); | |
| 911 | } | |
| 912 | ~~~~ | |
| 913 | ||
| 914 | # Traits | |
| 915 | ||
| 916 | ## Using Multiple Traits | |
| 917 | ||
| 918 | ~~~~{.rust} | |
| 919 | fn print_head<T: Clone+Printable>(lst: &List<T>) { | |
| 920 | match lst { | |
| 921 | &Nil => { println!("Nothing!") } | |
| 922 | &Cons(ref hd, _) => { hd.clone().print() } | |
| 923 | } | |
| 924 | } | |
| 925 | ~~~~ | |
| 926 | ||
| 927 | # Traits | |
| 928 | ||
| 929 | ## Static Dispatch | |
| 930 | ||
| 931 | ~~~~{.rust} | |
| 932 | fn printAll<T: Printable>(vec: &[T]) { | |
| 933 | for p in vec.iter() { p.print() } | |
| 934 | } | |
| 935 | fn main() { | |
| 936 | printAll([1, 2, 3]); | |
| 937 | } | |
| 938 | ~~~~ | |
| 939 | ||
| 940 | ## Dynamic Dispatch | |
| 941 | ||
| 942 | ~~~~{.rust} | |
| 943 | fn print_all(vec: &[~Printable]) { | |
| 944 | for p in vec.iter() { p.print() } | |
| 945 | } | |
| 946 | fn main() { | |
| 947 | print_all([~1 as ~Printable, ~true as ~Printable]); | |
| 948 | } | |
| 949 | ~~~~ | |
| 950 | ||
| 951 | # Tasks and Communication | |
| 952 | ||
| 953 | ## Tasks | |
| 954 | ||
| 955 | ~~~~{.rust} | |
| 956 | fn main() { | |
| 957 | spawn(proc() { | |
| 958 | println!("Hello from another task!"); | |
| 959 | }); | |
| 960 | println!("Hello from the parent task!"); | |
| 961 | } | |
| 962 | ~~~~ | |
| 963 | ||
| 964 | # Tasks and Communication | |
| 965 | ||
| 966 | ## Communication | |
| 967 | ||
| 968 | ~~~~{.rust} | |
| 969 | fn main() { | |
| 970 | let (port, chan): (Port<int>, Chan<int>) = Chan::new(); | |
| 971 | spawn(proc() { | |
| 972 | chan.send(some_computation()); | |
| 973 | }); | |
| 974 | some_other_computation(); | |
| 975 | let result = port.recv(); | |
| 976 | } | |
| 977 | ~~~~ | |
| 978 | ||
| 979 | # Tasks and Communication | |
| 980 | ||
| 981 | ## Atomic Reference Counting | |
| 982 | ||
| 983 | ~~~~{.rust} | |
| 984 | fn main() { | |
| 985 | let parent_copy = Arc::new(something_very_large()); | |
| 986 | let (port, chan) = Chan::new(); | |
| 987 | chan.send(parent_copy.clone()); | |
| 988 | spawn(proc() { | |
| 989 | let task_copy = port.recv(); | |
| 990 | task_copy.get().do_something(); | |
| 991 | }); | |
| 992 | parent_copy.get().do_something_else(); | |
| 993 | } | |
| 994 | ~~~~ | |
| 995 | ||
| 996 | # Tasks and Communication | |
| 997 | ||
| 998 | ## Failure | |
| 999 | ||
| 1000 | ~~~~{.rust} | |
| 1001 | fn main() { | |
| 1002 | let r : Result<int, ()> = try(proc() { | |
| 1003 | if some_operation_succeeds() { | |
| 1004 | return 5; | |
| 1005 | } else { | |
| 1006 | fail!("Hark! An error!"); | |
| 1007 | } | |
| 1008 | }); | |
| 1009 | match r { | |
| 1010 | Ok(i) => println!("Got {}", i), | |
| 1011 | Err(_) => println!("Hark!"), | |
| 1012 | }; | |
| 1013 | } | |
| 1014 | ~~~~ | |
| 1015 | ||
| 1016 | # Crates and Modules | |
| 1017 | ||
| 1018 | - A "crate" is a compilation unit; `rustc` produces a single crate | |
| 1019 | if it is run (either a library or an executable.) | |
| 1020 | - A module is a grouping of definitions. Modules can be hierarchical | |
| 1021 | and can be defined in a single file in `mod { ... }` blocks, or in | |
| 1022 | separate files. | |
| 1023 | ||
| 1024 | # Crates and Modules | |
| 1025 | ||
| 1026 | ## main.rs | |
| 1027 | ||
| 1028 | ~~~~{.rust} | |
| 1029 | mod mylist { | |
| 1030 | pub enum List<T> { Cons(T, ~List<T>), Nil } | |
| 1031 | pub fn from_vec<T>(mut vec : ~[T]) -> ~List<T> { ... } | |
| 1032 | impl<T> List<T> { | |
| 1033 | pub fn length(&self) -> int { ... } | |
| 1034 | } | |
| 1035 | } | |
| 1036 | ||
| 1037 | fn main() { | |
| 1038 | let v = ~[1,2,3]; | |
| 1039 | let l = ::mylist::from_vec(v); | |
| 1040 | /* ... */ | |
| 1041 | } | |
| 1042 | ~~~~ | |
| 1043 | ||
| 1044 | # Crates and Modules | |
| 1045 | ||
| 1046 | ## mylist.rs or mylist/mod.rs | |
| 1047 | ||
| 1048 | ~~~~{.rust} | |
| 1049 | mod mylist { | |
| 1050 | pub enum List<T> { Cons(T, ~List<T>), Nil } | |
| 1051 | pub fn from_vec<T>(mut vec : ~[T]) -> ~List<T> { ... } | |
| 1052 | impl<T> List<T> { | |
| 1053 | pub fn length(&self) -> int { ... } | |
| 1054 | } | |
| 1055 | } | |
| 1056 | ~~~~ | |
| 1057 | ||
| 1058 | ## main.rs | |
| 1059 | ||
| 1060 | ~~~~{.rust} | |
| 1061 | mod mylist; | |
| 1062 | main() { | |
| 1063 | let v = ~[1,2,3]; | |
| 1064 | let l = ::mylist::from_vec(v); | |
| 1065 | /* ... */ | |
| 1066 | } | |
| 1067 | ~~~~ | |
| 1068 | ||
| 1069 | # Crates and Modules | |
| 1070 | ## main.rs | |
| 1071 | ||
| 1072 | ~~~~{.rust} | |
| 1073 | use mylist::from_vec; | |
| 1074 | mod mylist; | |
| 1075 | ||
| 1076 | main() { | |
| 1077 | let v = ~[1,2,3]; | |
| 1078 | let l = from_vec(v); | |
| 1079 | /* ... */ | |
| 1080 | } | |
| 1081 | ~~~~ | |
| 1082 | ||
| 1083 | # Crates and Modules | |
| 1084 | ## Crate Metadata | |
| 1085 | ||
| 1086 | ~~~~{.rust} | |
| 1087 | #[crate_id = "mycrate#1.2"]; | |
| 1088 | #[crate_type = "lib"]; | |
| 1089 | ~~~~ | |
| 1090 | ||
| 1091 | ## Requesting Crate Metadata | |
| 1092 | ||
| 1093 | ~~~~{.rust} | |
| 1094 | extern crate mycrate "mycrate#1.2"; | |
| 1095 | extern crate oldmycrate "mycrate#0.6"; | |
| 1096 | ~~~~ | |
| 1097 | ||
| 1098 | # The Future | |
| 1099 | ||
| 1100 | # The Future | |
| 1101 | ||
| 1102 | \begin{center} | |
| 1103 | \includegraphics[width=.9\textwidth]{imgs/flying-machines.jpg} | |
| 1104 | \end{center} | |
| 1105 | ||
| 1106 | # The Future | |
| 1107 | ||
| 1108 | ## Possible Syntax Changes | |
| 1109 | ||
| 1110 | - `~foo` might become `box foo` | |
| 1111 | - `~[T]` might become `Vec<T>` | |
| 1112 | - Operator overloading | |
| 1113 | ||
| 1114 | ## Possible Language Changes | |
| 1115 | ||
| 1116 | - Speculations about inheritance, subtyping | |
| 1117 | - Stronger restrictions on `unsafe` code | |
| 1118 | ||
| 1119 | ## Standard Library Improvements | |
| 1120 | ||
| 1121 | ## Package Manager |
| 1 | DEPS="rust.tex rust.md" | |
| 2 | redo-ifchange $DEPS | |
| 3 | xelatex --output-directory build 1>&2 rust.tex | |
| 4 | mv build/rust.pdf $3 |
| 1 | redo-ifchange rust.md | |
| 2 | pandoc -f markdown -t beamer --standalone --highlight-style haddock \ | |
| 3 | -V theme=Boadilla -V colortheme=beaver --template=my.beamer <rust.md >$3 |
| 1 | #include <stdio.h> | |
| 2 | #include <stdlib.h> | |
| 3 | ||
| 4 | typedef struct { | |
| 5 | int x, y; | |
| 6 | } point; | |
| 7 | ||
| 8 | point add(point a, point b) | |
| 9 | { | |
| 10 | point result = { a.x + b.x, a.y + b.y }; | |
| 11 | return result; | |
| 12 | } | |
| 13 | ||
| 14 | int main(int argc, char* argv[]) | |
| 15 | { | |
| 16 | point a = { 1, 2 }; | |
| 17 | point* b = malloc(sizeof(point)); | |
| 18 | b->x = 4; | |
| 19 | b->y = 3; | |
| 20 | point c = add(a, *b); | |
| 21 | printf("{.x = %d, .y = %d}\n", c.x, c.y); | |
| 22 | return 0; | |
| 23 | } |
| 1 | #include "stdio.h" | |
| 2 | #include "stdlib.h" | |
| 3 | #include <iostream> | |
| 4 | ||
| 5 | struct point { | |
| 6 | int x, y; | |
| 7 | point(int _x, int _y) { | |
| 8 | x = _x; y = _y; | |
| 9 | } | |
| 10 | point add(point other) { | |
| 11 | return point(x + other.x, y + other.y); | |
| 12 | } | |
| 13 | }; | |
| 14 | ||
| 15 | int main(int argc, char* argv[]) { | |
| 16 | point a(1, 2); | |
| 17 | point* b = new point(4, 3); | |
| 18 | point c = a.add(*b); | |
| 19 | std::cout << "{.x = " << c.x; | |
| 20 | std::cout << ", .y = " << c.y << "}" << std::endl; | |
| 21 | delete b; | |
| 22 | } |
| 1 | import core.memory; | |
| 2 | import std.stdio; | |
| 3 | ||
| 4 | struct Point { | |
| 5 | int x, y; | |
| 6 | Point add(Point other) { | |
| 7 | return Point(this.x + other.x, this.y + other.y); | |
| 8 | } | |
| 9 | } | |
| 10 | ||
| 11 | void main() { | |
| 12 | Point a = Point(1, 2); | |
| 13 | Point* b = cast(Point*)GC.malloc(Point.sizeof); | |
| 14 | b.x = 4; | |
| 15 | b.y = 3; | |
| 16 | writeln(a.add(*b)); | |
| 17 | GC.free(b); | |
| 18 | } |
| 1 | data Point = { x, y : Int } | |
| 2 | ||
| 3 | addPoint : Point -> Point -> Point | |
| 4 | addPoint p1 p2 = { x = p1.x + p2.x, y = p1.y + p2.y } | |
| 5 | ||
| 6 | main : () | |
| 7 | main = { let a = { x = 1, y = 2 } | |
| 8 | ; let b = malloc { x = 4, y = 3} | |
| 9 | ; print (addPoint a (deref b)) | |
| 10 | ; free(b) | |
| 11 | } |
| 1 | package main | |
| 2 | ||
| 3 | import "fmt" | |
| 4 | ||
| 5 | type Point struct { X, Y int } | |
| 6 | ||
| 7 | func (a Point) add(b Point) Point { | |
| 8 | return Point{ a.X + b.X, a.Y + b.Y } | |
| 9 | } | |
| 10 | ||
| 11 | func main() { | |
| 12 | a := Point{1, 2} | |
| 13 | b := new(Point) | |
| 14 | b.X, b.Y = 4, 3 | |
| 15 | fmt.Println(a.add(*b)) | |
| 16 | } |
| 1 | type Point = tuple[x: int, y: int] | |
| 2 | ||
| 3 | proc add(a: Point, b: Point): Point = | |
| 4 | (x: a.x + b.x, y: a.y + b.y) | |
| 5 | ||
| 6 | var a : Point | |
| 7 | var b : ptr Point | |
| 8 | ||
| 9 | a = (x: 1, y: 2) | |
| 10 | b = cast[ptr Point](alloc(sizeof(Point))) | |
| 11 | b.x = 4 | |
| 12 | b.y = 3 | |
| 13 | echo(add(a, b[])) | |
| 14 | dealloc(b) |
| 1 | struct Point { | |
| 2 | x: int, | |
| 3 | y: int | |
| 4 | } | |
| 5 | ||
| 6 | impl Point { | |
| 7 | fn add(self, other: Point) -> Point { | |
| 8 | Point { x: self.x + other.x, | |
| 9 | y: self.y + other.y } | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | fn main() { | |
| 14 | let a = Point { x: 1, y: 2 }; | |
| 15 | let b = ~Point { x: 4, y: 3 }; | |
| 16 | println!("{:?}", a.add(*b)); | |
| 17 | } |
| 1 | if [ -e regexp ]; then rm regexp; fi |
| 1 | redo-ifchange regexp |
| 1 | use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
| 2 | use std::vec::append; | |
| 3 | mod instruction; | |
| 4 | ||
| 5 | /* A regular expression parse tree */ | |
| 6 | enum Regexp { | |
| 7 | RChar(char), | |
| 8 | RSeq(~Regexp, ~Regexp), | |
| 9 | RChc(~Regexp, ~Regexp), | |
| 10 | RRep(~Regexp), | |
| 11 | } | |
| 12 | ||
| 13 | /* We're assuming a prefix regexp here. That means that we have | |
| 14 | * the following operators: | |
| 15 | * .ab => ab | |
| 16 | * |ab => a|b | |
| 17 | * *a => a* | |
| 18 | * but these nest, so (ab|c)* would become | |
| 19 | * *|c.ab | |
| 20 | * This is easier to parse. Deal with it. | |
| 21 | */ | |
| 22 | fn parse<'a>(s: &'a str) -> (&'a str, Regexp) { | |
| 23 | match s.char_at(0) { | |
| 24 | '.' => { let (s1, r1) = parse(s.slice_from(1)); | |
| 25 | let (s2, r2) = parse(s1); | |
| 26 | (s2, RSeq(~r1, ~r2)) }, | |
| 27 | '|' => { let (s1, r1) = parse(s.slice_from(1)); | |
| 28 | let (s2, r2) = parse(s1); | |
| 29 | (s2, RChc(~r1, ~r2)) }, | |
| 30 | '*' => { let (s1, r1) = parse(s.slice_from(1)); | |
| 31 | (s1, RRep(~r1)) }, | |
| 32 | c => (s.slice_from(1), RChar(c)), | |
| 33 | } | |
| 34 | } | |
| 35 | ||
| 36 | /* Compiling an AST for regexps to the instructions */ | |
| 37 | fn emit(r: &Regexp, i: uint) -> (uint, ~[Instr]) { | |
| 38 | match *r { | |
| 39 | RChar(c) => { (i+1, ~[IChar(c)]) }, | |
| 40 | RSeq(ref a, ref b) => | |
| 41 | { let (ai, v1) = emit(*a, i); | |
| 42 | let (bi, v2) = emit(*b, ai); | |
| 43 | (bi, append(v1, v2)) }, | |
| 44 | RChc(ref a, ref b) => | |
| 45 | { let (ai, v1) = emit(*a, i + 1); | |
| 46 | let (bi, v2) = emit(*b, ai + 1); | |
| 47 | let spl = ~[ ISplit(i + 1, ai + 1) ]; | |
| 48 | let jmp = ~[ IJmp(ai) ]; | |
| 49 | (bi, append(spl, append(v1, append(jmp, v2)))) }, | |
| 50 | RRep(ref a) => | |
| 51 | { let (ai, v1) = emit(*a, i + 1); | |
| 52 | let spl = ~[ ISplit(i + 1, ai + 1) ]; | |
| 53 | let jmp = ~[ IJmp(i) ]; | |
| 54 | (ai + 1, append(spl, append(v1, jmp))) }, | |
| 55 | } | |
| 56 | } | |
| 57 | ||
| 58 | /* A wrapper over these processes */ | |
| 59 | pub fn compile(s: &str) -> ~[Instr] { | |
| 60 | let (_, re) = parse(s); | |
| 61 | println!("{:?}", re); | |
| 62 | let (_, ins) = emit(&re, 0); | |
| 63 | println!("{:?}", ins); | |
| 64 | return append(ins, [IMatch]); | |
| 65 | } |
| 1 | /* A single instruction as used in the VM-based matcher */ | |
| 2 | #[deriving(Clone)] | |
| 3 | pub enum Instr { | |
| 4 | IChar(char), /* match a character or fail */ | |
| 5 | IMatch, /* match anything successfully */ | |
| 6 | IJmp(uint) , /* jump to instr i */ | |
| 7 | ISplit(uint, uint), /* try both instrs i and j */ | |
| 8 | } |
| 1 | pub use re::compile::compile; | |
| 2 | pub use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
| 3 | pub use re::recursive::eval; | |
| 4 | pub use re::stack::eval; | |
| 5 | pub mod compile; | |
| 6 | pub mod instruction; | |
| 7 | pub mod recursive; | |
| 8 | pub mod stack; |
| 1 | use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
| 2 | mod instruction; | |
| 3 | ||
| 4 | /* We wrap the real evaluation function, as we're always going to | |
| 5 | * start executing instruction 0 with no string matched. */ | |
| 6 | pub fn eval(instrs: &[Instr], input: &str) -> bool { | |
| 7 | eval1(instrs, input, 0, 0) | |
| 8 | } | |
| 9 | ||
| 10 | /* We use the Rust stack as our stack in this naive recursive | |
| 11 | * implementation. */ | |
| 12 | fn eval1(instrs: &[Instr], input: &str, pc: uint, cc: uint) -> bool { | |
| 13 | match instrs[pc] { | |
| 14 | IChar(_) if cc >= input.len() => return false, | |
| 15 | IChar(c) if c == input.char_at(cc) => | |
| 16 | eval1(instrs, input, pc + 1, cc + 1), | |
| 17 | IChar(_) => return false, | |
| 18 | IMatch => return true, | |
| 19 | IJmp(i) => eval1(instrs, input, i, cc), | |
| 20 | ISplit(i, _) if eval1(instrs, input, i, cc) => true, | |
| 21 | ISplit(_, j) => eval1(instrs, input, j, cc), | |
| 22 | } | |
| 23 | } |
| 1 | use re::instruction::{Instr,IChar,IMatch,IJmp,ISplit}; | |
| 2 | mod instruction; | |
| 3 | ||
| 4 | /* The state of a program can be unambiguously specified by | |
| 5 | * a current instruction and a current position in the string. */ | |
| 6 | struct EvalState { pc: uint, cc: uint } | |
| 7 | ||
| 8 | /* An evaluator that maintains a manual, mutable stack for doing | |
| 9 | * regular-expression matching. */ | |
| 10 | pub fn eval(instrs: &[Instr], input: &str) -> bool { | |
| 11 | let mut stack = ~[ EvalState {pc: 0, cc: 0} ]; | |
| 12 | ||
| 13 | while stack.len() > 0 { | |
| 14 | let st = stack.pop(); | |
| 15 | match instrs[st.pc] { | |
| 16 | IChar(_) if st.cc >= input.len() => | |
| 17 | continue, | |
| 18 | IChar(c) if c == input.char_at(st.cc) => | |
| 19 | stack.push(EvalState { pc: st.pc + 1, cc: st.cc + 1 }), | |
| 20 | IChar(_) => | |
| 21 | continue, | |
| 22 | IMatch => | |
| 23 | return true, | |
| 24 | IJmp(i) => | |
| 25 | stack.push(EvalState { pc: i, cc: st.cc }), | |
| 26 | ISplit(i, j) => { | |
| 27 | stack.push(EvalState { pc: j, cc: st.cc }); | |
| 28 | stack.push(EvalState { pc: i, cc: st.cc }); | |
| 29 | }, | |
| 30 | } | |
| 31 | } | |
| 32 | return false; | |
| 33 | } |
| 1 | DEPS="regexp.rs re/compile.rs re/instruction.rs re/mod.rs re/recursive.rs re/stack.rs" | |
| 2 | redo-ifchange $DEPS | |
| 3 | rustc regexp.rs -o $3 |
| 1 | /* This is a basic implementation of a regular expression matcher, | |
| 2 | * based on Henry Spencer's virtual-machine approach to regular | |
| 3 | * expression matching outlined by Russ Cox here: | |
| 4 | * http://swtch.com/~rsc/regexp/regexp2.html | |
| 5 | * | |
| 6 | * For ease of parsing, I'm using a highly non-standard Polish | |
| 7 | * notation for regular expressions, in which . and | are | |
| 8 | * prefix binary operators for catenation and choice, respectively, | |
| 9 | * and * is a prefix unary operator for repetition. */ | |
| 10 | use re::compile; | |
| 11 | mod re; | |
| 12 | ||
| 13 | fn main() { | |
| 14 | /* our sample regexp corresponds to /ab*c/ in | |
| 15 | * the usual notation. */ | |
| 16 | let re = compile("..a*bc"); | |
| 17 | println("Recursive:"); | |
| 18 | println!(" match(re, \"abbbc\")\t== {}", | |
| 19 | ::re::recursive::eval(re, "abbbc")); | |
| 20 | println!(" match(re, \"ac\")\t== {}", | |
| 21 | ::re::recursive::eval(re, "ac")); | |
| 22 | println!(" match(re, \"abd\")\t== {}", | |
| 23 | ::re::recursive::eval(re, "abd")); | |
| 24 | println("Manual Stack:"); | |
| 25 | println!(" match(re, \"abbbc\")\t== {}", | |
| 26 | ::re::stack::eval(re, "abbbc")); | |
| 27 | println!(" match(re, \"ac\")\t== {}", | |
| 28 | ::re::stack::eval(re, "ac")); | |
| 29 | println!(" match(re, \"abd\")\t== {}", | |
| 30 | ::re::stack::eval(re, "abd")); | |
| 31 | } |