auto merge of #4891 : nikomatsakis/rust/region-syntax, r=nikomatsakis
r? @graydon
This commit is contained in:
commit
2782202201
@ -7,7 +7,6 @@
|
||||
|
||||
(require 'cm-mode)
|
||||
(require 'cc-mode)
|
||||
(eval-when-compile (require 'cl))
|
||||
|
||||
(defun rust-electric-brace (arg)
|
||||
(interactive "*P")
|
||||
@ -17,6 +16,12 @@
|
||||
'(font-lock-comment-face font-lock-string-face))))
|
||||
(cm-indent)))
|
||||
|
||||
(defcustom rust-capitalized-idents-are-types t
|
||||
"If non-nil, capitalized identifiers will be treated as types for the purposes of font-lock mode"
|
||||
:type 'boolean
|
||||
:require 'rust-mode
|
||||
:group 'rust-mode)
|
||||
|
||||
(defvar rust-indent-unit 4)
|
||||
(defvar rust-syntax-table (let ((table (make-syntax-table)))
|
||||
(c-populate-syntax-table table)
|
||||
@ -101,14 +106,7 @@
|
||||
(rust-push-context st 'string (current-column) t)
|
||||
(setf (rust-state-tokenize st) 'rust-token-string)
|
||||
(rust-token-string st))
|
||||
(def ?\' (forward-char)
|
||||
(setf rust-tcat 'atom)
|
||||
(let ((is-escape (eq (char-after) ?\\))
|
||||
(start (point)))
|
||||
(if (not (rust-eat-until-unescaped ?\'))
|
||||
'font-lock-warning-face
|
||||
(if (or is-escape (= (point) (+ start 2)))
|
||||
'font-lock-string-face 'font-lock-warning-face))))
|
||||
(def ?\' (rust-single-quote))
|
||||
(def ?/ (forward-char)
|
||||
(case (char-after)
|
||||
(?/ (end-of-line) 'font-lock-comment-face)
|
||||
@ -122,12 +120,7 @@
|
||||
((rust-eat-re "[a-z_]+") (setf rust-tcat 'macro)))
|
||||
'font-lock-preprocessor-face)
|
||||
(def ((?a . ?z) (?A . ?Z) ?_)
|
||||
(rust-eat-re "[a-zA-Z_][a-zA-Z0-9_]*")
|
||||
(setf rust-tcat 'ident)
|
||||
(if (and (eq (char-after) ?:) (eq (char-after (+ (point) 1)) ?:)
|
||||
(not (eq (char-after (+ (point) 2)) ?:)))
|
||||
(progn (forward-char 2) 'font-lock-builtin-face)
|
||||
(match-string 0)))
|
||||
(rust-token-identifier))
|
||||
(def ((?0 . ?9))
|
||||
(rust-eat-re "0x[0-9a-fA-F_]+\\|0b[01_]+\\|[0-9_]+\\(\\.[0-9_]+\\)?\\(e[+\\-]?[0-9_]+\\)?")
|
||||
(setf rust-tcat 'atom)
|
||||
@ -150,6 +143,31 @@
|
||||
(setf rust-tcat 'op) nil)
|
||||
table)))
|
||||
|
||||
(defun rust-token-identifier ()
|
||||
(rust-eat-re "[a-zA-Z_][a-zA-Z0-9_]*")
|
||||
(setf rust-tcat 'ident)
|
||||
(if (and (eq (char-after) ?:) (eq (char-after (+ (point) 1)) ?:)
|
||||
(not (eq (char-after (+ (point) 2)) ?:)))
|
||||
(progn (forward-char 2) 'font-lock-builtin-face)
|
||||
(match-string 0)))
|
||||
|
||||
(defun rust-single-quote ()
|
||||
(forward-char)
|
||||
(setf rust-tcat 'atom)
|
||||
; Is this a lifetime?
|
||||
(if (or (looking-at "[a-zA-Z_]$")
|
||||
(looking-at "[a-zA-Z_][^']"))
|
||||
; If what we see is 'abc, use font-lock-builtin-face:
|
||||
(progn (rust-eat-re "[a-zA-Z_][a-zA-Z_0-9]*")
|
||||
'font-lock-builtin-face)
|
||||
; Otherwise, handle as a character constant:
|
||||
(let ((is-escape (eq (char-after) ?\\))
|
||||
(start (point)))
|
||||
(if (not (rust-eat-until-unescaped ?\'))
|
||||
'font-lock-warning-face
|
||||
(if (or is-escape (= (point) (+ start 2)))
|
||||
'font-lock-string-face 'font-lock-warning-face)))))
|
||||
|
||||
(defun rust-token-base (st)
|
||||
(funcall (char-table-range rust-char-table (char-after)) st))
|
||||
|
||||
@ -190,6 +208,10 @@
|
||||
(dolist (cx (rust-state-context st))
|
||||
(when (eq (rust-context-type cx) ?\}) (return (rust-context-info cx)))))
|
||||
|
||||
(defun rust-is-capitalized (string)
|
||||
(let ((case-fold-search nil))
|
||||
(string-match-p "[A-Z]" string)))
|
||||
|
||||
(defun rust-token (st)
|
||||
(let ((cx (car (rust-state-context st))))
|
||||
(when (bolp)
|
||||
@ -206,6 +228,8 @@
|
||||
(setf tok (cond ((eq tok-id 'atom) 'font-lock-constant-face)
|
||||
(tok-id 'font-lock-keyword-face)
|
||||
((equal (rust-state-last-token st) 'def) 'font-lock-function-name-face)
|
||||
((and rust-capitalized-idents-are-types
|
||||
(rust-is-capitalized tok)) 'font-lock-type-face)
|
||||
(t nil))))
|
||||
(when rust-tcat
|
||||
(when (eq (rust-context-align cx) 'unset)
|
||||
|
@ -67,6 +67,12 @@ pub impl to_bytes::IterBytes for ident {
|
||||
// Functions may or may not have names.
|
||||
pub type fn_ident = Option<ident>;
|
||||
|
||||
pub struct Lifetime {
|
||||
id: node_id,
|
||||
span: span,
|
||||
ident: ident
|
||||
}
|
||||
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
#[deriving_eq]
|
||||
|
@ -307,12 +307,12 @@ fn parse_ty_bare_fn() -> ty_
|
||||
{
|
||||
/*
|
||||
|
||||
extern "ABI" [pure|unsafe] fn (S) -> T
|
||||
^~~~^ ^~~~~~~~~~~~^ ^~^ ^
|
||||
| | | |
|
||||
| | | Return type
|
||||
| | Argument types
|
||||
| |
|
||||
extern "ABI" [pure|unsafe] fn <'lt> (S) -> T
|
||||
^~~~^ ^~~~~~~~~~~~^ ^~~~^ ^~^ ^
|
||||
| | | | |
|
||||
| | | | Return type
|
||||
| | | Argument types
|
||||
| | Lifetimes
|
||||
| |
|
||||
| Purity
|
||||
ABI
|
||||
@ -333,12 +333,12 @@ fn parse_ty_closure(pre_sigil: Option<ast::Sigil>,
|
||||
{
|
||||
/*
|
||||
|
||||
(&|~|@) [r/] [pure|unsafe] [once] fn (S) -> T
|
||||
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~^ ^
|
||||
| | | | | |
|
||||
| | | | | Return type
|
||||
| | | | Argument types
|
||||
| | | |
|
||||
(&|~|@) [r/] [pure|unsafe] [once] fn <'lt> (S) -> T
|
||||
^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~^ ^~^ ^
|
||||
| | | | | | |
|
||||
| | | | | | Return type
|
||||
| | | | | Argument types
|
||||
| | | | Lifetimes
|
||||
| | | Once-ness (a.k.a., affine)
|
||||
| | Purity
|
||||
| Lifetime bound
|
||||
@ -394,12 +394,24 @@ fn parse_purity() -> purity {
|
||||
}
|
||||
|
||||
fn parse_ty_fn_decl() -> fn_decl {
|
||||
let inputs = do self.parse_unspanned_seq(
|
||||
token::LPAREN, token::RPAREN,
|
||||
seq_sep_trailing_disallowed(token::COMMA)) |p| {
|
||||
/*
|
||||
|
||||
p.parse_arg_general(false)
|
||||
};
|
||||
(fn) <'lt> (S) -> T
|
||||
^~~~^ ^~^ ^
|
||||
| | |
|
||||
| | Return type
|
||||
| Argument types
|
||||
Lifetimes
|
||||
|
||||
*/
|
||||
if self.eat(token::LT) {
|
||||
let _lifetimes = self.parse_lifetimes();
|
||||
self.expect(token::GT);
|
||||
}
|
||||
let inputs = self.parse_unspanned_seq(
|
||||
token::LPAREN, token::RPAREN,
|
||||
seq_sep_trailing_disallowed(token::COMMA),
|
||||
|p| p.parse_arg_general(false));
|
||||
let (ret_style, ret_ty) = self.parse_ret_ty();
|
||||
ast::fn_decl { inputs: inputs, output: ret_ty, cf: ret_style }
|
||||
}
|
||||
@ -624,8 +636,13 @@ fn parse_box_or_uniq_pointee(
|
||||
sigil: ast::Sigil,
|
||||
ctor: &fn(+v: mt) -> ty_) -> ty_
|
||||
{
|
||||
// @foo/fn() or @fn() are parsed directly as fn types:
|
||||
// @'foo fn() or @foo/fn() or @fn() are parsed directly as fn types:
|
||||
match copy self.token {
|
||||
token::LIFETIME(rname) => {
|
||||
self.bump();
|
||||
return self.parse_ty_closure(Some(sigil), Some(rname));
|
||||
}
|
||||
|
||||
token::IDENT(rname, _) => {
|
||||
if self.look_ahead(1u) == token::BINOP(token::SLASH) &&
|
||||
self.token_is_closure_keyword(self.look_ahead(2u))
|
||||
@ -648,8 +665,13 @@ fn parse_box_or_uniq_pointee(
|
||||
}
|
||||
|
||||
fn parse_borrowed_pointee() -> ty_ {
|
||||
// look for `&foo/` and interpret `foo` as the region name:
|
||||
let rname = match copy self.token {
|
||||
// look for `&'lt` or `&foo/` and interpret `foo` as the region name:
|
||||
let rname = match self.token {
|
||||
token::LIFETIME(sid) => {
|
||||
self.bump();
|
||||
Some(sid)
|
||||
}
|
||||
|
||||
token::IDENT(sid, _) => {
|
||||
if self.look_ahead(1u) == token::BINOP(token::SLASH) {
|
||||
self.bump(); self.bump();
|
||||
@ -658,6 +680,7 @@ fn parse_borrowed_pointee() -> ty_ {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
_ => { None }
|
||||
};
|
||||
|
||||
@ -890,22 +913,95 @@ fn parse_path_with_tps(colons: bool) -> @path {
|
||||
}
|
||||
};
|
||||
|
||||
// Parse any type parameters which may appear:
|
||||
// Parse any lifetime or type parameters which may appear:
|
||||
let tps = {
|
||||
if self.token == token::LT {
|
||||
self.parse_seq_lt_gt(Some(token::COMMA),
|
||||
|p| p.parse_ty(false))
|
||||
if !self.eat(token::LT) {
|
||||
~[]
|
||||
} else {
|
||||
codemap::spanned {node: ~[], span: path.span}
|
||||
// First consume lifetimes.
|
||||
let _lifetimes = self.parse_lifetimes();
|
||||
let result = self.parse_seq_to_gt(
|
||||
Some(token::COMMA),
|
||||
|p| p.parse_ty(false));
|
||||
result
|
||||
}
|
||||
};
|
||||
|
||||
@ast::path { span: mk_sp(lo, tps.span.hi),
|
||||
let hi = self.span.lo;
|
||||
|
||||
@ast::path { span: mk_sp(lo, hi),
|
||||
rp: rp,
|
||||
types: tps.node,
|
||||
types: tps,
|
||||
.. *path }
|
||||
}
|
||||
|
||||
fn parse_opt_lifetime() -> Option<ast::Lifetime> {
|
||||
/*!
|
||||
*
|
||||
* Parses 0 or 1 lifetime.
|
||||
*/
|
||||
|
||||
match self.token {
|
||||
token::LIFETIME(_) => {
|
||||
Some(self.parse_lifetime())
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_lifetime() -> ast::Lifetime {
|
||||
/*!
|
||||
*
|
||||
* Parses a single lifetime.
|
||||
*/
|
||||
|
||||
match self.token {
|
||||
token::LIFETIME(i) => {
|
||||
self.bump();
|
||||
return ast::Lifetime {
|
||||
id: self.get_id(),
|
||||
span: self.span,
|
||||
ident: i
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
self.fatal(fmt!("Expected a lifetime name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_lifetimes() -> ~[ast::Lifetime] {
|
||||
/*!
|
||||
*
|
||||
* Parses zero or more comma separated lifetimes.
|
||||
* Expects each lifetime to be followed by either
|
||||
* a comma or `>`. Used when parsing type parameter
|
||||
* lists, where we expect something like `<'a, 'b, T>`.
|
||||
*/
|
||||
|
||||
let mut res = ~[];
|
||||
loop {
|
||||
match self.token {
|
||||
token::LIFETIME(_) => {
|
||||
res.push(self.parse_lifetime());
|
||||
}
|
||||
_ => {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
match self.token {
|
||||
token::COMMA => { self.bump();}
|
||||
token::GT => { return res; }
|
||||
_ => {
|
||||
self.fatal(~"expected `,` or `>` after lifetime name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_mutability() -> mutability {
|
||||
if self.eat_keyword(~"mut") {
|
||||
m_mutbl
|
||||
@ -1424,6 +1520,7 @@ fn parse_prefix_expr() -> @expr {
|
||||
}
|
||||
token::AND => {
|
||||
self.bump();
|
||||
let _lt = self.parse_opt_lifetime();
|
||||
let m = self.parse_mutability();
|
||||
let e = self.parse_prefix_expr();
|
||||
hi = e.span.hi;
|
||||
@ -2574,7 +2671,10 @@ fn parse_ty_param() -> ty_param {
|
||||
|
||||
fn parse_ty_params() -> ~[ty_param] {
|
||||
if self.eat(token::LT) {
|
||||
self.parse_seq_to_gt(Some(token::COMMA), |p| p.parse_ty_param())
|
||||
let _lifetimes = self.parse_lifetimes();
|
||||
self.parse_seq_to_gt(
|
||||
Some(token::COMMA),
|
||||
|p| p.parse_ty_param())
|
||||
} else { ~[] }
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,11 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn foo(a: int) {
|
||||
let _p: &static/int = &a; //~ ERROR illegal borrow
|
||||
let _p: &'static int = &a; //~ ERROR illegal borrow
|
||||
}
|
||||
|
||||
fn bar(a: int) {
|
||||
let _q: &blk/int = &a;
|
||||
let _q: &'blk int = &a;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -15,7 +15,7 @@ struct dog {
|
||||
impl dog {
|
||||
fn chase_cat() {
|
||||
for uint::range(0u, 10u) |_i| {
|
||||
let p: &static/mut uint = &mut self.food; //~ ERROR illegal borrow
|
||||
let p: &'static mut uint = &mut self.food; //~ ERROR illegal borrow
|
||||
*p = 3u;
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,10 @@
|
||||
// checked.
|
||||
|
||||
enum an_enum = ∫
|
||||
trait a_trait { fn foo() -> &self/int; }
|
||||
struct a_class { x:&self/int }
|
||||
trait a_trait {
|
||||
fn foo() -> &'self int;
|
||||
}
|
||||
struct a_class { x:&'self int }
|
||||
|
||||
fn a_fn1(e: an_enum/&a) -> an_enum/&b {
|
||||
return e; //~ ERROR mismatched types: expected `an_enum/&b` but found `an_enum/&a`
|
||||
|
@ -8,16 +8,17 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum yes0 {
|
||||
x3(&uint)
|
||||
enum yes0<'lt> {
|
||||
// This will eventually be legal (and in fact the only way):
|
||||
X3(&'lt uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
|
||||
}
|
||||
|
||||
enum yes1 {
|
||||
x4(&self/uint)
|
||||
X4(&'self uint)
|
||||
}
|
||||
|
||||
enum yes2 {
|
||||
x5(&foo/uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
|
||||
X5(&'foo uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -10,13 +10,13 @@
|
||||
|
||||
fn with<T>(t: T, f: fn(T)) { f(t) }
|
||||
|
||||
fn nested(x: &x/int) { // (1)
|
||||
fn nested<'x>(x: &'x int) { // (1)
|
||||
do with(
|
||||
fn&(x: &x/int, // Refers to the region `x` at (1)
|
||||
y: &y/int, // A fresh region `y` (2)
|
||||
z: fn(x: &x/int, // Refers to `x` at (1)
|
||||
y: &y/int, // Refers to `y` at (2)
|
||||
z: &z/int) -> &z/int) // A fresh region `z` (3)
|
||||
fn&(x: &'x int, // Refers to the region `x` at (1)
|
||||
y: &'y int, // A fresh region `y` (2)
|
||||
z: fn<'z>(x: &'x int, // Refers to `x` at (1)
|
||||
y: &'y int, // Refers to `y` at (2)
|
||||
z: &'z int) -> &'z int) // A fresh region `z` (3)
|
||||
-> &x/int {
|
||||
|
||||
if false { return z(x, y, x); }
|
||||
@ -29,13 +29,13 @@ fn nested(x: &x/int) { // (1)
|
||||
}
|
||||
) |foo| {
|
||||
|
||||
let a: &x/int = foo(x, x, |_x, _y, z| z );
|
||||
let b: &x/int = foo(x, a, |_x, _y, z| z );
|
||||
let c: &x/int = foo(a, a, |_x, _y, z| z );
|
||||
let a: &'x int = foo(x, x, |_x, _y, z| z );
|
||||
let b: &'x int = foo(x, a, |_x, _y, z| z );
|
||||
let c: &'x int = foo(a, a, |_x, _y, z| z );
|
||||
|
||||
let z = 3i;
|
||||
let d: &x/int = foo(x, x, |_x, _y, z| z );
|
||||
let e: &x/int = foo(x, &z, |_x, _y, z| z );
|
||||
let d: &'x int = foo(x, x, |_x, _y, z| z );
|
||||
let e: &'x int = foo(x, &z, |_x, _y, z| z );
|
||||
|
||||
// This would result in an error, but it is not reported by typeck
|
||||
// anymore but rather borrowck. Therefore, it doesn't end up
|
||||
|
@ -8,14 +8,16 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct Clam { chowder: &int }
|
||||
|
||||
trait get_chowder {
|
||||
fn get_chowder() -> &self/int;
|
||||
struct Clam<'self> {
|
||||
chowder: &'self int
|
||||
}
|
||||
|
||||
impl get_chowder for Clam {
|
||||
fn get_chowder() -> &self/int { return self.chowder; }
|
||||
trait get_chowder<'self> {
|
||||
fn get_chowder() -> &'self int;
|
||||
}
|
||||
|
||||
impl<'self> get_chowder<'self> for Clam<'self> {
|
||||
fn get_chowder() -> &'self int { return self.chowder; }
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
Loading…
Reference in New Issue
Block a user