Skip to content

Commit 25dc59d

Browse files
committed
libsyntax: Parse and report errors for a few obsolete syntaxes
1 parent 2508c24 commit 25dc59d

File tree

5 files changed

+253
-14
lines changed

5 files changed

+253
-14
lines changed

src/libsyntax/parse.rs

+6
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ fn parse_crate_from_crate_file(input: &Path, cfg: ast::crate_cfg,
7878
cx, cdirs, &prefix, &companionmod);
7979
let mut hi = p.span.hi;
8080
p.expect(token::EOF);
81+
p.abort_if_errors();
8182
return @ast_util::respan(ast_util::mk_sp(lo, hi),
8283
{directives: cdirs,
8384
module: m,
@@ -100,6 +101,7 @@ fn parse_crate_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
100101
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
101102
codemap::fss_none, source);
102103
let r = p.parse_crate_mod(cfg);
104+
p.abort_if_errors();
103105
sess.chpos = rdr.chpos;
104106
sess.byte_pos = sess.byte_pos + rdr.pos;
105107
return r;
@@ -110,6 +112,7 @@ fn parse_expr_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
110112
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
111113
codemap::fss_none, source);
112114
let r = p.parse_expr();
115+
p.abort_if_errors();
113116
sess.chpos = rdr.chpos;
114117
sess.byte_pos = sess.byte_pos + rdr.pos;
115118
return r;
@@ -121,6 +124,7 @@ fn parse_item_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
121124
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
122125
codemap::fss_none, source);
123126
let r = p.parse_item(attrs);
127+
p.abort_if_errors();
124128
sess.chpos = rdr.chpos;
125129
sess.byte_pos = sess.byte_pos + rdr.pos;
126130
return r;
@@ -132,6 +136,7 @@ fn parse_stmt_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
132136
let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
133137
codemap::fss_none, source);
134138
let r = p.parse_stmt(attrs);
139+
p.abort_if_errors();
135140
sess.chpos = rdr.chpos;
136141
sess.byte_pos = sess.byte_pos + rdr.pos;
137142
return r;
@@ -149,6 +154,7 @@ fn parse_from_source_str<T>(f: fn (p: parser) -> T,
149154
if !p.reader.is_eof() {
150155
p.reader.fatal(~"expected end-of-string");
151156
}
157+
p.abort_if_errors();
152158
sess.chpos = rdr.chpos;
153159
sess.byte_pos = sess.byte_pos + rdr.pos;
154160
return r;

src/libsyntax/parse/obsolete.rs

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*!
2+
Support for parsing unsupported, old syntaxes, for the
3+
purpose of reporting errors. Parsing of these syntaxes
4+
is tested by compile-test/obsolete-syntax.rs.
5+
6+
Obsolete syntax that becomes too hard to parse can be
7+
removed.
8+
*/
9+
10+
use codemap::span;
11+
use ast::{expr, expr_lit, lit_nil};
12+
use ast_util::{respan};
13+
use token::token;
14+
15+
/// The specific types of unsupported syntax
16+
pub enum ObsoleteSyntax {
17+
ObsoleteLowerCaseKindBounds,
18+
ObsoleteLet,
19+
ObsoleteFieldTerminator,
20+
ObsoleteStructCtor,
21+
ObsoleteWith
22+
}
23+
24+
impl ObsoleteSyntax : cmp::Eq {
25+
pure fn eq(&&other: ObsoleteSyntax) -> bool {
26+
self as uint == other as uint
27+
}
28+
pure fn ne(&&other: ObsoleteSyntax) -> bool {
29+
!self.eq(other)
30+
}
31+
}
32+
33+
impl ObsoleteSyntax: to_bytes::IterBytes {
34+
#[inline(always)]
35+
fn iter_bytes(lsb0: bool, f: to_bytes::Cb) {
36+
(self as uint).iter_bytes(lsb0, f);
37+
}
38+
}
39+
40+
pub trait ObsoleteReporter {
41+
fn obsolete(sp: span, kind: ObsoleteSyntax);
42+
fn obsolete_expr(sp: span, kind: ObsoleteSyntax) -> @expr;
43+
}
44+
45+
impl parser : ObsoleteReporter {
46+
/// Reports an obsolete syntax non-fatal error.
47+
fn obsolete(sp: span, kind: ObsoleteSyntax) {
48+
let (kind_str, desc) = match kind {
49+
ObsoleteLowerCaseKindBounds => (
50+
"lower-case kind bounds",
51+
"the `send`, `copy`, `const`, and `owned` \
52+
kinds are represented as traits now, and \
53+
should be camel cased"
54+
),
55+
ObsoleteLet => (
56+
"`let` in field declaration",
57+
"declare fields as `field: Type`"
58+
),
59+
ObsoleteFieldTerminator => (
60+
"field declaration terminated with semicolon",
61+
"fields are now separated by commas"
62+
),
63+
ObsoleteStructCtor => (
64+
"struct constructor",
65+
"structs are now constructed with `MyStruct { foo: val }` \
66+
syntax. Structs with private fields cannot be created \
67+
outside of their defining module"
68+
),
69+
ObsoleteWith => (
70+
"with",
71+
"record update is done with `..`, e.g. \
72+
`MyStruct { foo: bar, .. baz }`"
73+
),
74+
};
75+
76+
self.report(sp, kind, kind_str, desc);
77+
}
78+
79+
// Reports an obsolete syntax non-fatal error, and returns
80+
// a placeholder expression
81+
fn obsolete_expr(sp: span, kind: ObsoleteSyntax) -> @expr {
82+
self.obsolete(sp, kind);
83+
self.mk_expr(sp.lo, sp.hi, expr_lit(@respan(sp, lit_nil)))
84+
}
85+
86+
priv fn report(sp: span, kind: ObsoleteSyntax, kind_str: &str,
87+
desc: &str) {
88+
self.span_err(sp, fmt!("obsolete syntax: %s", kind_str));
89+
90+
if !self.obsolete_set.contains_key(kind) {
91+
self.sess.span_diagnostic.handler().note(fmt!("%s", desc));
92+
self.obsolete_set.insert(kind, ());
93+
}
94+
}
95+
96+
fn token_is_obsolete_ident(ident: &str, token: token) -> bool {
97+
match token {
98+
token::IDENT(copy sid, _) => {
99+
str::eq_slice(*self.id_to_str(sid), ident)
100+
}
101+
_ => false
102+
}
103+
}
104+
105+
fn is_obsolete_ident(ident: &str) -> bool {
106+
self.token_is_obsolete_ident(ident, copy self.token)
107+
}
108+
109+
fn eat_obsolete_ident(ident: &str) -> bool {
110+
if self.is_obsolete_ident(ident) {
111+
self.bump();
112+
true
113+
} else {
114+
false
115+
}
116+
}
117+
118+
fn try_parse_obsolete_struct_ctor() -> bool {
119+
if self.eat_obsolete_ident("new") {
120+
self.obsolete(copy self.last_span, ObsoleteStructCtor);
121+
self.parse_fn_decl(|p| p.parse_arg());
122+
self.parse_block();
123+
true
124+
} else {
125+
false
126+
}
127+
}
128+
129+
fn try_parse_obsolete_with() -> bool {
130+
if self.token == token::COMMA
131+
&& self.token_is_obsolete_ident("with",
132+
self.look_ahead(1u)) {
133+
self.bump();
134+
}
135+
if self.eat_obsolete_ident("with") {
136+
self.obsolete(copy self.last_span, ObsoleteWith);
137+
self.parse_expr();
138+
true
139+
} else {
140+
false
141+
}
142+
}
143+
144+
}
145+

src/libsyntax/parse/parser.rs

+59-14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ use common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed,
1515
seq_sep_none, token_to_str};
1616
use dvec::DVec;
1717
use vec::{push};
18+
use obsolete::{
19+
ObsoleteReporter, ObsoleteSyntax,
20+
ObsoleteLowerCaseKindBounds, ObsoleteLet,
21+
ObsoleteFieldTerminator, ObsoleteStructCtor,
22+
ObsoleteWith
23+
};
1824
use ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
1925
bind_by_ref, bind_by_implicit_ref, bind_by_value, bind_by_move,
2026
bitand, bitor, bitxor, blk, blk_check_mode, bound_const,
@@ -208,7 +214,8 @@ fn parser(sess: parse_sess, cfg: ast::crate_cfg,
208214
restriction: UNRESTRICTED,
209215
quote_depth: 0u,
210216
keywords: token::keyword_table(),
211-
restricted_keywords: token::restricted_keyword_table()
217+
restricted_keywords: token::restricted_keyword_table(),
218+
obsolete_set: std::map::hashmap(),
212219
}
213220
}
214221

@@ -228,6 +235,9 @@ struct parser {
228235
interner: interner<@~str>,
229236
keywords: hashmap<~str, ()>,
230237
restricted_keywords: hashmap<~str, ()>,
238+
/// The set of seen errors about obsolete syntax. Used to suppress
239+
/// extra detail when the same error is seen twice
240+
obsolete_set: hashmap<ObsoleteSyntax, ()>,
231241

232242
drop {} /* do not copy the parser; its state is tied to outside state */
233243

@@ -276,6 +286,12 @@ struct parser {
276286
fn warn(m: ~str) {
277287
self.sess.span_diagnostic.span_warn(copy self.span, m)
278288
}
289+
fn span_err(sp: span, m: ~str) {
290+
self.sess.span_diagnostic.span_err(sp, m)
291+
}
292+
fn abort_if_errors() {
293+
self.sess.span_diagnostic.handler().abort_if_errors();
294+
}
279295
fn get_id() -> node_id { next_node_id(self.sess) }
280296

281297
pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
@@ -1004,24 +1020,28 @@ struct parser {
10041020
// It's a struct literal.
10051021
self.bump();
10061022
let mut fields = ~[];
1023+
let mut base = None;
10071024
vec::push(fields, self.parse_field(token::COLON));
10081025
while self.token != token::RBRACE {
1026+
1027+
if self.try_parse_obsolete_with() {
1028+
break;
1029+
}
1030+
10091031
self.expect(token::COMMA);
1010-
if self.token == token::RBRACE ||
1011-
self.token == token::DOTDOT {
1032+
1033+
if self.eat(token::DOTDOT) {
1034+
base = Some(self.parse_expr());
1035+
break;
1036+
}
1037+
1038+
if self.token == token::RBRACE {
10121039
// Accept an optional trailing comma.
10131040
break;
10141041
}
10151042
vec::push(fields, self.parse_field(token::COLON));
10161043
}
10171044

1018-
let base;
1019-
if self.eat(token::DOTDOT) {
1020-
base = Some(self.parse_expr());
1021-
} else {
1022-
base = None;
1023-
}
1024-
10251045
hi = pth.span.hi;
10261046
self.expect(token::RBRACE);
10271047
ex = expr_struct(pth, fields, base);
@@ -1664,6 +1684,10 @@ struct parser {
16641684
base = Some(self.parse_expr()); break;
16651685
}
16661686

1687+
if self.try_parse_obsolete_with() {
1688+
break;
1689+
}
1690+
16671691
self.expect(token::COMMA);
16681692
if self.token == token::RBRACE {
16691693
// record ends by an optional trailing comma
@@ -2281,12 +2305,22 @@ struct parser {
22812305
if is_ident(self.token) {
22822306
// XXX: temporary until kinds become traits
22832307
let maybe_bound = match self.token {
2284-
token::IDENT(sid, _) => {
2308+
token::IDENT(copy sid, _) => {
22852309
match *self.id_to_str(sid) {
22862310
~"Send" => Some(bound_send),
22872311
~"Copy" => Some(bound_copy),
22882312
~"Const" => Some(bound_const),
22892313
~"Owned" => Some(bound_owned),
2314+
2315+
~"send"
2316+
| ~"copy"
2317+
| ~"const"
2318+
| ~"owned" => {
2319+
self.obsolete(copy self.span,
2320+
ObsoleteLowerCaseKindBounds);
2321+
None
2322+
}
2323+
22902324
_ => None
22912325
}
22922326
}
@@ -2737,11 +2771,18 @@ struct parser {
27372771
}
27382772

27392773
fn parse_single_class_item(vis: visibility) -> @class_member {
2740-
if (self.token_is_keyword(~"mut", copy self.token) ||
2741-
!self.is_any_keyword(copy self.token)) &&
2742-
!self.token_is_pound_or_doc_comment(self.token) {
2774+
let obsolete_let = self.eat_obsolete_ident("let");
2775+
if obsolete_let { self.obsolete(copy self.last_span, ObsoleteLet) }
2776+
2777+
if (obsolete_let || self.token_is_keyword(~"mut", copy self.token) ||
2778+
!self.is_any_keyword(copy self.token)) &&
2779+
!self.token_is_pound_or_doc_comment(self.token) {
27432780
let a_var = self.parse_instance_var(vis);
27442781
match self.token {
2782+
token::SEMI => {
2783+
self.obsolete(copy self.span, ObsoleteFieldTerminator);
2784+
self.bump();
2785+
}
27452786
token::COMMA => {
27462787
self.bump();
27472788
}
@@ -2792,6 +2833,10 @@ struct parser {
27922833

27932834
let attrs = self.parse_outer_attributes();
27942835

2836+
if self.try_parse_obsolete_struct_ctor() {
2837+
return members(~[]);
2838+
}
2839+
27952840
if self.eat_keyword(~"drop") {
27962841
return self.parse_dtor(attrs);
27972842
}

src/libsyntax/syntax.rc

+3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ mod parse {
5252

5353
/// Routines the parser uses to classify AST nodes
5454
mod classify;
55+
56+
/// Reporting obsolete syntax
57+
mod obsolete;
5558
}
5659

5760
mod print {
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
fn f1<T: copy>() -> T { }
2+
//~^ ERROR obsolete syntax: lower-case kind bounds
3+
4+
fn f1<T: send>() -> T { }
5+
//~^ ERROR obsolete syntax: lower-case kind bounds
6+
7+
fn f1<T: const>() -> T { }
8+
//~^ ERROR obsolete syntax: lower-case kind bounds
9+
10+
fn f1<T: owned>() -> T { }
11+
//~^ ERROR obsolete syntax: lower-case kind bounds
12+
13+
struct s {
14+
let foo: (),
15+
//~^ ERROR obsolete syntax: `let` in field declaration
16+
bar: ();
17+
//~^ ERROR obsolete syntax: field declaration terminated with semicolon
18+
new() { }
19+
//~^ ERROR obsolete syntax: struct constructor
20+
}
21+
22+
fn obsolete_with() {
23+
struct S {
24+
foo: (),
25+
bar: (),
26+
}
27+
28+
let a = S { foo: (), bar: () };
29+
let b = S { foo: () with a };
30+
//~^ ERROR obsolete syntax: with
31+
let c = S { foo: (), with a };
32+
//~^ ERROR obsolete syntax: with
33+
let a = { foo: (), bar: () };
34+
let b = { foo: () with a };
35+
//~^ ERROR obsolete syntax: with
36+
let c = { foo: (), with a };
37+
//~^ ERROR obsolete syntax: with
38+
}
39+
40+
fn main() { }

0 commit comments

Comments
 (0)