Skip to content

Commit

Permalink
feat(rome_js_parser): instantiation expressions rome#3147
Browse files Browse the repository at this point in the history
  • Loading branch information
denbezrukov committed Dec 11, 2022
1 parent 7ba67ce commit c88a068
Show file tree
Hide file tree
Showing 15 changed files with 9,538 additions and 315 deletions.

This file was deleted.

1 change: 1 addition & 0 deletions crates/rome_js_parser/src/syntax/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ pub(crate) fn is_nth_at_expression(p: &mut JsParser, n: usize) -> bool {
| TRUE_KW
| FALSE_KW
| JS_NUMBER_LITERAL
| JS_BIG_INT_LITERAL
| JS_STRING_LITERAL
| NULL_KW => true,
t => t.is_contextual_keyword() || t.is_future_reserved_keyword(),
Expand Down
276 changes: 244 additions & 32 deletions crates/rome_js_parser/src/syntax/typescript/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::parser::{RecoveryError, RecoveryResult};
use crate::prelude::*;
use crate::state::{EnterType, SignatureFlags};
use crate::syntax::expr::{
is_at_identifier, is_nth_at_identifier, is_nth_at_identifier_or_keyword,
is_at_expression, is_at_identifier, is_nth_at_identifier, is_nth_at_identifier_or_keyword,
parse_big_int_literal_expression, parse_identifier, parse_literal_expression, parse_name,
parse_number_literal_expression, parse_reference_identifier, parse_template_elements,
ExpressionContext,
Expand Down Expand Up @@ -1256,19 +1256,241 @@ fn parse_ts_type_predicate(p: &mut JsParser) -> ParsedSyntax {
// const b4 = f<number>?.<number>(); // Type Error, expected no type arguments
// const x1 = f<true>
// (true);
// // Parsed as relational expression
// // Parsed as instantiation expression
// const x2 = f<true>
// true;
// // Parsed as instantiation expression
// const x3 = f<true>;
// true;
// (f<T>)<K>;
// (f<T>)<K>();
// (f<T>)<K>?.();
// (a?.f<T>)<K>();
// new (a<T>)<K>();
// f<<T>() => T>?.();
// f?.<<T>() => T>();
// f<x> ? g<y> : h<z>;
// [f<x>];
// { f<x> }

// test ts ts_type_instantiation_expression
// type StringBox = Box<string>;

// test_err ts ts_instantiation_expressions1
// test ts ts_instantiation_expressions_1
// class A {
// constructor() {
// f<T> super();
// }
// }
// f<TemplateStringsArray>``;
// f<T>(1);
// f<T> ?? 1;
// f<T> || 1;
// f<T> && 1;
// f<T> | 1;
// f<T> ^ 1;
// f<T> & 1;
// f<T> == f<T>;
// f<T> != f<T>;
// f<T> === f<T>;
// f<T> !== f<T>;
// f<T> <= f<T>;
// f<T> instanceof f<T>;
// f<T> in {};
// f<T> as {};
// f<T> satisfies {};
// f<T> * f<T>;
// f<T> / f<T>;
// f<T> % f<T>;
// f<T> ** f<T>;
// f < T > +f<T>;
// f < T > -f<T>;
// f < T > this;
// f < T > null;
// f < T > true;
// f < T > false;
// f < T > 1;
// f < T > 123n;
// f < T > [];
// f < T > {};
// f < T > function test() {};
// f < T > class A {};
// f < T > new A();
// f<T> / 1;
// f < T > +1;
// f < T > -1;
// f < T > ~1;
// f < T > !1;
// f < T > someIdentifier;
// f < T > delete a[field];
// f < T > typeof MyClass;
// f < T > void a;
// f<T> <= 1;
// f < T > (await 1);
// f < T > import.meta;
// f < T > import("123");
// a < b >> c;
// f = h >>> 0 < j >>> 0;

// test ts ts_instantiation_expressions_new_line
// class A {
// constructor() {
// f<T>
// super();
// }
// }
// function *f() {
// const f = f<T>
// yield;
// }
// f<T>
// ?? 1;
// f<T>
// || 1;
// f<T>
// && 1;
// f<T>
// | 1;
// f<T>
// ^ 1;
// f<T>
// & 1;
// f<T>
// == f<T>;
// f<T>
// <= f<T>;
// f<T>
// != f<T>;
// f<T>
// === f<T>;
// f<T>
// !== f<T>;
// f<T>
// instanceof f<T>;
// f<T>
// in {};
// f<T>
// * f<T>;
// f<T>
// / f<T>;
// f<T>
// % f<T>;
// f<T>
// ** f<T>;
// f <T>
// +f<T>;
// f <T>
// -f<T>;
// f <T>
// this;
// f <T>
// null;
// f <T>
// true;
// f <T>
// false;
// f <T>
// 1;
// f <T>
// 123n;
// f <T>
// {};
// f <T>
// function test() {};
// f <T>
// class A {};
// f <T>
// new A();
// f<T>
// / 1;
// f <T>
// +1;
// f <T>
// -1;
// f <T>
// ~1;
// f <T>
// !1;
// f <T>
// someIdentifier;
// f <T>
// delete a[field];
// f <T>
// typeof MyClass;
// f <T>
// void a;
// f<T>
// <= 1;
// f <T>
// (await 1);
// f <T>
// import.meta;
// f <T>
// import("123");

// test ts ts_instantiation_expressions_asi
// const x5 = f<true>
// let yy = 0;
// const x6 = f<true>
// interface I {}
// let x10 = f<true>
// this.bar()
// let x11 = f<true>
// function bar() {}
// let x12 = f<true>
// class C {}
// let x13 = f<true>
// bar()
// let x14 = f<true>
// void bar()
// class C1 {
// static specialFoo = f<string>
// static bar = 123
// }
// class C2 {
// public specialFoo = f<string>
// public bar = 123
// }
// class C3 {
// private specialFoo = f<string>
// private bar = 123
// }
// class C4 {
// protected specialFoo = f<string>
// protected bar = 123
// }
// class C5 {
// protected specialFoo = f<string>
// #bar = 123
// }
// const Bar = Foo<string>
// const Baz = 123

// test_err ts ts_instantiation_expressions_1
// const a8 = f<number><number>; // Relational operator error
// const b1 = f?.<number>; // Error, `(` expected
// f<T> << f<T>;
// f<T> = g<K>;
// f<T> >> f<T>;
// f<T> >= f<T>;
// f<T> < f<T>;
// f<T> > f<T>;
// f<T> import<1>;
// f<T> yield;
// f<T> ++;
// f<T> --;
// f<T> /= 1;
// f<T> <= f<T>;
// f<T> << f<T>;
// f <T>
// [];
// f<T>
// as {};
// f<T>
// satisfies {};
// class C5 {
// protected specialFoo = f<string> #bar = 123
// }

pub(crate) fn parse_ts_type_arguments_in_expression(p: &mut JsParser) -> ParsedSyntax {
// Don't parse type arguments in JS because the syntax is ambiguous
Expand All @@ -1285,7 +1507,7 @@ pub(crate) fn parse_ts_type_arguments_in_expression(p: &mut JsParser) -> ParsedS
p.re_lex(ReLexContext::TypeArgumentLessThan);
let arguments = parse_ts_type_arguments_impl(p, false);

if p.last() == Some(T![>]) && can_follow_type_arguments_in_expr(p.cur()) {
if p.last() == Some(T![>]) && can_follow_type_arguments_in_expr(p) {
Ok(Present(arguments))
} else {
Err(())
Expand All @@ -1294,35 +1516,25 @@ pub(crate) fn parse_ts_type_arguments_in_expression(p: &mut JsParser) -> ParsedS
.unwrap_or(Absent)
}

#[inline]
pub fn can_follow_type_arguments_in_expr(cur_kind: JsSyntaxKind) -> bool {
fn can_follow_type_arguments_in_expr(p: &mut JsParser) -> bool {
let cur_kind = p.cur();
match cur_kind {
// These tokens can follow a type argument list in a call expression.
T!['('] | BACKTICK | EOF => true,
// A type argument list followed by `<` never makes sense, and a type argument list followed
// by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in
// this context, `+` and `-` are unary operators, not binary operators.
T![<] | T![>] | T![+] | T![-] => false,
// We favor the type argument list interpretation when it is immediately followed by
// a line break, a binary operator, or something that can't start an expression.
_ => p.has_preceding_line_break() || is_binary_operator(p) || !is_at_expression(p),
}
}

fn is_binary_operator(p: &mut JsParser) -> bool {
matches!(
cur_kind,
T!['(']
| BACKTICK
// These tokens can't follow in a call expression, nor can they start an
// expression. So, consider the type argument list part of an instantiation
// expression.
| T![,]
| T![.]
| T![?.]
| T![')']
| T![']']
| T![:]
| T![;]
| T![?]
| T![==]
| T![===]
| T![!=]
| T![!==]
| T![&&]
| T![||]
| T![??]
| T![^]
| T![&]
| T![|]
| T!['}']
| EOF
OperatorPrecedence::try_from_binary_operator(p.cur()),
Some(_)
)
}

Expand Down
Loading

0 comments on commit c88a068

Please sign in to comment.