libsyntax: Parse and report errors for a few obsolete syntaxes
This commit is contained in:
parent
2508c24276
commit
25dc59dc59
5 changed files with 253 additions and 14 deletions
|
|
@ -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;
|
||||
|
|
|
|||
145
src/libsyntax/parse/obsolete.rs
Normal file
145
src/libsyntax/parse/obsolete.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ mod parse {
|
|||
|
||||
/// Routines the parser uses to classify AST nodes
|
||||
mod classify;
|
||||
|
||||
/// Reporting obsolete syntax
|
||||
mod obsolete;
|
||||
}
|
||||
|
||||
mod print {
|
||||
|
|
|
|||
40
src/test/compile-fail/obsolete-syntax.rs
Normal file
40
src/test/compile-fail/obsolete-syntax.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
fn f1<T: copy>() -> T { }
|
||||
//~^ ERROR obsolete syntax: lower-case kind bounds
|
||||
|
||||
fn f1<T: send>() -> T { }
|
||||
//~^ ERROR obsolete syntax: lower-case kind bounds
|
||||
|
||||
fn f1<T: const>() -> T { }
|
||||
//~^ ERROR obsolete syntax: lower-case kind bounds
|
||||
|
||||
fn f1<T: owned>() -> T { }
|
||||
//~^ ERROR obsolete syntax: lower-case kind bounds
|
||||
|
||||
struct s {
|
||||
let foo: (),
|
||||
//~^ ERROR obsolete syntax: `let` in field declaration
|
||||
bar: ();
|
||||
//~^ ERROR obsolete syntax: field declaration terminated with semicolon
|
||||
new() { }
|
||||
//~^ ERROR obsolete syntax: struct constructor
|
||||
}
|
||||
|
||||
fn obsolete_with() {
|
||||
struct S {
|
||||
foo: (),
|
||||
bar: (),
|
||||
}
|
||||
|
||||
let a = S { foo: (), bar: () };
|
||||
let b = S { foo: () with a };
|
||||
//~^ ERROR obsolete syntax: with
|
||||
let c = S { foo: (), with a };
|
||||
//~^ ERROR obsolete syntax: with
|
||||
let a = { foo: (), bar: () };
|
||||
let b = { foo: () with a };
|
||||
//~^ ERROR obsolete syntax: with
|
||||
let c = { foo: (), with a };
|
||||
//~^ ERROR obsolete syntax: with
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
Loading…
Add table
Add a link
Reference in a new issue