Skip to content

Commit 25c81c0

Browse files
committed
Allow keywords and other words (null, new) as identifiers for objects
and property accessors
1 parent 0028029 commit 25c81c0

File tree

5 files changed

+171
-65
lines changed

5 files changed

+171
-65
lines changed

core/src/codegen.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,13 @@ impl Code for Statement {
642642
Statement::Expression {
643643
ref value,
644644
} => {
645-
gen.write(value);
645+
if value.is_allowed_as_bare_statement() {
646+
gen.write(value);
647+
} else {
648+
gen.write_byte(b'(');
649+
gen.write(value);
650+
gen.write_byte(b')');
651+
}
646652
gen.write_byte(b';');
647653
},
648654

core/src/grammar.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,16 @@ impl Expression {
367367
_ => false
368368
}
369369
}
370+
371+
#[inline]
372+
pub fn is_allowed_as_bare_statement(&self) -> bool {
373+
match *self {
374+
Expression::Object(_) => false,
375+
Expression::Function { .. } => false,
376+
377+
_ => true,
378+
}
379+
}
370380
}
371381

372382
impl From<&'static str> for Expression {

core/src/lexicon.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,51 @@ pub enum Token {
6565
Literal(Value),
6666
Template(TemplateKind),
6767
}
68+
69+
impl Token {
70+
pub fn as_word(&self) -> Option<&'static str> {
71+
use self::Token::*;
72+
use grammar::OperatorType::*;
73+
use grammar::Value::*;
74+
75+
match *self {
76+
Break => Some("break"),
77+
Do => Some("do"),
78+
Case => Some("case"),
79+
Else => Some("else"),
80+
Catch => Some("catch"),
81+
Export => Some("export"),
82+
Class => Some("class"),
83+
Extends => Some("extends"),
84+
Return => Some("return"),
85+
While => Some("while"),
86+
Finally => Some("finally"),
87+
Super => Some("super"),
88+
With => Some("with"),
89+
Continue => Some("continue"),
90+
For => Some("for"),
91+
Switch => Some("switch"),
92+
Yield => Some("yield"),
93+
Debugger => Some("debugger"),
94+
Function => Some("function"),
95+
This => Some("this"),
96+
Default => Some("default"),
97+
If => Some("if"),
98+
Throw => Some("throw"),
99+
Import => Some("import"),
100+
Try => Some("try"),
101+
Static => Some("static"),
102+
Operator(New) => Some("new"),
103+
Operator(Typeof) => Some("typeof"),
104+
Operator(Void) => Some("void"),
105+
Operator(Delete) => Some("delte"),
106+
Operator(Instanceof) => Some("instanceof"),
107+
Literal(True) => Some("true"),
108+
Literal(False) => Some("false"),
109+
Literal(Null) => Some("null"),
110+
Literal(Undefined) => Some("undefined"),
111+
112+
_ => None,
113+
}
114+
}
115+
}

core/src/parser.rs

Lines changed: 44 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -171,81 +171,49 @@ impl<'a> Parser<'a> {
171171

172172
#[inline]
173173
fn object_member(&mut self, token: Token) -> Result<ObjectMember> {
174-
Ok(match token {
175-
176-
Identifier(key) |
177-
Literal(Value::String(key)) |
178-
Literal(Value::Number(key)) => {
179-
174+
let key = match token {
175+
Identifier(key) => {
180176
match peek!(self) {
181-
Colon => {
182-
self.consume();
183-
let key = ObjectKey::Literal(key);
177+
Colon | ParenOpen => ObjectKey::Literal(key),
184178

185-
ObjectMember::Value {
186-
key: key,
187-
value: try!(self.expression(0)),
188-
}
189-
},
190-
191-
ParenOpen => {
192-
self.consume();
193-
let key = ObjectKey::Literal(key);
194-
195-
ObjectMember::Method {
196-
key: key,
197-
params: try!(self.parameter_list()),
198-
body: try!(self.block_body())
199-
}
200-
},
201-
202-
_ => ObjectMember::Shorthand {
179+
_ => return Ok(ObjectMember::Shorthand {
203180
key: key,
204-
}
181+
})
205182
}
206183
},
207-
Literal(Value::Binary(num)) => {
208-
let key = ObjectKey::Binary(num);
209-
match peek!(self) {
210-
Colon => {
211-
self.consume();
212-
213-
ObjectMember::Value {
214-
key: key,
215-
value: try!(self.expression(0)),
216-
}
217-
},
218-
219-
ParenOpen => {
220-
self.consume();
221184

222-
ObjectMember::Method {
223-
key: key,
224-
params: try!(self.parameter_list()),
225-
body: try!(self.block_body())
226-
}
227-
},
228-
229-
_ => unexpected_token!(self)
230-
}
231-
},
232185
BracketOpen => {
233186
let key = ObjectKey::Computed(try!(self.expression(0)));
234187

235188
expect!(self, BracketClose);
236189

237-
match next!(self) {
238-
Colon => ObjectMember::Value {
239-
key: key,
240-
value: try!(self.expression(0)),
241-
},
242-
ParenOpen => ObjectMember::Method {
243-
key: key,
244-
params: try!(self.parameter_list()),
245-
body: try!(self.block_body()),
246-
},
247-
_ => unexpected_token!(self)
190+
key
191+
},
192+
193+
Literal(Value::String(key)) => ObjectKey::Literal(key),
194+
195+
Literal(Value::Number(key)) => ObjectKey::Literal(key),
196+
197+
Literal(Value::Binary(num)) => ObjectKey::Binary(num),
198+
199+
_ => {
200+
// Allow word tokens such as "null" and "typeof" as identifiers
201+
match token.as_word() {
202+
Some(key) => ObjectKey::Literal(key.into()),
203+
None => unexpected_token!(self)
248204
}
205+
}
206+
};
207+
208+
Ok(match next!(self) {
209+
Colon => ObjectMember::Value {
210+
key: key,
211+
value: try!(self.expression(0)),
212+
},
213+
ParenOpen => ObjectMember::Method {
214+
key: key,
215+
params: try!(self.parameter_list()),
216+
body: try!(self.block_body()),
249217
},
250218
_ => unexpected_token!(self)
251219
})
@@ -358,7 +326,19 @@ impl<'a> Parser<'a> {
358326
operand: Box::new(left),
359327
},
360328

361-
Accessor => Expression::member(left, expect_identifier!(self)),
329+
Accessor => {
330+
let ident = match next!(self) {
331+
Identifier(ident) => ident,
332+
333+
// Allow word tokens such as "null" and "typeof" as identifiers
334+
token => match token.as_word() {
335+
Some(ident) => ident.into(),
336+
None => unexpected_token!(self)
337+
},
338+
};
339+
340+
Expression::member(left, ident)
341+
},
362342

363343
Conditional => Expression::Conditional {
364344
test: Box::new(left),

core/tests/parser.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,36 @@ fn object_hex_literal_member() {
807807
]));
808808
}
809809

810+
#[test]
811+
fn object_keyword_literal_member() {
812+
assert_expression!("({ function : 100})", Expression::Object(vec![
813+
ObjectMember::Value {
814+
key: ObjectKey::Literal("function".into()),
815+
value: num!("100"),
816+
}
817+
]));
818+
}
819+
820+
#[test]
821+
fn object_value_word_literal_member() {
822+
assert_expression!("({ true : 100})", Expression::Object(vec![
823+
ObjectMember::Value {
824+
key: ObjectKey::Literal("true".into()),
825+
value: num!("100"),
826+
}
827+
]));
828+
}
829+
830+
#[test]
831+
fn object_operator_word_literal_member() {
832+
assert_expression!("({ new : 100})", Expression::Object(vec![
833+
ObjectMember::Value {
834+
key: ObjectKey::Literal("new".into()),
835+
value: num!("100"),
836+
}
837+
]));
838+
}
839+
810840
#[test]
811841
fn object_computed_member() {
812842
assert_expression!("({[100]:100})", Expression::Object(vec![
@@ -859,6 +889,38 @@ fn object_number_method_member() {
859889
]));
860890
}
861891

892+
#[test]
893+
fn accesss_member_identifier() {
894+
assert_expression!("this.foo", Expression::Member {
895+
object: Box::new(Expression::This),
896+
property: "foo".into()
897+
})
898+
}
899+
900+
#[test]
901+
fn accesss_member_keyword() {
902+
assert_expression!("this.function", Expression::Member {
903+
object: Box::new(Expression::This),
904+
property: "function".into()
905+
})
906+
}
907+
908+
#[test]
909+
fn accesss_member_value_word() {
910+
assert_expression!("this.true", Expression::Member {
911+
object: Box::new(Expression::This),
912+
property: "true".into()
913+
})
914+
}
915+
916+
#[test]
917+
fn accesss_member_operator_word() {
918+
assert_expression!("this.new", Expression::Member {
919+
object: Box::new(Expression::This),
920+
property: "new".into()
921+
})
922+
}
923+
862924
#[test]
863925
fn class_statement() {
864926
assert_statement!("class Foo {}", Statement::Class {

0 commit comments

Comments
 (0)