Skip to content

Commit 2782202

Browse files
committed
auto merge of #4891 : nikomatsakis/rust/region-syntax, r=nikomatsakis
r? @graydon
2 parents 9ad8a1f + d3f3d07 commit 2782202

File tree

9 files changed

+203
-68
lines changed

9 files changed

+203
-68
lines changed

src/etc/emacs/rust-mode.el

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
(require 'cm-mode)
99
(require 'cc-mode)
10-
(eval-when-compile (require 'cl))
1110

1211
(defun rust-electric-brace (arg)
1312
(interactive "*P")
@@ -17,6 +16,12 @@
1716
'(font-lock-comment-face font-lock-string-face))))
1817
(cm-indent)))
1918

19+
(defcustom rust-capitalized-idents-are-types t
20+
"If non-nil, capitalized identifiers will be treated as types for the purposes of font-lock mode"
21+
:type 'boolean
22+
:require 'rust-mode
23+
:group 'rust-mode)
24+
2025
(defvar rust-indent-unit 4)
2126
(defvar rust-syntax-table (let ((table (make-syntax-table)))
2227
(c-populate-syntax-table table)
@@ -101,14 +106,7 @@
101106
(rust-push-context st 'string (current-column) t)
102107
(setf (rust-state-tokenize st) 'rust-token-string)
103108
(rust-token-string st))
104-
(def ?\' (forward-char)
105-
(setf rust-tcat 'atom)
106-
(let ((is-escape (eq (char-after) ?\\))
107-
(start (point)))
108-
(if (not (rust-eat-until-unescaped ?\'))
109-
'font-lock-warning-face
110-
(if (or is-escape (= (point) (+ start 2)))
111-
'font-lock-string-face 'font-lock-warning-face))))
109+
(def ?\' (rust-single-quote))
112110
(def ?/ (forward-char)
113111
(case (char-after)
114112
(?/ (end-of-line) 'font-lock-comment-face)
@@ -122,12 +120,7 @@
122120
((rust-eat-re "[a-z_]+") (setf rust-tcat 'macro)))
123121
'font-lock-preprocessor-face)
124122
(def ((?a . ?z) (?A . ?Z) ?_)
125-
(rust-eat-re "[a-zA-Z_][a-zA-Z0-9_]*")
126-
(setf rust-tcat 'ident)
127-
(if (and (eq (char-after) ?:) (eq (char-after (+ (point) 1)) ?:)
128-
(not (eq (char-after (+ (point) 2)) ?:)))
129-
(progn (forward-char 2) 'font-lock-builtin-face)
130-
(match-string 0)))
123+
(rust-token-identifier))
131124
(def ((?0 . ?9))
132125
(rust-eat-re "0x[0-9a-fA-F_]+\\|0b[01_]+\\|[0-9_]+\\(\\.[0-9_]+\\)?\\(e[+\\-]?[0-9_]+\\)?")
133126
(setf rust-tcat 'atom)
@@ -150,6 +143,31 @@
150143
(setf rust-tcat 'op) nil)
151144
table)))
152145

146+
(defun rust-token-identifier ()
147+
(rust-eat-re "[a-zA-Z_][a-zA-Z0-9_]*")
148+
(setf rust-tcat 'ident)
149+
(if (and (eq (char-after) ?:) (eq (char-after (+ (point) 1)) ?:)
150+
(not (eq (char-after (+ (point) 2)) ?:)))
151+
(progn (forward-char 2) 'font-lock-builtin-face)
152+
(match-string 0)))
153+
154+
(defun rust-single-quote ()
155+
(forward-char)
156+
(setf rust-tcat 'atom)
157+
; Is this a lifetime?
158+
(if (or (looking-at "[a-zA-Z_]$")
159+
(looking-at "[a-zA-Z_][^']"))
160+
; If what we see is 'abc, use font-lock-builtin-face:
161+
(progn (rust-eat-re "[a-zA-Z_][a-zA-Z_0-9]*")
162+
'font-lock-builtin-face)
163+
; Otherwise, handle as a character constant:
164+
(let ((is-escape (eq (char-after) ?\\))
165+
(start (point)))
166+
(if (not (rust-eat-until-unescaped ?\'))
167+
'font-lock-warning-face
168+
(if (or is-escape (= (point) (+ start 2)))
169+
'font-lock-string-face 'font-lock-warning-face)))))
170+
153171
(defun rust-token-base (st)
154172
(funcall (char-table-range rust-char-table (char-after)) st))
155173

@@ -190,6 +208,10 @@
190208
(dolist (cx (rust-state-context st))
191209
(when (eq (rust-context-type cx) ?\}) (return (rust-context-info cx)))))
192210

211+
(defun rust-is-capitalized (string)
212+
(let ((case-fold-search nil))
213+
(string-match-p "[A-Z]" string)))
214+
193215
(defun rust-token (st)
194216
(let ((cx (car (rust-state-context st))))
195217
(when (bolp)
@@ -206,6 +228,8 @@
206228
(setf tok (cond ((eq tok-id 'atom) 'font-lock-constant-face)
207229
(tok-id 'font-lock-keyword-face)
208230
((equal (rust-state-last-token st) 'def) 'font-lock-function-name-face)
231+
((and rust-capitalized-idents-are-types
232+
(rust-is-capitalized tok)) 'font-lock-type-face)
209233
(t nil))))
210234
(when rust-tcat
211235
(when (eq (rust-context-align cx) 'unset)

src/libsyntax/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ pub impl to_bytes::IterBytes for ident {
6767
// Functions may or may not have names.
6868
pub type fn_ident = Option<ident>;
6969
70+
pub struct Lifetime {
71+
id: node_id,
72+
span: span,
73+
ident: ident
74+
}
75+
7076
#[auto_encode]
7177
#[auto_decode]
7278
#[deriving_eq]

src/libsyntax/parse/parser.rs

Lines changed: 128 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,12 @@ pub impl Parser {
307307
{
308308
/*
309309
310-
extern "ABI" [pure|unsafe] fn (S) -> T
311-
^~~~^ ^~~~~~~~~~~~^ ^~^ ^
312-
| | | |
313-
| | | Return type
314-
| | Argument types
315-
| |
310+
extern "ABI" [pure|unsafe] fn <'lt> (S) -> T
311+
^~~~^ ^~~~~~~~~~~~^ ^~~~^ ^~^ ^
312+
| | | | |
313+
| | | | Return type
314+
| | | Argument types
315+
| | Lifetimes
316316
| |
317317
| Purity
318318
ABI
@@ -333,12 +333,12 @@ pub impl Parser {
333333
{
334334
/*
335335
336-
(&|~|@) [r/] [pure|unsafe] [once] fn (S) -> T
337-
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~^ ^
338-
| | | | | |
339-
| | | | | Return type
340-
| | | | Argument types
341-
| | | |
336+
(&|~|@) [r/] [pure|unsafe] [once] fn <'lt> (S) -> T
337+
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~^ ^~^ ^
338+
| | | | | | |
339+
| | | | | | Return type
340+
| | | | | Argument types
341+
| | | | Lifetimes
342342
| | | Once-ness (a.k.a., affine)
343343
| | Purity
344344
| Lifetime bound
@@ -394,12 +394,24 @@ pub impl Parser {
394394
}
395395
396396
fn parse_ty_fn_decl() -> fn_decl {
397-
let inputs = do self.parse_unspanned_seq(
398-
token::LPAREN, token::RPAREN,
399-
seq_sep_trailing_disallowed(token::COMMA)) |p| {
397+
/*
400398
401-
p.parse_arg_general(false)
402-
};
399+
(fn) <'lt> (S) -> T
400+
^~~~^ ^~^ ^
401+
| | |
402+
| | Return type
403+
| Argument types
404+
Lifetimes
405+
406+
*/
407+
if self.eat(token::LT) {
408+
let _lifetimes = self.parse_lifetimes();
409+
self.expect(token::GT);
410+
}
411+
let inputs = self.parse_unspanned_seq(
412+
token::LPAREN, token::RPAREN,
413+
seq_sep_trailing_disallowed(token::COMMA),
414+
|p| p.parse_arg_general(false));
403415
let (ret_style, ret_ty) = self.parse_ret_ty();
404416
ast::fn_decl { inputs: inputs, output: ret_ty, cf: ret_style }
405417
}
@@ -624,8 +636,13 @@ pub impl Parser {
624636
sigil: ast::Sigil,
625637
ctor: &fn(+v: mt) -> ty_) -> ty_
626638
{
627-
// @foo/fn() or @fn() are parsed directly as fn types:
639+
// @'foo fn() or @foo/fn() or @fn() are parsed directly as fn types:
628640
match copy self.token {
641+
token::LIFETIME(rname) => {
642+
self.bump();
643+
return self.parse_ty_closure(Some(sigil), Some(rname));
644+
}
645+
629646
token::IDENT(rname, _) => {
630647
if self.look_ahead(1u) == token::BINOP(token::SLASH) &&
631648
self.token_is_closure_keyword(self.look_ahead(2u))
@@ -648,8 +665,13 @@ pub impl Parser {
648665
}
649666

650667
fn parse_borrowed_pointee() -> ty_ {
651-
// look for `&foo/` and interpret `foo` as the region name:
652-
let rname = match copy self.token {
668+
// look for `&'lt` or `&foo/` and interpret `foo` as the region name:
669+
let rname = match self.token {
670+
token::LIFETIME(sid) => {
671+
self.bump();
672+
Some(sid)
673+
}
674+
653675
token::IDENT(sid, _) => {
654676
if self.look_ahead(1u) == token::BINOP(token::SLASH) {
655677
self.bump(); self.bump();
@@ -658,6 +680,7 @@ pub impl Parser {
658680
None
659681
}
660682
}
683+
661684
_ => { None }
662685
};
663686

@@ -890,22 +913,95 @@ pub impl Parser {
890913
}
891914
};
892915

893-
// Parse any type parameters which may appear:
916+
// Parse any lifetime or type parameters which may appear:
894917
let tps = {
895-
if self.token == token::LT {
896-
self.parse_seq_lt_gt(Some(token::COMMA),
897-
|p| p.parse_ty(false))
918+
if !self.eat(token::LT) {
919+
~[]
898920
} else {
899-
codemap::spanned {node: ~[], span: path.span}
921+
// First consume lifetimes.
922+
let _lifetimes = self.parse_lifetimes();
923+
let result = self.parse_seq_to_gt(
924+
Some(token::COMMA),
925+
|p| p.parse_ty(false));
926+
result
900927
}
901928
};
902929

903-
@ast::path { span: mk_sp(lo, tps.span.hi),
930+
let hi = self.span.lo;
931+
932+
@ast::path { span: mk_sp(lo, hi),
904933
rp: rp,
905-
types: tps.node,
934+
types: tps,
906935
.. *path }
907936
}
908937

938+
fn parse_opt_lifetime() -> Option<ast::Lifetime> {
939+
/*!
940+
*
941+
* Parses 0 or 1 lifetime.
942+
*/
943+
944+
match self.token {
945+
token::LIFETIME(_) => {
946+
Some(self.parse_lifetime())
947+
}
948+
_ => {
949+
None
950+
}
951+
}
952+
}
953+
954+
fn parse_lifetime() -> ast::Lifetime {
955+
/*!
956+
*
957+
* Parses a single lifetime.
958+
*/
959+
960+
match self.token {
961+
token::LIFETIME(i) => {
962+
self.bump();
963+
return ast::Lifetime {
964+
id: self.get_id(),
965+
span: self.span,
966+
ident: i
967+
};
968+
}
969+
_ => {
970+
self.fatal(fmt!("Expected a lifetime name"));
971+
}
972+
}
973+
}
974+
975+
fn parse_lifetimes() -> ~[ast::Lifetime] {
976+
/*!
977+
*
978+
* Parses zero or more comma separated lifetimes.
979+
* Expects each lifetime to be followed by either
980+
* a comma or `>`. Used when parsing type parameter
981+
* lists, where we expect something like `<'a, 'b, T>`.
982+
*/
983+
984+
let mut res = ~[];
985+
loop {
986+
match self.token {
987+
token::LIFETIME(_) => {
988+
res.push(self.parse_lifetime());
989+
}
990+
_ => {
991+
return res;
992+
}
993+
}
994+
995+
match self.token {
996+
token::COMMA => { self.bump();}
997+
token::GT => { return res; }
998+
_ => {
999+
self.fatal(~"expected `,` or `>` after lifetime name");
1000+
}
1001+
}
1002+
}
1003+
}
1004+
9091005
fn parse_mutability() -> mutability {
9101006
if self.eat_keyword(~"mut") {
9111007
m_mutbl
@@ -1424,6 +1520,7 @@ pub impl Parser {
14241520
}
14251521
token::AND => {
14261522
self.bump();
1523+
let _lt = self.parse_opt_lifetime();
14271524
let m = self.parse_mutability();
14281525
let e = self.parse_prefix_expr();
14291526
hi = e.span.hi;
@@ -2574,7 +2671,10 @@ pub impl Parser {
25742671

25752672
fn parse_ty_params() -> ~[ty_param] {
25762673
if self.eat(token::LT) {
2577-
self.parse_seq_to_gt(Some(token::COMMA), |p| p.parse_ty_param())
2674+
let _lifetimes = self.parse_lifetimes();
2675+
self.parse_seq_to_gt(
2676+
Some(token::COMMA),
2677+
|p| p.parse_ty_param())
25782678
} else { ~[] }
25792679
}
25802680

src/test/compile-fail/regions-addr-of-arg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
// except according to those terms.
1010

1111
fn foo(a: int) {
12-
let _p: &static/int = &a; //~ ERROR illegal borrow
12+
let _p: &'static int = &a; //~ ERROR illegal borrow
1313
}
1414

1515
fn bar(a: int) {
16-
let _q: &blk/int = &a;
16+
let _q: &'blk int = &a;
1717
}
1818

1919
fn main() {

src/test/compile-fail/regions-addr-of-upvar-self.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct dog {
1515
impl dog {
1616
fn chase_cat() {
1717
for uint::range(0u, 10u) |_i| {
18-
let p: &static/mut uint = &mut self.food; //~ ERROR illegal borrow
18+
let p: &'static mut uint = &mut self.food; //~ ERROR illegal borrow
1919
*p = 3u;
2020
}
2121
}

src/test/compile-fail/regions-bounds.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
// checked.
1414

1515
enum an_enum = &int;
16-
trait a_trait { fn foo() -> &self/int; }
17-
struct a_class { x:&self/int }
16+
trait a_trait {
17+
fn foo() -> &'self int;
18+
}
19+
struct a_class { x:&'self int }
1820

1921
fn a_fn1(e: an_enum/&a) -> an_enum/&b {
2022
return e; //~ ERROR mismatched types: expected `an_enum/&b` but found `an_enum/&a`

0 commit comments

Comments
 (0)