Skip to content

Commit

Permalink
fix(es/parser): Re-lex << as two <-s if required (#7439)
Browse files Browse the repository at this point in the history
**Related issue:**

 - Closes #7187.
  • Loading branch information
kdy1 committed Jun 30, 2023
1 parent af3654c commit 6850372
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 7 deletions.
4 changes: 4 additions & 0 deletions crates/swc_ecma_parser/src/lexer/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ impl Tokens for Lexer<'_> {
fn take_errors(&mut self) -> Vec<Error> {
take(&mut self.errors.borrow_mut())
}

fn reset_to(&mut self, to: BytePos) {
self.input.reset_to(to);
}
}

impl<'a> Iterator for Lexer<'a> {
Expand Down
3 changes: 3 additions & 0 deletions crates/swc_ecma_parser/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ macro_rules! tok {
('>') => {
crate::token::Token::BinOp(crate::token::BinOpToken::Gt)
};
("<<") => {
crate::token::Token::BinOp(crate::token::BinOpToken::LShift)
};
(">>") => {
crate::token::Token::BinOp(crate::token::BinOpToken::RShift)
};
Expand Down
23 changes: 21 additions & 2 deletions crates/swc_ecma_parser/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -688,11 +688,12 @@ impl<I: Tokens> Parser<I> {
let obj = self.parse_primary_expr()?;
return_if_arrow!(self, obj);

let type_args = if self.syntax().typescript() && is!(self, '<') {
let type_args = if self.syntax().typescript() {
self.try_parse_ts_type_args()
} else {
None
};

let obj = if let Some(type_args) = type_args {
trace_cur!(self, parse_member_expr_or_new_expr__with_type_args);
Box::new(Expr::TsInstantiation(TsInstantiation {
Expand Down Expand Up @@ -1620,9 +1621,27 @@ impl<I: Tokens> Parser<I> {
let callee = self.parse_new_expr()?;
return_if_arrow!(self, callee);

let type_args = if self.input.syntax().typescript() && is!(self, '<') {
let type_args = if self.input.syntax().typescript() && is_one_of!(self, '<', "<<") {
let type_args_start = self.input.cur_pos();
self.try_parse_ts(|p| {
trace_cur!(p, parse_lhs_expr__type_args);

if is!(p, "<<") {
let ctx = Context {
should_not_lex_lt_or_gt_as_type: false,
in_type: true,
..p.ctx()
};
p.input.reset_to(type_args_start);
p.input.set_ctx(ctx);
}

trace_cur!(p, parse_lhs_expr__before_type_args);

let type_args = p.parse_ts_type_args()?;

trace_cur!(p, parse_lhs_expr__after_type_args);

if is!(p, '(') {
Ok(Some(type_args))
} else {
Expand Down
20 changes: 17 additions & 3 deletions crates/swc_ecma_parser/src/parser/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub trait Tokens: Clone + Iterator<Item = TokenAndSpan> {
fn add_module_mode_error(&self, error: Error);

fn take_errors(&mut self) -> Vec<Error>;

fn reset_to(&mut self, to: BytePos);
}

#[derive(Clone)]
Expand Down Expand Up @@ -141,6 +143,8 @@ impl Tokens for TokensInput {
fn take_errors(&mut self) -> Vec<Error> {
take(&mut self.errors.borrow_mut())
}

fn reset_to(&mut self, _: BytePos) {}
}

/// Note: Lexer need access to parser's context to lex correctly.
Expand Down Expand Up @@ -253,6 +257,10 @@ impl<I: Tokens> Tokens for Capturing<I> {
fn take_errors(&mut self) -> Vec<Error> {
self.inner.take_errors()
}

fn reset_to(&mut self, to: BytePos) {
self.inner.reset_to(to);
}
}

/// This struct is responsible for managing current token and peeked token.
Expand Down Expand Up @@ -318,9 +326,9 @@ impl<I: Tokens> Buffer<I> {

#[cold]
#[inline(never)]
pub fn dump_cur(&mut self) -> String {
match self.cur() {
Some(v) => format!("{:?}", v),
pub fn dump_cur(&self) -> String {
match &self.cur {
Some(v) => format!("{:?}", v.token),
None => "<eof>".to_string(),
}
}
Expand Down Expand Up @@ -494,4 +502,10 @@ impl<I: Tokens> Buffer<I> {
pub(crate) fn set_token_context(&mut self, c: lexer::TokenContexts) {
self.iter.set_token_context(c)
}

#[inline]
pub(crate) fn reset_to(&mut self, to: BytePos) {
self.cur = None;
self.iter.reset_to(to)
}
}
29 changes: 27 additions & 2 deletions crates/swc_ecma_parser/src/parser/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,9 @@ impl<I: Tokens> Parser<I> {
permit_in_out: bool,
permit_const: bool,
) -> PResult<Box<TsTypeParamDecl>> {
self.in_type().parse_with(|p| {
trace_cur!(self, parse_ts_type_params);

let ret = self.in_type().parse_with(|p| {
p.ts_in_no_context(|p| {
let start = cur_pos!(p);

Expand All @@ -483,7 +485,11 @@ impl<I: Tokens> Parser<I> {
params,
}))
})
})
})?;

trace_cur!(self, parse_ts_type_params__end);

Ok(ret)
}

/// `tsParseTypeOrTypePredicateAnnotation`
Expand Down Expand Up @@ -579,11 +585,25 @@ impl<I: Tokens> Parser<I> {

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
pub(super) fn try_parse_ts_type_args(&mut self) -> Option<Box<TsTypeParamInstantiation>> {
let start = self.input.cur_pos();

trace_cur!(self, try_parse_ts_type_args);
debug_assert!(self.input.syntax().typescript());

self.try_parse_ts(|p| {
let nested = is!(p, "<<");
if nested {
let ctx = Context {
should_not_lex_lt_or_gt_as_type: false,
in_type: true,
..p.ctx()
};
p.input.reset_to(start);
p.input.set_ctx(ctx);
}

let type_args = p.parse_ts_type_args()?;
trace_cur!(p, try_parse_ts_type_args__after_type_args);

if is_one_of!(
p, '<', // invalid syntax
Expand Down Expand Up @@ -1845,9 +1865,12 @@ impl<I: Tokens> Parser<I> {

// ----- inlined `self.tsFillSignature(tt.arrow, node)`
let type_params = self.try_parse_ts_type_params(false, true)?;
trace_cur!(self, parse_ts_fn_or_constructor_type__after_type_params);
expect!(self, '(');
let params = self.parse_ts_binding_list_for_signature()?;
trace_cur!(self, parse_ts_fn_or_constructor_type__after_params);
let type_ann = self.parse_ts_type_or_type_predicate_ann(&tok!("=>"))?;
trace_cur!(self, parse_ts_fn_or_constructor_type__after_type_ann);
// ----- end

Ok(if is_fn_type {
Expand Down Expand Up @@ -2015,6 +2038,8 @@ impl<I: Tokens> Parser<I> {
permit_in_out: bool,
permit_const: bool,
) -> PResult<Option<Box<TsTypeParamDecl>>> {
trace_cur!(self, try_parse_ts_type_params);

if !cfg!(feature = "typescript") {
return Ok(None);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
assertType<<K>(key: K) => K>(foo);
169 changes: 169 additions & 0 deletions crates/swc_ecma_parser/tests/typescript/issue-7187/1/input.tsx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
{
"type": "Script",
"span": {
"start": 1,
"end": 35,
"ctxt": 0
},
"body": [
{
"type": "ExpressionStatement",
"span": {
"start": 1,
"end": 35,
"ctxt": 0
},
"expression": {
"type": "CallExpression",
"span": {
"start": 1,
"end": 34,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 1,
"end": 11,
"ctxt": 0
},
"value": "assertType",
"optional": false
},
"arguments": [
{
"spread": null,
"expression": {
"type": "Identifier",
"span": {
"start": 30,
"end": 33,
"ctxt": 0
},
"value": "foo",
"optional": false
}
}
],
"typeArguments": {
"type": "TsTypeParameterInstantiation",
"span": {
"start": 11,
"end": 29,
"ctxt": 0
},
"params": [
{
"type": "TsFunctionType",
"span": {
"start": 12,
"end": 28,
"ctxt": 0
},
"params": [
{
"type": "Identifier",
"span": {
"start": 16,
"end": 22,
"ctxt": 0
},
"value": "key",
"optional": false,
"typeAnnotation": {
"type": "TsTypeAnnotation",
"span": {
"start": 19,
"end": 22,
"ctxt": 0
},
"typeAnnotation": {
"type": "TsTypeReference",
"span": {
"start": 21,
"end": 22,
"ctxt": 0
},
"typeName": {
"type": "Identifier",
"span": {
"start": 21,
"end": 22,
"ctxt": 0
},
"value": "K",
"optional": false
},
"typeParams": null
}
}
}
],
"typeParams": {
"type": "TsTypeParameterDeclaration",
"span": {
"start": 12,
"end": 15,
"ctxt": 0
},
"parameters": [
{
"type": "TsTypeParameter",
"span": {
"start": 13,
"end": 14,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 13,
"end": 14,
"ctxt": 0
},
"value": "K",
"optional": false
},
"in": false,
"out": false,
"const": false,
"constraint": null,
"default": null
}
]
},
"typeAnnotation": {
"type": "TsTypeAnnotation",
"span": {
"start": 24,
"end": 28,
"ctxt": 0
},
"typeAnnotation": {
"type": "TsTypeReference",
"span": {
"start": 27,
"end": 28,
"ctxt": 0
},
"typeName": {
"type": "Identifier",
"span": {
"start": 27,
"end": 28,
"ctxt": 0
},
"value": "K",
"optional": false
},
"typeParams": null
}
}
}
]
}
}
}
],
"interpreter": null
}

1 comment on commit 6850372

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 6850372 Previous: 8209594 Ratio
es/full/bugs-1 319606 ns/iter (± 11061) 315750 ns/iter (± 13958) 1.01
es/full/minify/libraries/antd 1487421871 ns/iter (± 21970358) 1471254982 ns/iter (± 19865158) 1.01
es/full/minify/libraries/d3 315332774 ns/iter (± 1318431) 320576698 ns/iter (± 5464125) 0.98
es/full/minify/libraries/echarts 1204519126 ns/iter (± 11779301) 1204190652 ns/iter (± 5703973) 1.00
es/full/minify/libraries/jquery 96072159 ns/iter (± 249407) 95628019 ns/iter (± 455310) 1.00
es/full/minify/libraries/lodash 113708243 ns/iter (± 276221) 113855168 ns/iter (± 497710) 1.00
es/full/minify/libraries/moment 56453497 ns/iter (± 245827) 55933420 ns/iter (± 119350) 1.01
es/full/minify/libraries/react 20230332 ns/iter (± 39409) 20062804 ns/iter (± 83589) 1.01
es/full/minify/libraries/terser 246486216 ns/iter (± 1458266) 248761265 ns/iter (± 1738033) 0.99
es/full/minify/libraries/three 436841704 ns/iter (± 2400359) 436744123 ns/iter (± 3354347) 1.00
es/full/minify/libraries/typescript 2976193578 ns/iter (± 15302949) 2998120157 ns/iter (± 26755708) 0.99
es/full/minify/libraries/victory 645956633 ns/iter (± 4852461) 656448350 ns/iter (± 6698209) 0.98
es/full/minify/libraries/vue 138795766 ns/iter (± 4010764) 138417556 ns/iter (± 752295) 1.00
es/full/codegen/es3 35514 ns/iter (± 121) 36502 ns/iter (± 81) 0.97
es/full/codegen/es5 35595 ns/iter (± 324) 36713 ns/iter (± 395) 0.97
es/full/codegen/es2015 35519 ns/iter (± 73) 36520 ns/iter (± 102) 0.97
es/full/codegen/es2016 35872 ns/iter (± 109) 36498 ns/iter (± 79) 0.98
es/full/codegen/es2017 35971 ns/iter (± 90) 36514 ns/iter (± 71) 0.99
es/full/codegen/es2018 35793 ns/iter (± 62) 36460 ns/iter (± 124) 0.98
es/full/codegen/es2019 35831 ns/iter (± 84) 36480 ns/iter (± 71) 0.98
es/full/codegen/es2020 35576 ns/iter (± 86) 36511 ns/iter (± 201) 0.97
es/full/all/es3 185604954 ns/iter (± 717111) 181052054 ns/iter (± 775410) 1.03
es/full/all/es5 176539344 ns/iter (± 370649) 172523479 ns/iter (± 457823) 1.02
es/full/all/es2015 132414743 ns/iter (± 626192) 127777520 ns/iter (± 745884) 1.04
es/full/all/es2016 131549476 ns/iter (± 465315) 126583454 ns/iter (± 424793) 1.04
es/full/all/es2017 131116887 ns/iter (± 390749) 125786775 ns/iter (± 468371) 1.04
es/full/all/es2018 129044951 ns/iter (± 637528) 124187922 ns/iter (± 708529) 1.04
es/full/all/es2019 127749772 ns/iter (± 386056) 123655468 ns/iter (± 363510) 1.03
es/full/all/es2020 123631759 ns/iter (± 925418) 118404443 ns/iter (± 834184) 1.04
es/full/parser 562169 ns/iter (± 7025) 517161 ns/iter (± 6225) 1.09
es/full/base/fixer 18687 ns/iter (± 171) 20817 ns/iter (± 153) 0.90
es/full/base/resolver_and_hygiene 96903 ns/iter (± 225) 96414 ns/iter (± 234) 1.01
serialization of serde 296 ns/iter (± 0) 299 ns/iter (± 3) 0.99
css/minify/libraries/bootstrap 31013134 ns/iter (± 83054) 30949212 ns/iter (± 86644) 1.00
css/visitor/compare/clone 2129158 ns/iter (± 14906) 2128459 ns/iter (± 36371) 1.00
css/visitor/compare/visit_mut_span 2251441 ns/iter (± 16957) 2257352 ns/iter (± 35410) 1.00
css/visitor/compare/visit_mut_span_panic 2322416 ns/iter (± 5970) 2325287 ns/iter (± 14425) 1.00
css/visitor/compare/fold_span 3011796 ns/iter (± 20862) 2992943 ns/iter (± 22471) 1.01
css/visitor/compare/fold_span_panic 3209746 ns/iter (± 15199) 3174715 ns/iter (± 28237) 1.01
css/lexer/bootstrap_5_1_3 4688945 ns/iter (± 18162) 4688099 ns/iter (± 7648) 1.00
css/lexer/foundation_6_7_4 3963096 ns/iter (± 1523) 3969923 ns/iter (± 1771) 1.00
css/lexer/tailwind_3_1_1 755504 ns/iter (± 489) 753689 ns/iter (± 388) 1.00
css/parser/bootstrap_5_1_3 20443679 ns/iter (± 57054) 20717709 ns/iter (± 34749) 0.99
css/parser/foundation_6_7_4 16537735 ns/iter (± 16356) 16679197 ns/iter (± 30692) 0.99
css/parser/tailwind_3_1_1 3199810 ns/iter (± 2036) 3227127 ns/iter (± 7772) 0.99
es/codegen/colors 734759 ns/iter (± 398009) 734698 ns/iter (± 399125) 1.00
es/codegen/large 2980746 ns/iter (± 1563999) 2975791 ns/iter (± 1562809) 1.00
es/codegen/with-parser/colors 48858 ns/iter (± 252) 48869 ns/iter (± 233) 1.00
es/codegen/with-parser/large 522932 ns/iter (± 1565) 515253 ns/iter (± 1537) 1.01
es/minify/libraries/antd 1297008954 ns/iter (± 11765725) 1303743388 ns/iter (± 9036592) 0.99
es/minify/libraries/d3 280113756 ns/iter (± 1246219) 279583215 ns/iter (± 1447669) 1.00
es/minify/libraries/echarts 1038128881 ns/iter (± 6405924) 1043823063 ns/iter (± 6477272) 0.99
es/minify/libraries/jquery 83947014 ns/iter (± 103329) 83833670 ns/iter (± 146316) 1.00
es/minify/libraries/lodash 103036304 ns/iter (± 508208) 102924679 ns/iter (± 289054) 1.00
es/minify/libraries/moment 49529794 ns/iter (± 135102) 49244517 ns/iter (± 68491) 1.01
es/minify/libraries/react 18076046 ns/iter (± 56037) 17948476 ns/iter (± 169321) 1.01
es/minify/libraries/terser 213416812 ns/iter (± 1060162) 211516900 ns/iter (± 628385) 1.01
es/minify/libraries/three 373362419 ns/iter (± 31240543) 365643881 ns/iter (± 2409813) 1.02
es/minify/libraries/typescript 2554768851 ns/iter (± 19062383) 2525780943 ns/iter (± 10975100) 1.01
es/minify/libraries/victory 542881310 ns/iter (± 5297599) 542164571 ns/iter (± 3432721) 1.00
es/minify/libraries/vue 123525386 ns/iter (± 301004) 123852495 ns/iter (± 638928) 1.00
es/visitor/compare/clone 2125766 ns/iter (± 4102) 2092946 ns/iter (± 10121) 1.02
es/visitor/compare/visit_mut_span 2471050 ns/iter (± 4990) 2435221 ns/iter (± 8914) 1.01
es/visitor/compare/visit_mut_span_panic 2506858 ns/iter (± 10687) 2476574 ns/iter (± 5940) 1.01
es/visitor/compare/fold_span 3542763 ns/iter (± 8493) 3513187 ns/iter (± 6613) 1.01
es/visitor/compare/fold_span_panic 3668076 ns/iter (± 12656) 3649153 ns/iter (± 5038) 1.01
es/lexer/colors 13413 ns/iter (± 31) 13269 ns/iter (± 34) 1.01
es/lexer/angular 6289320 ns/iter (± 23558) 6271584 ns/iter (± 15951) 1.00
es/lexer/backbone 840001 ns/iter (± 3609) 832507 ns/iter (± 2447) 1.01
es/lexer/jquery 4711075 ns/iter (± 6536) 4688253 ns/iter (± 9753) 1.00
es/lexer/jquery mobile 7212271 ns/iter (± 4711) 7227164 ns/iter (± 26032) 1.00
es/lexer/mootools 3708319 ns/iter (± 1942) 3672175 ns/iter (± 18461) 1.01
es/lexer/underscore 696371 ns/iter (± 1393) 689633 ns/iter (± 6160) 1.01
es/lexer/three 22045027 ns/iter (± 23254) 22034968 ns/iter (± 32524) 1.00
es/lexer/yui 4107391 ns/iter (± 36426) 4142836 ns/iter (± 13285) 0.99
es/parser/colors 29557 ns/iter (± 43) 28950 ns/iter (± 35) 1.02
es/parser/angular 14639686 ns/iter (± 66958) 14063881 ns/iter (± 87181) 1.04
es/parser/backbone 2202677 ns/iter (± 14257) 2101719 ns/iter (± 8688) 1.05
es/parser/jquery 11957504 ns/iter (± 58996) 11419224 ns/iter (± 51833) 1.05
es/parser/jquery mobile 18218506 ns/iter (± 39672) 17531751 ns/iter (± 88034) 1.04
es/parser/mootools 9180656 ns/iter (± 34240) 8748132 ns/iter (± 21880) 1.05
es/parser/underscore 1891273 ns/iter (± 62680) 1802672 ns/iter (± 9480) 1.05
es/parser/three 51099820 ns/iter (± 289301) 48986259 ns/iter (± 278331) 1.04
es/parser/yui 9201989 ns/iter (± 44796) 8862091 ns/iter (± 92597) 1.04
es/preset-env/usage/builtin_type 145363 ns/iter (± 32907) 144037 ns/iter (± 33693) 1.01
es/preset-env/usage/property 19023 ns/iter (± 129) 18266 ns/iter (± 110) 1.04
es/resolver/typescript 94759008 ns/iter (± 1213689) 96069272 ns/iter (± 1369610) 0.99
es/fixer/typescript 64318844 ns/iter (± 275933) 65867221 ns/iter (± 706758) 0.98
es/hygiene/typescript 140268960 ns/iter (± 887766) 142924500 ns/iter (± 642356) 0.98
es/resolver_with_hygiene/typescript 297936845 ns/iter (± 1837522) 301350845 ns/iter (± 1142443) 0.99
es/visitor/base-perf/module_clone 61504 ns/iter (± 302) 62269 ns/iter (± 297) 0.99
es/visitor/base-perf/fold_empty 64841 ns/iter (± 233) 65658 ns/iter (± 276) 0.99
es/visitor/base-perf/fold_noop_impl_all 64822 ns/iter (± 309) 65946 ns/iter (± 264) 0.98
es/visitor/base-perf/fold_noop_impl_vec 64875 ns/iter (± 227) 66189 ns/iter (± 294) 0.98
es/visitor/base-perf/boxing_boxed_clone 56 ns/iter (± 0) 56 ns/iter (± 0) 1
es/visitor/base-perf/boxing_unboxed_clone 39 ns/iter (± 0) 40 ns/iter (± 0) 0.97
es/visitor/base-perf/boxing_boxed 115 ns/iter (± 0) 108 ns/iter (± 0) 1.06
es/visitor/base-perf/boxing_unboxed 81 ns/iter (± 0) 79 ns/iter (± 0) 1.03
es/visitor/base-perf/visit_empty 0 ns/iter (± 0) 0 ns/iter (± 0) NaN
es/visitor/base-perf/visit_contains_this 2664 ns/iter (± 10) 2637 ns/iter (± 7) 1.01
es/base/parallel/resolver/typescript 4420754888 ns/iter (± 284024559) 4513833990 ns/iter (± 266368220) 0.98
es/base/parallel/hygiene/typescript 1564697986 ns/iter (± 20609563) 1567435918 ns/iter (± 12446102) 1.00
misc/visitors/time-complexity/time 5 98 ns/iter (± 0) 108 ns/iter (± 0) 0.91
misc/visitors/time-complexity/time 10 257 ns/iter (± 0) 300 ns/iter (± 0) 0.86
misc/visitors/time-complexity/time 15 492 ns/iter (± 0) 519 ns/iter (± 1) 0.95
misc/visitors/time-complexity/time 20 1025 ns/iter (± 2) 1050 ns/iter (± 2) 0.98
misc/visitors/time-complexity/time 40 3708 ns/iter (± 47) 3571 ns/iter (± 8) 1.04
misc/visitors/time-complexity/time 60 7727 ns/iter (± 32) 7460 ns/iter (± 93) 1.04
es/full-target/es2016 244521 ns/iter (± 1973) 238914 ns/iter (± 1306) 1.02
es/full-target/es2017 232876 ns/iter (± 2013) 224168 ns/iter (± 1199) 1.04
es/full-target/es2018 221431 ns/iter (± 1199) 212240 ns/iter (± 947) 1.04
es2020_nullish_coalescing 71745 ns/iter (± 548) 71988 ns/iter (± 520) 1.00
es2020_optional_chaining 82558 ns/iter (± 308) 82301 ns/iter (± 391) 1.00
es2022_class_properties 122325 ns/iter (± 221) 120532 ns/iter (± 269) 1.01
es2018_object_rest_spread 75865 ns/iter (± 189) 70829 ns/iter (± 350) 1.07
es2019_optional_catch_binding 65418 ns/iter (± 173) 64279 ns/iter (± 207) 1.02
es2017_async_to_generator 64241 ns/iter (± 366) 64917 ns/iter (± 176) 0.99
es2016_exponentiation 69758 ns/iter (± 199) 69506 ns/iter (± 266) 1.00
es2015_arrow 72238 ns/iter (± 297) 72766 ns/iter (± 137) 0.99
es2015_block_scoped_fn 70138 ns/iter (± 169) 69081 ns/iter (± 264) 1.02
es2015_block_scoping 136022 ns/iter (± 362) 130661 ns/iter (± 613) 1.04

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.