about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-09-08 15:50:29 -0700
committerBrian Anderson <banderson@mozilla.com>2012-09-08 20:04:21 -0700
commit25dc59dc59ee8026d978aa72e57649b529c548fb (patch)
tree8eefb3cab9fd4ea1f863c2c932fc1fda24c869ab /src/libsyntax
parent2508c2427652528e65cbc5d613fee09af498acbc (diff)
downloadrust-25dc59dc59ee8026d978aa72e57649b529c548fb.tar.gz
rust-25dc59dc59ee8026d978aa72e57649b529c548fb.zip
libsyntax: Parse and report errors for a few obsolete syntaxes
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/parse.rs6
-rw-r--r--src/libsyntax/parse/obsolete.rs145
-rw-r--r--src/libsyntax/parse/parser.rs73
-rw-r--r--src/libsyntax/syntax.rc3
4 files changed, 213 insertions, 14 deletions
diff --git a/src/libsyntax/parse.rs b/src/libsyntax/parse.rs
index 7190337a5ed..5d2e081354e 100644
--- a/src/libsyntax/parse.rs
+++ b/src/libsyntax/parse.rs
@@ -78,6 +78,7 @@ fn parse_crate_from_crate_file(input: &Path, cfg: ast::crate_cfg,
         cx, cdirs, &prefix, &companionmod);
     let mut hi = p.span.hi;
     p.expect(token::EOF);
+    p.abort_if_errors();
     return @ast_util::respan(ast_util::mk_sp(lo, hi),
                           {directives: cdirs,
                            module: m,
@@ -100,6 +101,7 @@ fn parse_crate_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
     let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
                                                   codemap::fss_none, source);
     let r = p.parse_crate_mod(cfg);
+    p.abort_if_errors();
     sess.chpos = rdr.chpos;
     sess.byte_pos = sess.byte_pos + rdr.pos;
     return r;
@@ -110,6 +112,7 @@ fn parse_expr_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
     let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
                                                   codemap::fss_none, source);
     let r = p.parse_expr();
+    p.abort_if_errors();
     sess.chpos = rdr.chpos;
     sess.byte_pos = sess.byte_pos + rdr.pos;
     return r;
@@ -121,6 +124,7 @@ fn parse_item_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
     let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
                                                   codemap::fss_none, source);
     let r = p.parse_item(attrs);
+    p.abort_if_errors();
     sess.chpos = rdr.chpos;
     sess.byte_pos = sess.byte_pos + rdr.pos;
     return r;
@@ -132,6 +136,7 @@ fn parse_stmt_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
     let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
                                                   codemap::fss_none, source);
     let r = p.parse_stmt(attrs);
+    p.abort_if_errors();
     sess.chpos = rdr.chpos;
     sess.byte_pos = sess.byte_pos + rdr.pos;
     return r;
@@ -149,6 +154,7 @@ fn parse_from_source_str<T>(f: fn (p: parser) -> T,
     if !p.reader.is_eof() {
         p.reader.fatal(~"expected end-of-string");
     }
+    p.abort_if_errors();
     sess.chpos = rdr.chpos;
     sess.byte_pos = sess.byte_pos + rdr.pos;
     return r;
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
new file mode 100644
index 00000000000..1a4c08747bf
--- /dev/null
+++ b/src/libsyntax/parse/obsolete.rs
@@ -0,0 +1,145 @@
+/*!
+Support for parsing unsupported, old syntaxes, for the
+purpose of reporting errors. Parsing of these syntaxes
+is tested by compile-test/obsolete-syntax.rs.
+
+Obsolete syntax that becomes too hard to parse can be
+removed.
+*/
+
+use codemap::span;
+use ast::{expr, expr_lit, lit_nil};
+use ast_util::{respan};
+use token::token;
+
+/// The specific types of unsupported syntax
+pub enum ObsoleteSyntax {
+    ObsoleteLowerCaseKindBounds,
+    ObsoleteLet,
+    ObsoleteFieldTerminator,
+    ObsoleteStructCtor,
+    ObsoleteWith
+}
+
+impl ObsoleteSyntax : cmp::Eq {
+    pure fn eq(&&other: ObsoleteSyntax) -> bool {
+        self as uint == other as uint
+    }
+    pure fn ne(&&other: ObsoleteSyntax) -> bool {
+        !self.eq(other)
+    }
+}
+
+impl ObsoleteSyntax: to_bytes::IterBytes {
+    #[inline(always)]
+    fn iter_bytes(lsb0: bool, f: to_bytes::Cb) {
+        (self as uint).iter_bytes(lsb0, f);
+    }
+}
+
+pub trait ObsoleteReporter {
+    fn obsolete(sp: span, kind: ObsoleteSyntax);
+    fn obsolete_expr(sp: span, kind: ObsoleteSyntax) -> @expr;
+}
+
+impl parser : ObsoleteReporter {
+    /// Reports an obsolete syntax non-fatal error.
+    fn obsolete(sp: span, kind: ObsoleteSyntax) {
+        let (kind_str, desc) = match kind {
+            ObsoleteLowerCaseKindBounds => (
+                "lower-case kind bounds",
+                "the `send`, `copy`, `const`, and `owned` \
+                 kinds are represented as traits now, and \
+                 should be camel cased"
+            ),
+            ObsoleteLet => (
+                "`let` in field declaration",
+                "declare fields as `field: Type`"
+            ),
+            ObsoleteFieldTerminator => (
+                "field declaration terminated with semicolon",
+                "fields are now separated by commas"
+            ),
+            ObsoleteStructCtor => (
+                "struct constructor",
+                "structs are now constructed with `MyStruct { foo: val }` \
+                 syntax. Structs with private fields cannot be created \
+                 outside of their defining module"
+            ),
+            ObsoleteWith => (
+                "with",
+                "record update is done with `..`, e.g. \
+                 `MyStruct { foo: bar, .. baz }`"
+            ),
+        };
+
+        self.report(sp, kind, kind_str, desc);
+    }
+
+    // Reports an obsolete syntax non-fatal error, and returns
+    // a placeholder expression
+    fn obsolete_expr(sp: span, kind: ObsoleteSyntax) -> @expr {
+        self.obsolete(sp, kind);
+        self.mk_expr(sp.lo, sp.hi, expr_lit(@respan(sp, lit_nil)))
+    }
+
+    priv fn report(sp: span, kind: ObsoleteSyntax, kind_str: &str,
+                   desc: &str) {
+        self.span_err(sp, fmt!("obsolete syntax: %s", kind_str));
+
+        if !self.obsolete_set.contains_key(kind) {
+            self.sess.span_diagnostic.handler().note(fmt!("%s", desc));
+            self.obsolete_set.insert(kind, ());
+        }
+    }
+
+    fn token_is_obsolete_ident(ident: &str, token: token) -> bool {
+        match token {
+            token::IDENT(copy sid, _) => {
+                str::eq_slice(*self.id_to_str(sid), ident)
+            }
+            _ => false
+        }
+    }
+
+    fn is_obsolete_ident(ident: &str) -> bool {
+        self.token_is_obsolete_ident(ident, copy self.token)
+    }
+
+    fn eat_obsolete_ident(ident: &str) -> bool {
+        if self.is_obsolete_ident(ident) {
+            self.bump();
+            true
+        } else {
+            false
+        }
+    }
+
+    fn try_parse_obsolete_struct_ctor() -> bool {
+        if self.eat_obsolete_ident("new") {
+            self.obsolete(copy self.last_span, ObsoleteStructCtor);
+            self.parse_fn_decl(|p| p.parse_arg());
+            self.parse_block();
+            true
+        } else {
+            false
+        }
+    }
+
+    fn try_parse_obsolete_with() -> bool {
+        if self.token == token::COMMA
+            && self.token_is_obsolete_ident("with",
+                                            self.look_ahead(1u)) {
+            self.bump();
+        }
+        if self.eat_obsolete_ident("with") {
+            self.obsolete(copy self.last_span, ObsoleteWith);
+            self.parse_expr();
+            true
+        } else {
+            false
+        }
+    }
+
+}
+
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a38cc701dc3..73ff35481d4 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -15,6 +15,12 @@ use common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed,
                 seq_sep_none, token_to_str};
 use dvec::DVec;
 use vec::{push};
+use obsolete::{
+    ObsoleteReporter, ObsoleteSyntax,
+    ObsoleteLowerCaseKindBounds, ObsoleteLet,
+    ObsoleteFieldTerminator, ObsoleteStructCtor,
+    ObsoleteWith
+};
 use ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
              bind_by_ref, bind_by_implicit_ref, bind_by_value, bind_by_move,
              bitand, bitor, bitxor, blk, blk_check_mode, bound_const,
@@ -208,7 +214,8 @@ fn parser(sess: parse_sess, cfg: ast::crate_cfg,
         restriction: UNRESTRICTED,
         quote_depth: 0u,
         keywords: token::keyword_table(),
-        restricted_keywords: token::restricted_keyword_table()
+        restricted_keywords: token::restricted_keyword_table(),
+        obsolete_set: std::map::hashmap(),
     }
 }
 
@@ -228,6 +235,9 @@ struct parser {
     interner: interner<@~str>,
     keywords: hashmap<~str, ()>,
     restricted_keywords: hashmap<~str, ()>,
+    /// The set of seen errors about obsolete syntax. Used to suppress
+    /// extra detail when the same error is seen twice
+    obsolete_set: hashmap<ObsoleteSyntax, ()>,
 
     drop {} /* do not copy the parser; its state is tied to outside state */
 
@@ -276,6 +286,12 @@ struct parser {
     fn warn(m: ~str) {
         self.sess.span_diagnostic.span_warn(copy self.span, m)
     }
+    fn span_err(sp: span, m: ~str) {
+        self.sess.span_diagnostic.span_err(sp, m)
+    }
+    fn abort_if_errors() {
+        self.sess.span_diagnostic.handler().abort_if_errors();
+    }
     fn get_id() -> node_id { next_node_id(self.sess) }
 
     pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
@@ -1004,24 +1020,28 @@ struct parser {
                     // It's a struct literal.
                     self.bump();
                     let mut fields = ~[];
+                    let mut base = None;
                     vec::push(fields, self.parse_field(token::COLON));
                     while self.token != token::RBRACE {
+
+                        if self.try_parse_obsolete_with() {
+                            break;
+                        }
+
                         self.expect(token::COMMA);
-                        if self.token == token::RBRACE ||
-                                self.token == token::DOTDOT {
+
+                        if self.eat(token::DOTDOT) {
+                            base = Some(self.parse_expr());
+                            break;
+                        }
+
+                        if self.token == token::RBRACE {
                             // Accept an optional trailing comma.
                             break;
                         }
                         vec::push(fields, self.parse_field(token::COLON));
                     }
 
-                    let base;
-                    if self.eat(token::DOTDOT) {
-                        base = Some(self.parse_expr());
-                    } else {
-                        base = None;
-                    }
-
                     hi = pth.span.hi;
                     self.expect(token::RBRACE);
                     ex = expr_struct(pth, fields, base);
@@ -1664,6 +1684,10 @@ struct parser {
                 base = Some(self.parse_expr()); break;
             }
 
+            if self.try_parse_obsolete_with() {
+                break;
+            }
+
             self.expect(token::COMMA);
             if self.token == token::RBRACE {
                 // record ends by an optional trailing comma
@@ -2281,12 +2305,22 @@ struct parser {
                 if is_ident(self.token) {
                     // XXX: temporary until kinds become traits
                     let maybe_bound = match self.token {
-                      token::IDENT(sid, _) => {
+                      token::IDENT(copy sid, _) => {
                         match *self.id_to_str(sid) {
                           ~"Send" => Some(bound_send),
                           ~"Copy" => Some(bound_copy),
                           ~"Const" => Some(bound_const),
                           ~"Owned" => Some(bound_owned),
+
+                          ~"send"
+                          | ~"copy"
+                          | ~"const"
+                          | ~"owned" => {
+                            self.obsolete(copy self.span,
+                                          ObsoleteLowerCaseKindBounds);
+                            None
+                          }
+
                           _ => None
                         }
                       }
@@ -2737,11 +2771,18 @@ struct parser {
     }
 
     fn parse_single_class_item(vis: visibility) -> @class_member {
-        if (self.token_is_keyword(~"mut", copy self.token) ||
-                !self.is_any_keyword(copy self.token)) &&
-                !self.token_is_pound_or_doc_comment(self.token) {
+        let obsolete_let = self.eat_obsolete_ident("let");
+        if obsolete_let { self.obsolete(copy self.last_span, ObsoleteLet) }
+
+        if (obsolete_let || self.token_is_keyword(~"mut", copy self.token) ||
+            !self.is_any_keyword(copy self.token)) &&
+            !self.token_is_pound_or_doc_comment(self.token) {
             let a_var = self.parse_instance_var(vis);
             match self.token {
+                token::SEMI => {
+                    self.obsolete(copy self.span, ObsoleteFieldTerminator);
+                    self.bump();
+                }
                 token::COMMA => {
                     self.bump();
                 }
@@ -2792,6 +2833,10 @@ struct parser {
 
         let attrs = self.parse_outer_attributes();
 
+        if self.try_parse_obsolete_struct_ctor() {
+            return members(~[]);
+        }
+
         if self.eat_keyword(~"drop") {
            return self.parse_dtor(attrs);
         }
diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc
index 09162eba8ba..a7b606dc2a2 100644
--- a/src/libsyntax/syntax.rc
+++ b/src/libsyntax/syntax.rc
@@ -52,6 +52,9 @@ mod parse {
 
     /// Routines the parser uses to classify AST nodes
     mod classify;
+
+    /// Reporting obsolete syntax
+    mod obsolete;
 }
 
 mod print {