diff options
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/obsolete.rs | 145 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 73 |
2 files changed, 204 insertions, 14 deletions
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); } |
