diff options
| author | Brian Anderson <banderson@mozilla.com> | 2012-09-08 15:50:29 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2012-09-08 20:04:21 -0700 |
| commit | 25dc59dc59ee8026d978aa72e57649b529c548fb (patch) | |
| tree | 8eefb3cab9fd4ea1f863c2c932fc1fda24c869ab /src/libsyntax | |
| parent | 2508c2427652528e65cbc5d613fee09af498acbc (diff) | |
| download | rust-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.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/parse/obsolete.rs | 145 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 73 | ||||
| -rw-r--r-- | src/libsyntax/syntax.rc | 3 |
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 { |
