auto merge of #4891 : nikomatsakis/rust/region-syntax, r=nikomatsakis

r? @graydon
This commit is contained in:
bors 2013-02-16 10:16:12 -08:00
commit 2782202201
9 changed files with 204 additions and 69 deletions

View File

@ -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)

View File

@ -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]

View File

@ -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 { ~[] }
}

View File

@ -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() {

View File

@ -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;
}
}

View File

@ -13,8 +13,10 @@
// checked.
enum an_enum = &int;
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`

View File

@ -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() {}

View File

@ -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

View File

@ -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() {