1use std::cell::Cell;
12use std::collections::HashMap;
13use std::rc::Rc;
14
15use hermes_ast::context::GCLock;
16use hermes_ast::node::Node;
17use hermes_support::location::{SMLoc, SMRange};
18
19use crate::lexer::{GrammarContext, JSLexer};
20use crate::token_kinds::TokenKind;
21
22mod classes;
23mod expressions;
24mod flow;
25mod functions;
26mod jsx;
27mod modules;
28mod pre_lazy;
29mod statements;
30mod ts;
31
32pub use pre_lazy::ParserPass;
33use pre_lazy::PreParsedBufferInfo;
34
35#[derive(Clone, Copy, PartialEq, Eq, Debug)]
38#[allow(dead_code)] pub(super) enum AllowImportExport {
40 Yes,
41 No,
42}
43
44#[derive(Clone, Copy, PartialEq, Eq, Debug)]
47pub(super) enum IsConstructorCall {
48 No,
49 Yes,
50}
51
52#[derive(Clone, Copy, PartialEq, Eq, Debug)]
56#[allow(dead_code)]
57pub(super) enum IsClassHeritageArgument {
58 No,
59 Yes,
60}
61
62#[derive(Clone, Copy, Default, PartialEq, Eq, Debug)]
65pub struct Param(u32);
66
67pub const PARAM_IN: Param = Param(1 << 0);
69pub const PARAM_RETURN: Param = Param(1 << 1);
71pub const PARAM_DEFAULT: Param = Param(1 << 2);
73pub const PARAM_TAGGED: Param = Param(1 << 3);
75
76impl Param {
77 pub fn plus(self, b: Param) -> Param {
79 Param(self.0 | b.0)
80 }
81 pub fn minus(self, b: Param) -> Param {
83 Param(self.0 & !b.0)
84 }
85 pub fn has(self, p: Param) -> bool {
87 (self.0 & p.0) != 0
88 }
89 pub fn has_all(self, p: Param) -> bool {
91 (self.0 & p.0) == p.0
92 }
93 pub fn get(self, p: Param) -> Param {
97 Param(self.0 & p.0)
98 }
99}
100
101const MAX_RECURSION_DEPTH: u32 =
128 if cfg!(debug_assertions) { 128 } else { 1024 };
129
130pub(super) struct RecursionGuard(Rc<Cell<u32>>);
140
141impl Drop for RecursionGuard {
142 fn drop(&mut self) {
143 self.0.set(self.0.get() - 1);
144 }
145}
146
147pub(super) struct ParamFlagGuard {
159 cell: Rc<Cell<bool>>,
160 old: bool,
161}
162
163impl Drop for ParamFlagGuard {
164 fn drop(&mut self) {
165 self.cell.set(self.old);
166 }
167}
168
169pub(super) struct JsxDepthGuard {
181 cell: Rc<Cell<u32>>,
182 old: u32,
183}
184
185impl Drop for JsxDepthGuard {
186 fn drop(&mut self) {
187 self.cell.set(self.old);
188 }
189}
190
191pub struct JSParserImpl<'gc, 'ast, 'ctx, 'a> {
211 gc: &'gc GCLock<'ast, 'ctx>,
214 pub(super) lexer: JSLexer<'a>,
216 recursion_depth: Rc<Cell<u32>>,
220 pub(super) param_yield: Rc<Cell<bool>>,
225 pub(super) param_await: Rc<Cell<bool>>,
229 pub(super) use_static_builtin: bool,
231 pub(super) allow_anon_function_type: Rc<Cell<bool>>,
236 pub(super) allow_conditional_type: Rc<Cell<bool>>,
240 pub(super) jsx_depth: Rc<Cell<u32>>,
247 pub(super) pass: ParserPass,
249 pub(super) pre_parsed: PreParsedBufferInfo,
253 pub(super) is_arrow_function: Rc<Cell<bool>>,
256 pub(super) contains_arrow_functions: Rc<Cell<bool>>,
259 pub(super) may_contain_arrow_functions_using_arguments: Rc<Cell<bool>>,
263 pub(super) seen_directives: Vec<Vec<u8>>,
266}
267
268impl<'gc, 'ast, 'ctx, 'a> JSParserImpl<'gc, 'ast, 'ctx, 'a> {
269 pub fn new(gc: &'gc GCLock<'ast, 'ctx>, mut lexer: JSLexer<'a>) -> Self {
272 lexer.set_strict_mode(gc.ctx().strict_mode());
278 lexer.advance(GrammarContext::AllowRegExp);
279 JSParserImpl {
280 gc,
281 lexer,
282 recursion_depth: Rc::new(Cell::new(0)),
283 param_yield: Rc::new(Cell::new(false)),
284 param_await: Rc::new(Cell::new(false)),
285 use_static_builtin: false,
286 allow_anon_function_type: Rc::new(Cell::new(false)),
287 allow_conditional_type: Rc::new(Cell::new(false)),
288 jsx_depth: Rc::new(Cell::new(0)),
289 pass: ParserPass::FullParse,
290 pre_parsed: PreParsedBufferInfo {
291 function_info: HashMap::new(),
292 },
293 is_arrow_function: Rc::new(Cell::new(false)),
294 contains_arrow_functions: Rc::new(Cell::new(false)),
295 may_contain_arrow_functions_using_arguments: Rc::new(Cell::new(false)),
296 seen_directives: Vec::new(),
297 }
298 }
299
300 pub fn new_with_pass(
303 gc: &'gc GCLock<'ast, 'ctx>,
304 lexer: JSLexer<'a>,
305 pass: ParserPass,
306 ) -> Self {
307 let mut p = Self::new(gc, lexer);
308 p.pass = pass;
309 p
310 }
311
312 pub fn get_use_static_builtin(&self) -> bool {
314 self.use_static_builtin
315 }
316
317 pub fn take_pre_parsed(&mut self) -> PreParsedBufferInfo {
321 std::mem::replace(
322 &mut self.pre_parsed,
323 PreParsedBufferInfo {
324 function_info: HashMap::new(),
325 },
326 )
327 }
328
329 pub fn set_pre_parsed(&mut self, t: PreParsedBufferInfo) {
333 self.pre_parsed = t;
334 }
335
336 pub fn set_strict_mode(&mut self, strict: bool) {
341 self.lexer.set_strict_mode(strict);
342 }
343
344 pub(super) fn parse_flow(&self) -> bool {
347 self.gc.ctx().parse_flow()
348 }
349
350 pub(super) fn parse_flow_ambiguous(&self) -> bool {
353 self.gc.ctx().parse_flow_ambiguous()
354 }
355
356 pub(super) fn parse_flow_component_syntax(&self) -> bool {
359 self.gc.ctx().parse_flow_component_syntax()
360 }
361
362 pub(super) fn parse_flow_records(&self) -> bool {
365 self.gc.ctx().parse_flow_records()
366 }
367
368 pub(super) fn parse_flow_match(&self) -> bool {
371 self.gc.ctx().parse_flow_match()
372 }
373
374 pub(super) fn parse_ts(&self) -> bool {
377 self.gc.ctx().parse_ts()
378 }
379
380 pub(super) fn parse_jsx(&self) -> bool {
383 self.gc.ctx().parse_jsx()
384 }
385
386 pub(super) fn parse_types(&self) -> bool {
389 self.parse_flow() || self.parse_ts()
390 }
391
392 pub(in crate::js) fn parse_type_annotation(
398 &mut self,
399 wrapped_start: Option<SMLoc>,
400 allow_anon_function_type: flow::AllowAnonFunctionType,
401 ) -> Option<&'gc Node<'gc>> {
402 debug_assert!(self.parse_flow() || self.parse_ts());
403 if self.parse_flow() {
405 return self.parse_type_annotation_flow(
406 wrapped_start,
407 allow_anon_function_type,
408 );
409 }
410 self.parse_type_annotation_ts(wrapped_start)
412 }
413
414 pub(in crate::js) fn parse_return_type_annotation(
419 &mut self,
420 wrapped_start: Option<SMLoc>,
421 allow_anon_function_type: flow::AllowAnonFunctionType,
422 ) -> Option<&'gc Node<'gc>> {
423 debug_assert!(self.parse_flow() || self.parse_ts());
424 if self.parse_flow() {
426 return self.parse_return_type_annotation_flow(
427 wrapped_start,
428 allow_anon_function_type,
429 );
430 }
431 self.parse_type_annotation_ts(wrapped_start)
433 }
434
435 pub(in crate::js) fn parse_type_arguments(
439 &mut self,
440 ) -> Option<&'gc Node<'gc>> {
441 debug_assert!(self.parse_flow() || self.parse_ts());
442 if self.parse_flow() {
444 return self
445 .parse_type_args_flow(crate::lexer::GrammarContext::Type);
446 }
447 self.parse_ts_type_arguments()
449 }
450
451 #[inline]
452 pub(super) fn cur_kind(&self) -> TokenKind {
453 self.lexer.token().kind()
454 }
455 #[inline]
456 pub(super) fn cur_range(&self) -> SMRange {
457 self.lexer.token().source_range()
458 }
459 #[inline]
460 pub(super) fn cur_start(&self) -> SMLoc {
461 self.lexer.token().start_loc()
462 }
463
464 #[inline]
466 pub(super) fn check(&self, kind: TokenKind) -> bool {
467 self.cur_kind() == kind
468 }
469 #[inline]
471 pub(super) fn check2(&self, k1: TokenKind, k2: TokenKind) -> bool {
472 let k = self.cur_kind();
473 k == k1 || k == k2
474 }
475 #[inline]
478 pub(super) fn check_n3(
479 &self,
480 k1: TokenKind,
481 k2: TokenKind,
482 k3: TokenKind,
483 ) -> bool {
484 let k = self.cur_kind();
485 k == k1 || k == k2 || k == k3
486 }
487
488 #[inline]
491 pub(super) fn check_n4(
492 &self,
493 k1: TokenKind,
494 k2: TokenKind,
495 k3: TokenKind,
496 k4: TokenKind,
497 ) -> bool {
498 let k = self.cur_kind();
499 k == k1 || k == k2 || k == k3 || k == k4
500 }
501
502 pub(super) fn advance(&mut self, grammar_context: GrammarContext) -> SMRange {
506 let prev = self.cur_range();
507 self.lexer.advance(grammar_context);
508 prev
509 }
510
511 pub(super) fn check_and_eat(
513 &mut self,
514 kind: TokenKind,
515 grammar_context: GrammarContext,
516 ) -> bool {
517 if self.check(kind) {
518 self.advance(grammar_context);
519 true
520 } else {
521 false
522 }
523 }
524
525 pub(super) fn error_at(&mut self, range: SMRange, msg: &str) {
527 self.lexer.get_source_mgr_mut().error_at(
528 range.start,
529 Some(range),
530 msg,
531 hermes_support::diag::Subsystem::Parser,
532 );
533 }
534 pub(super) fn error_cur(&mut self, msg: &str) {
536 let range = self.cur_range();
537 self.error_at(range, msg);
538 }
539 pub(super) fn error_at_loc(&mut self, loc: SMLoc, msg: &str) {
543 self.lexer.get_source_mgr_mut().error_at(
544 loc,
545 None,
546 msg,
547 hermes_support::diag::Subsystem::Parser,
548 );
549 }
550
551 pub(super) fn need(&mut self, kind: TokenKind, where_: &str) -> bool {
577 if self.check(kind) {
578 return true;
579 }
580 let msg = format!(
581 "'{}' expected{}",
582 crate::token_kinds::token_kind_str(kind),
583 where_
584 );
585 self.error_expected_msg(&msg, None, None);
586 false
587 }
588
589 pub(super) fn error_expected_msg(
623 &mut self,
624 msg: &str,
625 what: Option<&str>,
626 what_loc: Option<SMLoc>,
627 ) {
628 let err_loc = self.cur_start();
629 let range = match what_loc {
634 Some(w) => {
635 let sm = self.lexer.get_source_mgr();
636 if sm
637 .find_coords(w)
638 .is_same_source_line_as(&sm.find_coords(err_loc))
639 {
640 Some(sm.combine_into_range(w, err_loc))
641 } else {
642 None
643 }
644 }
645 None => None,
646 };
647 let same_line = range.is_some();
648 self.lexer.get_source_mgr_mut().error_at(
649 err_loc,
650 range,
651 msg,
652 hermes_support::diag::Subsystem::Parser,
653 );
654 if !same_line {
657 if let (Some(what), Some(w)) = (what, what_loc) {
658 self.lexer.get_source_mgr_mut().note_at(
659 w,
660 None,
661 what,
662 hermes_support::diag::Subsystem::Parser,
663 );
664 }
665 }
666 }
667
668 pub(super) fn need_at(
673 &mut self,
674 kind: TokenKind,
675 where_: &str,
676 what: Option<&str>,
677 what_loc: SMLoc,
678 ) -> bool {
679 if self.check(kind) {
680 return true;
681 }
682 let msg = format!(
683 "'{}' expected{}",
684 crate::token_kinds::token_kind_str(kind),
685 where_
686 );
687 self.error_expected_msg(&msg, what, Some(what_loc));
688 false
689 }
690 pub(super) fn error_expected2(
701 &mut self,
702 k1: TokenKind,
703 k2: TokenKind,
704 where_: &str,
705 what: Option<&str>,
706 what_loc: SMLoc,
707 ) {
708 let msg = format!(
709 "'{}' or '{}' expected{}",
710 crate::token_kinds::token_kind_str(k1),
711 crate::token_kinds::token_kind_str(k2),
712 where_
713 );
714 self.error_expected_msg(&msg, what, Some(what_loc));
715 }
716
717 pub(super) fn error_expected3(
724 &mut self,
725 k1: TokenKind,
726 k2: TokenKind,
727 k3: TokenKind,
728 where_: &str,
729 what: Option<&str>,
730 what_loc: SMLoc,
731 ) {
732 let msg = format!(
733 "'{}', '{}' or '{}' expected{}",
734 crate::token_kinds::token_kind_str(k1),
735 crate::token_kinds::token_kind_str(k2),
736 crate::token_kinds::token_kind_str(k3),
737 where_
738 );
739 self.error_expected_msg(&msg, what, Some(what_loc));
740 }
741
742 #[allow(clippy::too_many_arguments)]
750 pub(super) fn error_expected4(
751 &mut self,
752 k1: TokenKind,
753 k2: TokenKind,
754 k3: TokenKind,
755 k4: TokenKind,
756 where_: &str,
757 what: Option<&str>,
758 what_loc: SMLoc,
759 ) {
760 let msg = format!(
761 "'{}', '{}', '{}' or '{}' expected{}",
762 crate::token_kinds::token_kind_str(k1),
763 crate::token_kinds::token_kind_str(k2),
764 crate::token_kinds::token_kind_str(k3),
765 crate::token_kinds::token_kind_str(k4),
766 where_
767 );
768 self.error_expected_msg(&msg, what, Some(what_loc));
769 }
770
771 pub(super) fn eat_at(
779 &mut self,
780 kind: TokenKind,
781 grammar_context: GrammarContext,
782 where_: &str,
783 what: Option<&str>,
784 what_loc: SMLoc,
785 ) -> bool {
786 if self.need_at(kind, where_, what, what_loc) {
787 self.advance(grammar_context);
788 true
789 } else {
790 false
791 }
792 }
793
794 pub(super) fn source_bytes(&self, start: SMLoc, end: SMLoc) -> &[u8] {
799 let buf_start = self.lexer.get_buffer_start();
800 let buf = self.lexer.buffer_bytes();
801 &buf[(start.offset - buf_start) as usize
802 ..(end.offset - buf_start) as usize]
803 }
804
805 pub(super) fn source_bytes_atom(
810 &self,
811 start: SMLoc,
812 end: SMLoc,
813 ) -> hermes_atom_table::AtomBytes {
814 self.lexer.get_string_literal(self.source_bytes(start, end))
815 }
816
817 pub(super) fn check_recursion(&mut self) -> Option<RecursionGuard> {
824 let depth = self.recursion_depth.get() + 1;
825 if depth >= MAX_RECURSION_DEPTH {
831 let loc = self.cur_start();
839 self.error_at_loc(
840 loc,
841 "Too many nested expressions/statements/declarations",
842 );
843 return None;
844 }
845 self.recursion_depth.set(depth);
846 Some(RecursionGuard(Rc::clone(&self.recursion_depth)))
847 }
848
849 pub(super) fn save_param_yield(&self, new_val: bool) -> ParamFlagGuard {
852 let old = self.param_yield.get();
853 self.param_yield.set(new_val);
854 ParamFlagGuard {
855 cell: Rc::clone(&self.param_yield),
856 old,
857 }
858 }
859
860 pub(super) fn save_param_await(&self, new_val: bool) -> ParamFlagGuard {
863 let old = self.param_await.get();
864 self.param_await.set(new_val);
865 ParamFlagGuard {
866 cell: Rc::clone(&self.param_await),
867 old,
868 }
869 }
870
871 pub(super) fn save_allow_anon_function_type(
876 &self,
877 new_val: bool,
878 ) -> ParamFlagGuard {
879 let old = self.allow_anon_function_type.get();
880 self.allow_anon_function_type.set(new_val);
881 ParamFlagGuard {
882 cell: Rc::clone(&self.allow_anon_function_type),
883 old,
884 }
885 }
886
887 pub(super) fn save_allow_conditional_type(
892 &self,
893 new_val: bool,
894 ) -> ParamFlagGuard {
895 let old = self.allow_conditional_type.get();
896 self.allow_conditional_type.set(new_val);
897 ParamFlagGuard {
898 cell: Rc::clone(&self.allow_conditional_type),
899 old,
900 }
901 }
902
903 pub(super) fn save_jsx_depth(&self, new_val: u32) -> JsxDepthGuard {
908 let old = self.jsx_depth.get();
909 self.jsx_depth.set(new_val);
910 JsxDepthGuard {
911 cell: Rc::clone(&self.jsx_depth),
912 old,
913 }
914 }
915
916 pub(super) fn dummy_range(&self) -> SMRange {
921 let loc = self.cur_start();
922 SMRange {
923 start: loc,
924 end: loc,
925 }
926 }
927
928 pub(super) fn invalid_range(&self) -> SMRange {
938 let loc = self.cur_start();
939 SMRange {
940 start: SMLoc {
941 source: loc.source,
942 offset: 1,
943 },
944 end: SMLoc {
945 source: loc.source,
946 offset: 0,
947 },
948 }
949 }
950
951 pub(super) fn set_location(
954 &self,
955 start: SMLoc,
956 end: SMLoc,
957 node: Node<'gc>,
958 ) -> &'gc Node<'gc> {
959 let allocated = self.gc.alloc(node);
960 let md = allocated.metadata();
961 md.range.set(SMRange { start, end });
962 md.debug_loc.set(start);
963 allocated
964 }
965
966 pub(super) fn set_location_d(
973 &self,
974 start: SMLoc,
975 end: SMLoc,
976 debug: SMLoc,
977 node: Node<'gc>,
978 ) -> &'gc Node<'gc> {
979 let allocated = self.gc.alloc(node);
980 let md = allocated.metadata();
981 md.range.set(SMRange { start, end });
982 md.debug_loc.set(debug);
983 allocated
984 }
985
986 pub fn parse(&mut self) -> Option<&'gc Node<'gc>> {
1008 let res = self.parse_program()?;
1009 if self.lexer.get_source_mgr().error_count() != 0 {
1010 return None;
1011 }
1012 Some(res)
1013 }
1014
1015 fn parse_program(&mut self) -> Option<&'gc Node<'gc>> {
1019 use hermes_ast::node::Program;
1020 use hermes_ast::node_child::{NodeList, NodeMetadata};
1021
1022 let start = self.cur_start();
1023
1024 let mut stmts: Vec<&'gc Node<'gc>> = Vec::new();
1025 if !self.parse_statement_list(
1026 Param::default(),
1027 [TokenKind::eof],
1028 true,
1029 AllowImportExport::Yes,
1030 &mut stmts,
1031 ) {
1032 return None;
1033 }
1034
1035 let end = if stmts.is_empty() {
1036 start
1037 } else {
1038 stmts.last().unwrap().metadata().range.get().end
1039 };
1040
1041 let body = NodeList::from_iter(self.gc, stmts);
1042 let program = Node::Program(Program::new(
1043 NodeMetadata::new(SMRange { start, end }),
1044 body,
1045 ));
1046 Some(self.set_location(start, end, program))
1047 }
1048
1049 #[cfg(test)]
1051 pub(crate) fn cur_kind_pub(&self) -> TokenKind {
1052 self.cur_kind()
1053 }
1054
1055 #[cfg(test)]
1057 pub(crate) fn error_count_pub(&self) -> u32 {
1058 self.lexer.get_source_mgr().error_count()
1059 }
1060}
1061
1062#[cfg(test)]
1063mod tests {
1064 use super::*;
1065
1066 #[test]
1067 fn parser_constructs_and_sees_first_token() {
1068 use hermes_ast::context::Context;
1069 use hermes_support::manager::SourceErrorManager;
1070
1071 let mut sm = SourceErrorManager::new();
1072 let buf_id = sm.add_buffer_bytes("input", b" /* hi */ ");
1073 let mut ctx = Context::new();
1074 let gc = ctx.lock();
1075 let atoms = &gc.ctx().atom_table;
1076 let lexer = crate::lexer::JSLexer::new(
1077 buf_id,
1078 &mut sm,
1079 atoms,
1080 crate::lexer::GrammarContext::AllowRegExp,
1081 );
1082 let parser = JSParserImpl::new(&gc, lexer);
1083 assert_eq!(
1084 parser.cur_kind_pub(),
1085 crate::token_kinds::TokenKind::eof
1086 );
1087 }
1088
1089 #[test]
1090 fn parses_empty_program() {
1091 use hermes_ast::context::Context;
1092 use hermes_ast::node::Node;
1093 use hermes_support::manager::SourceErrorManager;
1094
1095 let mut sm = SourceErrorManager::new();
1096 let buf_id = sm.add_buffer_bytes("input", b"/* only trivia */\n");
1097 let mut ctx = Context::new();
1098 let gc = ctx.lock();
1099 let atoms = &gc.ctx().atom_table;
1100 let lexer = crate::lexer::JSLexer::new(
1101 buf_id,
1102 &mut sm,
1103 atoms,
1104 crate::lexer::GrammarContext::AllowRegExp,
1105 );
1106 let mut parser = JSParserImpl::new(&gc, lexer);
1107 let program = parser.parse().expect("empty program parses");
1108 match program {
1109 Node::Program(p) => assert!(p.body.is_empty(), "empty source -> empty body"),
1110 other => panic!("expected Program, got {:?}", other.kind()),
1111 }
1112 assert_eq!(parser.error_count_pub(), 0);
1113 }
1114
1115 #[test]
1116 fn parses_numeric_literal_stmt() {
1117 use hermes_ast::context::Context;
1118 use hermes_ast::node::Node;
1119 use hermes_support::manager::SourceErrorManager;
1120
1121 let mut sm = SourceErrorManager::new();
1122 let buf_id = sm.add_buffer_bytes("input", b"42;\n");
1123 let mut ctx = Context::new();
1124 let gc = ctx.lock();
1125 let atoms = &gc.ctx().atom_table;
1126 let lexer = crate::lexer::JSLexer::new(
1127 buf_id,
1128 &mut sm,
1129 atoms,
1130 crate::lexer::GrammarContext::AllowRegExp,
1131 );
1132 let mut parser = JSParserImpl::new(&gc, lexer);
1133 let program = parser.parse().expect("42; parses");
1134 assert_eq!(parser.error_count_pub(), 0);
1135 if let Node::Program(p) = program {
1136 assert_eq!(p.body.iter().count(), 1);
1137 let stmt = p.body.iter().next().unwrap();
1138 if let Node::ExpressionStatement(es) = stmt {
1139 if let Node::NumericLiteral(nl) = es.expression {
1140 assert_eq!(nl.value.get(), 42.0);
1141 } else {
1142 panic!("expected NumericLiteral");
1143 }
1144 } else {
1145 panic!("expected ExpressionStatement");
1146 }
1147 } else {
1148 panic!("expected Program");
1149 }
1150 }
1151
1152 #[test]
1162 fn parse_returns_none_on_recoverable_error() {
1163 use hermes_ast::context::Context;
1164 use hermes_support::manager::SourceErrorManager;
1165
1166 let mut sm = SourceErrorManager::new();
1167 let buf_id =
1168 sm.add_buffer_bytes("input", b"\"use strict\"; var x = 010;\n");
1169 let mut ctx = Context::new();
1170 let gc = ctx.lock();
1171 let atoms = &gc.ctx().atom_table;
1172 let lexer = crate::lexer::JSLexer::new(
1173 buf_id,
1174 &mut sm,
1175 atoms,
1176 crate::lexer::GrammarContext::AllowRegExp,
1177 );
1178 let mut parser = JSParserImpl::new(&gc, lexer);
1179 let program = parser.parse();
1180 assert!(parser.error_count_pub() > 0, "octal literal must error");
1181 assert!(
1182 program.is_none(),
1183 "parse() must return None once the source has errors, even \
1184 though parseProgram() itself recovered and built a tree"
1185 );
1186 }
1187
1188 #[test]
1189 fn parses_empty_statement() {
1190 use hermes_ast::context::Context;
1191 use hermes_ast::node::Node;
1192 use hermes_support::manager::SourceErrorManager;
1193
1194 let mut sm = SourceErrorManager::new();
1195 let buf_id = sm.add_buffer_bytes("input", b";;;\n");
1196 let mut ctx = Context::new();
1197 let gc = ctx.lock();
1198 let atoms = &gc.ctx().atom_table;
1199 let lexer = crate::lexer::JSLexer::new(
1200 buf_id,
1201 &mut sm,
1202 atoms,
1203 crate::lexer::GrammarContext::AllowRegExp,
1204 );
1205 let mut parser = JSParserImpl::new(&gc, lexer);
1206 let program = parser.parse().expect(";;; parses");
1207 assert_eq!(parser.error_count_pub(), 0);
1208 if let Node::Program(p) = program {
1209 assert_eq!(p.body.iter().count(), 3);
1210 for stmt in p.body {
1211 assert!(
1212 matches!(stmt, Node::EmptyStatement(_)),
1213 "expected EmptyStatement"
1214 );
1215 }
1216 } else {
1217 panic!("expected Program");
1218 }
1219 }
1220
1221 #[test]
1223 fn if_statement_parses() {
1224 use hermes_ast::context::Context;
1225 use hermes_ast::node::Node;
1226 use hermes_support::manager::SourceErrorManager;
1227
1228 let mut sm = SourceErrorManager::new();
1229 let buf_id = sm.add_buffer_bytes("input", b"if(x);");
1230 let mut ctx = Context::new();
1231 let gc = ctx.lock();
1232 let atoms = &gc.ctx().atom_table;
1233 let lexer = crate::lexer::JSLexer::new(
1234 buf_id,
1235 &mut sm,
1236 atoms,
1237 crate::lexer::GrammarContext::AllowRegExp,
1238 );
1239 let mut parser = JSParserImpl::new(&gc, lexer);
1240 let program = parser.parse().expect("if statement parses in P2.4");
1241 assert_eq!(parser.error_count_pub(), 0, "zero errors");
1242 let Node::Program(p) = program else {
1243 panic!("expected Program")
1244 };
1245 let stmt = p.body.iter().next().expect("one statement");
1246 assert!(
1247 matches!(stmt, Node::IfStatement(_)),
1248 "expected IfStatement, got {:?}",
1249 stmt.kind()
1250 );
1251 }
1252
1253 #[test]
1255 fn function_expression_parses() {
1256 use hermes_ast::context::Context;
1257 use hermes_ast::node::Node;
1258 use hermes_support::manager::SourceErrorManager;
1259
1260 let mut sm = SourceErrorManager::new();
1261 let mut ctx = Context::new();
1262 let gc = ctx.lock();
1263 let atoms = &gc.ctx().atom_table;
1264
1265 let expr = parse_expr_from(&gc, &mut sm, atoms, b"(function(){});");
1266 assert!(
1267 matches!(expr, Node::FunctionExpression(_)),
1268 "expected FunctionExpression, got {:?}",
1269 expr.kind()
1270 );
1271 }
1272
1273 fn assert_parse_errors(src: &[u8], why: &str) {
1276 use hermes_ast::context::Context;
1277 use hermes_support::manager::SourceErrorManager;
1278
1279 let mut sm = SourceErrorManager::new();
1280 let buf_id = sm.add_buffer_bytes("input", src);
1281 let mut ctx = Context::new();
1282 let gc = ctx.lock();
1283 let atoms = &gc.ctx().atom_table;
1284 let lexer = crate::lexer::JSLexer::new(
1285 buf_id,
1286 &mut sm,
1287 atoms,
1288 crate::lexer::GrammarContext::AllowRegExp,
1289 );
1290 let mut parser = JSParserImpl::new(&gc, lexer);
1291 assert!(parser.parse().is_none(), "{why}");
1292 assert!(parser.error_count_pub() >= 1, "{why}: expected an error");
1293 }
1294
1295 fn assert_parse_has_errors_impl(src: &[u8], why: &str, parse_flow: bool) {
1300 use hermes_ast::context::Context;
1301 use hermes_support::manager::SourceErrorManager;
1302
1303 let mut sm = SourceErrorManager::new();
1304 let buf_id = sm.add_buffer_bytes("input", src);
1305 let mut ctx = Context::new();
1306 ctx.set_parse_flow(parse_flow);
1307 let gc = ctx.lock();
1308 let atoms = &gc.ctx().atom_table;
1309 let lexer = crate::lexer::JSLexer::new(
1310 buf_id,
1311 &mut sm,
1312 atoms,
1313 crate::lexer::GrammarContext::AllowRegExp,
1314 );
1315 let mut parser = JSParserImpl::new(&gc, lexer);
1316 let _ = parser.parse();
1317 assert!(parser.error_count_pub() >= 1, "{why}: expected an error");
1318 }
1319
1320 fn assert_parse_has_errors(src: &[u8], why: &str) {
1325 assert_parse_has_errors_impl(src, why, false);
1326 }
1327
1328 fn parse_one_stmt<'gc>(
1337 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
1338 sm: &mut hermes_support::manager::SourceErrorManager,
1339 src: &[u8],
1340 ) -> &'gc hermes_ast::node::Node<'gc> {
1341 flow_parse_stmt_at(gc, sm, src, 0)
1342 }
1343
1344 #[test]
1345 fn function_declaration_parses() {
1346 use hermes_ast::context::Context;
1347 use hermes_ast::node::Node;
1348 let mut sm = hermes_support::manager::SourceErrorManager::new();
1349 let mut ctx = Context::new();
1350 let gc = ctx.lock();
1351 let stmt = parse_one_stmt(&gc, &mut sm, b"function f(){}");
1352 assert!(
1353 matches!(stmt, Node::FunctionDeclaration(_)),
1354 "expected FunctionDeclaration, got {:?}",
1355 stmt.kind()
1356 );
1357 }
1358
1359 #[test]
1360 fn generator_declaration_has_generator_flag() {
1361 use hermes_ast::context::Context;
1362 use hermes_ast::node::Node;
1363 let mut sm = hermes_support::manager::SourceErrorManager::new();
1364 let mut ctx = Context::new();
1365 let gc = ctx.lock();
1366 let stmt = parse_one_stmt(&gc, &mut sm, b"function* h(){}");
1367 if let Node::FunctionDeclaration(fd) = stmt {
1368 assert!(fd.generator.get(), "generator flag is true");
1369 assert!(!fd.r#async.get(), "async flag is false");
1370 } else {
1371 panic!("expected FunctionDeclaration");
1372 }
1373 }
1374
1375 #[test]
1376 fn async_declaration_has_async_flag() {
1377 use hermes_ast::context::Context;
1378 use hermes_ast::node::Node;
1379 let mut sm = hermes_support::manager::SourceErrorManager::new();
1380 let mut ctx = Context::new();
1381 let gc = ctx.lock();
1382 let stmt = parse_one_stmt(&gc, &mut sm, b"async function k(){}");
1383 if let Node::FunctionDeclaration(fd) = stmt {
1384 assert!(fd.r#async.get(), "async flag is true");
1385 assert!(!fd.generator.get(), "generator flag is false");
1386 } else {
1387 panic!("expected FunctionDeclaration");
1388 }
1389 }
1390
1391 #[test]
1392 fn function_params_identifier_and_rest() {
1393 use hermes_ast::context::Context;
1394 use hermes_ast::node::Node;
1395 let mut sm = hermes_support::manager::SourceErrorManager::new();
1396 let mut ctx = Context::new();
1397 let gc = ctx.lock();
1398 let stmt = parse_one_stmt(&gc, &mut sm, b"function f(a, ...r){}");
1399 if let Node::FunctionDeclaration(fd) = stmt {
1400 let params: Vec<_> = fd.params.iter().collect();
1401 assert_eq!(params.len(), 2);
1402 assert!(
1403 matches!(params[0], Node::Identifier(_)),
1404 "first param is Identifier"
1405 );
1406 assert!(
1407 matches!(params[1], Node::RestElement(_)),
1408 "second param is RestElement"
1409 );
1410 } else {
1411 panic!("expected FunctionDeclaration");
1412 }
1413 }
1414
1415 #[test]
1416 fn function_params_object_and_array_patterns() {
1417 use hermes_ast::context::Context;
1418 use hermes_ast::node::Node;
1419 let mut sm = hermes_support::manager::SourceErrorManager::new();
1420 let mut ctx = Context::new();
1421 let gc = ctx.lock();
1422 let stmt = parse_one_stmt(&gc, &mut sm, b"function g({x},[y]){}");
1423 if let Node::FunctionDeclaration(fd) = stmt {
1424 let params: Vec<_> = fd.params.iter().collect();
1425 assert_eq!(params.len(), 2);
1426 assert!(
1427 matches!(params[0], Node::ObjectPattern(_)),
1428 "first param is ObjectPattern"
1429 );
1430 assert!(
1431 matches!(params[1], Node::ArrayPattern(_)),
1432 "second param is ArrayPattern"
1433 );
1434 } else {
1435 panic!("expected FunctionDeclaration");
1436 }
1437 }
1438
1439 #[test]
1442 fn await_in_async_body_parses() {
1443 let mut sm = hermes_support::manager::SourceErrorManager::new();
1444 assert!(
1445 parse_snippet(&mut sm, b"async function f(){ await x; }"),
1446 "await in async body must parse cleanly"
1447 );
1448 }
1449
1450 #[test]
1452 fn yield_in_generator_parses() {
1453 let mut sm = hermes_support::manager::SourceErrorManager::new();
1454 assert!(
1455 parse_snippet(&mut sm, b"function* g(){ yield 1; }"),
1456 "yield in generator body must parse cleanly"
1457 );
1458 }
1459
1460 #[test]
1465 fn class_declaration_with_heritage() {
1466 use hermes_ast::context::Context;
1467 use hermes_ast::node::Node;
1468 let mut sm = hermes_support::manager::SourceErrorManager::new();
1469 let mut ctx = Context::new();
1470 let gc = ctx.lock();
1471 let stmt = parse_one_stmt(&gc, &mut sm, b"class A extends B {}");
1472 let Node::ClassDeclaration(cd) = stmt else {
1473 panic!("expected ClassDeclaration, got {:?}", stmt.kind());
1474 };
1475 let sup = cd.super_class.expect("superClass present");
1476 match sup {
1477 Node::Identifier(id) => {
1478 let bytes = gc.ctx().atom_table.bytes(id.name.get());
1479 assert_eq!(bytes, b"B");
1480 }
1481 other => panic!("expected Identifier superClass, got {:?}", other.kind()),
1482 }
1483 }
1484
1485 fn parse_one_class_member<'gc>(
1488 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
1489 sm: &mut hermes_support::manager::SourceErrorManager,
1490 member_src: &str,
1491 ) -> &'gc hermes_ast::node::Node<'gc> {
1492 use hermes_ast::node::Node;
1493 let src = format!("class A {{ {member_src} }}");
1494 let stmt = parse_one_stmt(gc, sm, src.as_bytes());
1495 let Node::ClassDeclaration(cd) = stmt else {
1496 panic!("expected ClassDeclaration, got {:?}", stmt.kind());
1497 };
1498 let Node::ClassBody(cb) = cd.body else {
1499 panic!("expected ClassBody");
1500 };
1501 cb.body.iter().next().expect("one class member")
1502 }
1503
1504 #[test]
1506 fn class_method_kind_method() {
1507 use hermes_ast::context::Context;
1508 use hermes_ast::node::Node;
1509 let mut sm = hermes_support::manager::SourceErrorManager::new();
1510 let mut ctx = Context::new();
1511 let gc = ctx.lock();
1512 let member = parse_one_class_member(&gc, &mut sm, "m(){}");
1513 let Node::MethodDefinition(md) = member else {
1514 panic!("expected MethodDefinition, got {:?}", member.kind());
1515 };
1516 let kind = gc.ctx().atom_table.bytes(md.kind.get());
1517 assert_eq!(kind, b"method");
1518 assert!(!md.r#static.get(), "not static");
1519 }
1520
1521 #[test]
1523 fn class_method_kind_constructor() {
1524 use hermes_ast::context::Context;
1525 use hermes_ast::node::Node;
1526 let mut sm = hermes_support::manager::SourceErrorManager::new();
1527 let mut ctx = Context::new();
1528 let gc = ctx.lock();
1529 let member = parse_one_class_member(&gc, &mut sm, "constructor(){}");
1530 let Node::MethodDefinition(md) = member else {
1531 panic!("expected MethodDefinition, got {:?}", member.kind());
1532 };
1533 let kind = gc.ctx().atom_table.bytes(md.kind.get());
1534 assert_eq!(kind, b"constructor");
1535 }
1536
1537 #[test]
1539 fn class_method_kind_get() {
1540 use hermes_ast::context::Context;
1541 use hermes_ast::node::Node;
1542 let mut sm = hermes_support::manager::SourceErrorManager::new();
1543 let mut ctx = Context::new();
1544 let gc = ctx.lock();
1545 let member = parse_one_class_member(&gc, &mut sm, "get x(){}");
1546 let Node::MethodDefinition(md) = member else {
1547 panic!("expected MethodDefinition, got {:?}", member.kind());
1548 };
1549 let kind = gc.ctx().atom_table.bytes(md.kind.get());
1550 assert_eq!(kind, b"get");
1551 }
1552
1553 #[test]
1555 fn class_method_static() {
1556 use hermes_ast::context::Context;
1557 use hermes_ast::node::Node;
1558 let mut sm = hermes_support::manager::SourceErrorManager::new();
1559 let mut ctx = Context::new();
1560 let gc = ctx.lock();
1561 let member = parse_one_class_member(&gc, &mut sm, "static s(){}");
1562 let Node::MethodDefinition(md) = member else {
1563 panic!("expected MethodDefinition, got {:?}", member.kind());
1564 };
1565 assert!(md.r#static.get(), "static flag set");
1566 }
1567
1568 #[test]
1570 fn class_private_method_key_is_private_name() {
1571 use hermes_ast::context::Context;
1572 use hermes_ast::node::Node;
1573 let mut sm = hermes_support::manager::SourceErrorManager::new();
1574 let mut ctx = Context::new();
1575 let gc = ctx.lock();
1576 let member = parse_one_class_member(&gc, &mut sm, "#p(){}");
1577 let Node::MethodDefinition(md) = member else {
1578 panic!("expected MethodDefinition, got {:?}", member.kind());
1579 };
1580 assert!(
1581 matches!(md.key, Node::PrivateName(_)),
1582 "method key is PrivateName, got {:?}",
1583 md.key.kind()
1584 );
1585 }
1586
1587 #[test]
1589 fn class_field_with_value() {
1590 use hermes_ast::context::Context;
1591 use hermes_ast::node::Node;
1592 let mut sm = hermes_support::manager::SourceErrorManager::new();
1593 let mut ctx = Context::new();
1594 let gc = ctx.lock();
1595 let member = parse_one_class_member(&gc, &mut sm, "x = 1;");
1596 let Node::ClassProperty(cp) = member else {
1597 panic!("expected ClassProperty, got {:?}", member.kind());
1598 };
1599 assert!(cp.value.is_some(), "field has a value");
1600 }
1601
1602 #[test]
1604 fn class_private_field() {
1605 use hermes_ast::context::Context;
1606 use hermes_ast::node::Node;
1607 let mut sm = hermes_support::manager::SourceErrorManager::new();
1608 let mut ctx = Context::new();
1609 let gc = ctx.lock();
1610 let member = parse_one_class_member(&gc, &mut sm, "#f;");
1611 assert!(
1612 matches!(member, Node::ClassPrivateProperty(_)),
1613 "expected ClassPrivateProperty, got {:?}",
1614 member.kind()
1615 );
1616 }
1617
1618 #[test]
1620 fn class_static_block() {
1621 use hermes_ast::context::Context;
1622 use hermes_ast::node::Node;
1623 let mut sm = hermes_support::manager::SourceErrorManager::new();
1624 let mut ctx = Context::new();
1625 let gc = ctx.lock();
1626 let member = parse_one_class_member(&gc, &mut sm, "static { }");
1627 assert!(
1628 matches!(member, Node::StaticBlock(_)),
1629 "expected StaticBlock, got {:?}",
1630 member.kind()
1631 );
1632 }
1633
1634 #[test]
1636 fn class_expression_parses() {
1637 use hermes_ast::context::Context;
1638 use hermes_ast::node::Node;
1639 let mut sm = hermes_support::manager::SourceErrorManager::new();
1640 let mut ctx = Context::new();
1641 let gc = ctx.lock();
1642 let atoms = &gc.ctx().atom_table;
1643 let expr = parse_expr_from(&gc, &mut sm, atoms, b"(class {});");
1644 assert!(
1645 matches!(expr, Node::ClassExpression(_)),
1646 "expected ClassExpression, got {:?}",
1647 expr.kind()
1648 );
1649 }
1650
1651 #[test]
1654 fn class_declaration_with_decorator() {
1655 use hermes_ast::context::Context;
1656 use hermes_ast::node::Node;
1657 let mut sm = hermes_support::manager::SourceErrorManager::new();
1658 let mut ctx = Context::new();
1659 let gc = ctx.lock();
1660 let stmt = parse_one_stmt(&gc, &mut sm, b"@dec class A {}");
1661 let Node::ClassDeclaration(cd) = stmt else {
1662 panic!("expected ClassDeclaration, got {:?}", stmt.kind());
1663 };
1664 let decorators: Vec<_> = cd.decorators.iter().collect();
1665 assert_eq!(decorators.len(), 1, "one decorator");
1666 assert!(
1667 matches!(decorators[0], Node::Decorator(_)),
1668 "expected Decorator node"
1669 );
1670 }
1671
1672 #[test]
1676 fn class_strict_mode_does_not_leak() {
1677 use hermes_ast::context::Context;
1678 use hermes_support::manager::SourceErrorManager;
1679
1680 let mut sm = SourceErrorManager::new();
1681 let buf_id = sm.add_buffer_bytes("input", b"class A {}\nwith(x) y;");
1682 let mut ctx = Context::new();
1683 let gc = ctx.lock();
1684 let atoms = &gc.ctx().atom_table;
1685 let lexer = crate::lexer::JSLexer::new(
1686 buf_id,
1687 &mut sm,
1688 atoms,
1689 crate::lexer::GrammarContext::AllowRegExp,
1690 );
1691 let mut parser = JSParserImpl::new(&gc, lexer);
1692 assert!(
1693 parser.parse().is_some(),
1694 "with-statement after class must parse (sloppy mode restored)"
1695 );
1696 assert_eq!(
1697 parser.error_count_pub(),
1698 0,
1699 "no errors: class strict mode must not leak to enclosing sloppy code"
1700 );
1701 }
1702
1703 #[test]
1709 fn import_call_no_options() {
1710 use hermes_ast::context::Context;
1711 use hermes_ast::node::Node;
1712 use hermes_support::manager::SourceErrorManager;
1713
1714 let mut sm = SourceErrorManager::new();
1715 let mut ctx = Context::new();
1716 let gc = ctx.lock();
1717 let atoms = &gc.ctx().atom_table;
1718
1719 let expr = parse_expr_from(&gc, &mut sm, atoms, b"import('m');");
1720 if let Node::ImportExpression(ie) = expr {
1721 assert!(
1722 matches!(ie.source, Node::StringLiteral(_)),
1723 "source should be a StringLiteral, got {:?}",
1724 ie.source.kind()
1725 );
1726 assert!(ie.options.is_none(), "options should be None");
1727 } else {
1728 panic!("expected ImportExpression, got {:?}", expr.kind());
1729 }
1730 }
1731
1732 #[test]
1733 fn import_call_with_options() {
1734 use hermes_ast::context::Context;
1735 use hermes_ast::node::Node;
1736 use hermes_support::manager::SourceErrorManager;
1737
1738 let mut sm = SourceErrorManager::new();
1739 let mut ctx = Context::new();
1740 let gc = ctx.lock();
1741 let atoms = &gc.ctx().atom_table;
1742
1743 let expr = parse_expr_from(&gc, &mut sm, atoms, b"import('m', {});");
1744 if let Node::ImportExpression(ie) = expr {
1745 assert!(
1746 matches!(ie.options, Some(Node::ObjectExpression(_))),
1747 "options should be Some(ObjectExpression), got {:?}",
1748 ie.options.map(|o| o.kind())
1749 );
1750 } else {
1751 panic!("expected ImportExpression, got {:?}", expr.kind());
1752 }
1753 }
1754
1755 #[test]
1756 fn import_meta_property() {
1757 use hermes_ast::context::Context;
1758 use hermes_ast::node::Node;
1759 use hermes_support::manager::SourceErrorManager;
1760
1761 let mut sm = SourceErrorManager::new();
1762 let mut ctx = Context::new();
1763 let gc = ctx.lock();
1764 let atoms = &gc.ctx().atom_table;
1765
1766 let expr = parse_expr_from(&gc, &mut sm, atoms, b"import.meta;");
1767 if let Node::MetaProperty(mp) = expr {
1768 if let Node::Identifier(meta) = mp.meta {
1769 assert_eq!(
1770 gc.ctx().atom_table.bytes(meta.name.get()),
1771 b"import",
1772 "meta identifier name should be `import`"
1773 );
1774 } else {
1775 panic!("meta should be an Identifier");
1776 }
1777 if let Node::Identifier(prop) = mp.property {
1778 assert_eq!(
1779 gc.ctx().atom_table.bytes(prop.name.get()),
1780 b"meta",
1781 "property identifier name should be `meta`"
1782 );
1783 } else {
1784 panic!("property should be an Identifier");
1785 }
1786 } else {
1787 panic!("expected MetaProperty, got {:?}", expr.kind());
1788 }
1789 }
1790
1791 #[test]
1792 fn import_meta_bad_form_errors() {
1793 assert_parse_errors(b"import.foo;", "'meta' expected after import.");
1794 }
1795
1796 #[test]
1800 fn import_meta_escaped_meta_parses() {
1801 use hermes_ast::context::Context;
1802 use hermes_ast::node::Node;
1803 use hermes_support::manager::SourceErrorManager;
1804
1805 let mut sm = SourceErrorManager::new();
1806 let mut ctx = Context::new();
1807 let gc = ctx.lock();
1808 let atoms = &gc.ctx().atom_table;
1809
1810 let expr =
1811 parse_expr_from(&gc, &mut sm, atoms, b"import.m\\u0065ta;");
1812 if let Node::MetaProperty(mp) = expr {
1813 if let Node::Identifier(prop) = mp.property {
1814 assert_eq!(
1815 gc.ctx().atom_table.bytes(prop.name.get()),
1816 b"meta",
1817 "escaped `m\\u0065ta` should intern to `meta`"
1818 );
1819 } else {
1820 panic!("property should be an Identifier");
1821 }
1822 } else {
1823 panic!("expected MetaProperty, got {:?}", expr.kind());
1824 }
1825 }
1826
1827 fn ident_bytes<'gc>(
1831 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
1832 node: &hermes_ast::node::Node<'gc>,
1833 ) -> Vec<u8> {
1834 if let hermes_ast::node::Node::Identifier(id) = node {
1835 gc.ctx().atom_table.bytes(id.name.get()).to_vec()
1836 } else {
1837 panic!("expected Identifier, got {:?}", node.kind());
1838 }
1839 }
1840
1841 #[test]
1842 fn import_default_specifier_parses() {
1843 use hermes_ast::context::Context;
1844 use hermes_ast::node::Node;
1845 let mut sm = hermes_support::manager::SourceErrorManager::new();
1846 let mut ctx = Context::new();
1847 let gc = ctx.lock();
1848 let stmt = parse_one_stmt(&gc, &mut sm, b"import x from 'm';");
1849 if let Node::ImportDeclaration(decl) = stmt {
1850 assert_eq!(decl.specifiers.iter().count(), 1);
1851 let spec = decl.specifiers.iter().next().unwrap();
1852 if let Node::ImportDefaultSpecifier(ds) = spec {
1853 assert_eq!(ident_bytes(&gc, ds.local), b"x");
1854 } else {
1855 panic!("expected ImportDefaultSpecifier, got {:?}", spec.kind());
1856 }
1857 if let Node::StringLiteral(sl) = decl.source {
1858 assert_eq!(gc.ctx().atom_table.bytes(sl.value.get()), b"m");
1859 } else {
1860 panic!("source should be a StringLiteral");
1861 }
1862 assert_eq!(
1863 gc.ctx().atom_table.bytes(decl.import_kind.get()),
1864 b"value"
1865 );
1866 } else {
1867 panic!("expected ImportDeclaration, got {:?}", stmt.kind());
1868 }
1869 }
1870
1871 #[test]
1872 fn import_named_specifier_parses() {
1873 use hermes_ast::context::Context;
1874 use hermes_ast::node::Node;
1875 let mut sm = hermes_support::manager::SourceErrorManager::new();
1876 let mut ctx = Context::new();
1877 let gc = ctx.lock();
1878 let stmt = parse_one_stmt(&gc, &mut sm, b"import {b as c} from 'm';");
1879 if let Node::ImportDeclaration(decl) = stmt {
1880 assert_eq!(decl.specifiers.iter().count(), 1);
1881 let spec = decl.specifiers.iter().next().unwrap();
1882 if let Node::ImportSpecifier(is) = spec {
1883 assert_eq!(ident_bytes(&gc, is.imported), b"b");
1884 assert_eq!(ident_bytes(&gc, is.local), b"c");
1885 } else {
1886 panic!("expected ImportSpecifier, got {:?}", spec.kind());
1887 }
1888 } else {
1889 panic!("expected ImportDeclaration, got {:?}", stmt.kind());
1890 }
1891 }
1892
1893 #[test]
1894 fn import_namespace_specifier_parses() {
1895 use hermes_ast::context::Context;
1896 use hermes_ast::node::Node;
1897 let mut sm = hermes_support::manager::SourceErrorManager::new();
1898 let mut ctx = Context::new();
1899 let gc = ctx.lock();
1900 let stmt = parse_one_stmt(&gc, &mut sm, b"import * as ns from 'm';");
1901 if let Node::ImportDeclaration(decl) = stmt {
1902 assert_eq!(decl.specifiers.iter().count(), 1);
1903 let spec = decl.specifiers.iter().next().unwrap();
1904 if let Node::ImportNamespaceSpecifier(ns) = spec {
1905 assert_eq!(ident_bytes(&gc, ns.local), b"ns");
1906 } else {
1907 panic!(
1908 "expected ImportNamespaceSpecifier, got {:?}",
1909 spec.kind()
1910 );
1911 }
1912 } else {
1913 panic!("expected ImportDeclaration, got {:?}", stmt.kind());
1914 }
1915 }
1916
1917 #[test]
1918 fn import_default_plus_named_parses() {
1919 use hermes_ast::context::Context;
1920 use hermes_ast::node::Node;
1921 let mut sm = hermes_support::manager::SourceErrorManager::new();
1922 let mut ctx = Context::new();
1923 let gc = ctx.lock();
1924 let stmt =
1925 parse_one_stmt(&gc, &mut sm, b"import d, {a, b} from 'm';");
1926 if let Node::ImportDeclaration(decl) = stmt {
1927 let specs: Vec<_> = decl.specifiers.iter().collect();
1928 assert_eq!(specs.len(), 3);
1929 assert!(matches!(specs[0], Node::ImportDefaultSpecifier(_)));
1930 assert!(matches!(specs[1], Node::ImportSpecifier(_)));
1931 assert!(matches!(specs[2], Node::ImportSpecifier(_)));
1932 } else {
1933 panic!("expected ImportDeclaration, got {:?}", stmt.kind());
1934 }
1935 }
1936
1937 #[test]
1938 fn import_default_plus_namespace_parses() {
1939 use hermes_ast::context::Context;
1940 use hermes_ast::node::Node;
1941 let mut sm = hermes_support::manager::SourceErrorManager::new();
1942 let mut ctx = Context::new();
1943 let gc = ctx.lock();
1944 let stmt =
1945 parse_one_stmt(&gc, &mut sm, b"import d, * as ns from 'm';");
1946 if let Node::ImportDeclaration(decl) = stmt {
1947 let specs: Vec<_> = decl.specifiers.iter().collect();
1948 assert_eq!(specs.len(), 2);
1949 assert!(matches!(specs[0], Node::ImportDefaultSpecifier(_)));
1950 assert!(matches!(specs[1], Node::ImportNamespaceSpecifier(_)));
1951 } else {
1952 panic!("expected ImportDeclaration, got {:?}", stmt.kind());
1953 }
1954 }
1955
1956 #[test]
1957 fn import_bare_parses() {
1958 use hermes_ast::context::Context;
1959 use hermes_ast::node::Node;
1960 let mut sm = hermes_support::manager::SourceErrorManager::new();
1961 let mut ctx = Context::new();
1962 let gc = ctx.lock();
1963 let stmt = parse_one_stmt(&gc, &mut sm, b"import 'm';");
1964 if let Node::ImportDeclaration(decl) = stmt {
1965 assert_eq!(decl.specifiers.iter().count(), 0);
1966 assert_eq!(decl.attributes.iter().count(), 0);
1967 if let Node::StringLiteral(sl) = decl.source {
1968 assert_eq!(gc.ctx().atom_table.bytes(sl.value.get()), b"m");
1969 } else {
1970 panic!("source should be a StringLiteral");
1971 }
1972 } else {
1973 panic!("expected ImportDeclaration, got {:?}", stmt.kind());
1974 }
1975 }
1976
1977 #[test]
1978 fn import_attribute_parses() {
1979 use hermes_ast::context::Context;
1980 use hermes_ast::node::Node;
1981 let mut sm = hermes_support::manager::SourceErrorManager::new();
1982 let mut ctx = Context::new();
1983 let gc = ctx.lock();
1984 let stmt = parse_one_stmt(
1985 &gc,
1986 &mut sm,
1987 b"import x from 'm' with { type: 'json' };",
1988 );
1989 if let Node::ImportDeclaration(decl) = stmt {
1990 assert_eq!(decl.attributes.iter().count(), 1);
1991 let attr = decl.attributes.iter().next().unwrap();
1992 if let Node::ImportAttribute(ia) = attr {
1993 assert_eq!(ident_bytes(&gc, ia.key), b"type");
1994 if let Node::StringLiteral(sl) = ia.value {
1995 assert_eq!(
1996 gc.ctx().atom_table.bytes(sl.value.get()),
1997 b"json"
1998 );
1999 } else {
2000 panic!("attribute value should be a StringLiteral");
2001 }
2002 } else {
2003 panic!("expected ImportAttribute, got {:?}", attr.kind());
2004 }
2005 } else {
2006 panic!("expected ImportDeclaration, got {:?}", stmt.kind());
2007 }
2008 }
2009
2010 #[test]
2011 fn import_duplicate_named_errors() {
2012 assert_parse_has_errors(
2013 b"import {a, a} from 'm';",
2014 "duplicate named import is a Duplicate entry error",
2015 );
2016 }
2017
2018 #[test]
2019 fn import_in_block_errors() {
2020 assert_parse_has_errors(
2023 b"{ import x from 'm'; }",
2024 "import inside a block must be at top level of module",
2025 );
2026 }
2027
2028 #[test]
2031 fn export_named_specifier_parses() {
2032 use hermes_ast::context::Context;
2033 use hermes_ast::node::Node;
2034 let mut sm = hermes_support::manager::SourceErrorManager::new();
2035 let mut ctx = Context::new();
2036 let gc = ctx.lock();
2037 let buf_id = sm.add_buffer_bytes("input", b"var a;\nexport {a as b};");
2039 let atoms = &gc.ctx().atom_table;
2040 let lexer = crate::lexer::JSLexer::new(
2041 buf_id,
2042 &mut sm,
2043 atoms,
2044 crate::lexer::GrammarContext::AllowRegExp,
2045 );
2046 let mut parser = JSParserImpl::new(&gc, lexer);
2047 let program = parser.parse().expect("parse succeeded");
2048 assert_eq!(parser.error_count_pub(), 0, "zero errors");
2049 let Node::Program(p) = program else {
2050 panic!("expected Program")
2051 };
2052 let stmt = p.body.iter().nth(1).expect("has second statement");
2053 if let Node::ExportNamedDeclaration(decl) = stmt {
2054 assert!(decl.declaration.is_none(), "declaration None");
2055 assert!(decl.source.is_none(), "source None");
2056 assert_eq!(
2057 gc.ctx().atom_table.bytes(decl.export_kind.get()),
2058 b"value"
2059 );
2060 assert_eq!(decl.specifiers.iter().count(), 1);
2061 let spec = decl.specifiers.iter().next().unwrap();
2062 if let Node::ExportSpecifier(es) = spec {
2063 assert_eq!(ident_bytes(&gc, es.exported), b"b");
2064 assert_eq!(ident_bytes(&gc, es.local), b"a");
2065 } else {
2066 panic!("expected ExportSpecifier, got {:?}", spec.kind());
2067 }
2068 } else {
2069 panic!("expected ExportNamedDeclaration, got {:?}", stmt.kind());
2070 }
2071 }
2072
2073 #[test]
2074 fn export_named_from_parses() {
2075 use hermes_ast::context::Context;
2076 use hermes_ast::node::Node;
2077 let mut sm = hermes_support::manager::SourceErrorManager::new();
2078 let mut ctx = Context::new();
2079 let gc = ctx.lock();
2080 let stmt = parse_one_stmt(&gc, &mut sm, b"export {a} from 'm';");
2081 if let Node::ExportNamedDeclaration(decl) = stmt {
2082 if let Some(Node::StringLiteral(sl)) = decl.source {
2083 assert_eq!(gc.ctx().atom_table.bytes(sl.value.get()), b"m");
2084 } else {
2085 panic!("source should be a StringLiteral");
2086 }
2087 } else {
2088 panic!("expected ExportNamedDeclaration, got {:?}", stmt.kind());
2089 }
2090 }
2091
2092 #[test]
2093 fn export_all_parses() {
2094 use hermes_ast::context::Context;
2095 use hermes_ast::node::Node;
2096 let mut sm = hermes_support::manager::SourceErrorManager::new();
2097 let mut ctx = Context::new();
2098 let gc = ctx.lock();
2099 let stmt = parse_one_stmt(&gc, &mut sm, b"export * from 'm';");
2100 if let Node::ExportAllDeclaration(decl) = stmt {
2101 if let Node::StringLiteral(sl) = decl.source {
2102 assert_eq!(gc.ctx().atom_table.bytes(sl.value.get()), b"m");
2103 } else {
2104 panic!("source should be a StringLiteral");
2105 }
2106 } else {
2107 panic!("expected ExportAllDeclaration, got {:?}", stmt.kind());
2108 }
2109 }
2110
2111 #[test]
2112 fn export_namespace_parses() {
2113 use hermes_ast::context::Context;
2114 use hermes_ast::node::Node;
2115 let mut sm = hermes_support::manager::SourceErrorManager::new();
2116 let mut ctx = Context::new();
2117 let gc = ctx.lock();
2118 let stmt = parse_one_stmt(&gc, &mut sm, b"export * as ns from 'm';");
2119 if let Node::ExportNamedDeclaration(decl) = stmt {
2120 assert_eq!(decl.specifiers.iter().count(), 1);
2121 let spec = decl.specifiers.iter().next().unwrap();
2122 if let Node::ExportNamespaceSpecifier(ns) = spec {
2123 assert_eq!(ident_bytes(&gc, ns.exported), b"ns");
2124 } else {
2125 panic!("expected ExportNamespaceSpecifier, got {:?}", spec.kind());
2126 }
2127 } else {
2128 panic!("expected ExportNamedDeclaration, got {:?}", stmt.kind());
2129 }
2130 }
2131
2132 #[test]
2133 fn export_default_expr_parses() {
2134 use hermes_ast::context::Context;
2135 use hermes_ast::node::Node;
2136 let mut sm = hermes_support::manager::SourceErrorManager::new();
2137 let mut ctx = Context::new();
2138 let gc = ctx.lock();
2139 let stmt = parse_one_stmt(&gc, &mut sm, b"export default 1;");
2140 if let Node::ExportDefaultDeclaration(decl) = stmt {
2141 assert!(
2142 matches!(decl.declaration, Node::NumericLiteral(_)),
2143 "declaration should be a NumericLiteral, got {:?}",
2144 decl.declaration.kind()
2145 );
2146 } else {
2147 panic!("expected ExportDefaultDeclaration, got {:?}", stmt.kind());
2148 }
2149 }
2150
2151 #[test]
2152 fn export_default_function_parses() {
2153 use hermes_ast::context::Context;
2154 use hermes_ast::node::Node;
2155 let mut sm = hermes_support::manager::SourceErrorManager::new();
2156 let mut ctx = Context::new();
2157 let gc = ctx.lock();
2158 let stmt = parse_one_stmt(&gc, &mut sm, b"export default function(){}");
2159 if let Node::ExportDefaultDeclaration(decl) = stmt {
2160 if let Node::FunctionDeclaration(fd) = decl.declaration {
2161 assert!(fd.id.is_none(), "default function has no id");
2162 } else {
2163 panic!(
2164 "declaration should be a FunctionDeclaration, got {:?}",
2165 decl.declaration.kind()
2166 );
2167 }
2168 } else {
2169 panic!("expected ExportDefaultDeclaration, got {:?}", stmt.kind());
2170 }
2171 }
2172
2173 #[test]
2174 fn export_var_declaration_parses() {
2175 use hermes_ast::context::Context;
2176 use hermes_ast::node::Node;
2177 let mut sm = hermes_support::manager::SourceErrorManager::new();
2178 let mut ctx = Context::new();
2179 let gc = ctx.lock();
2180 let stmt = parse_one_stmt(&gc, &mut sm, b"export var x = 1;");
2181 if let Node::ExportNamedDeclaration(decl) = stmt {
2182 assert!(
2183 matches!(decl.declaration, Some(Node::VariableDeclaration(_))),
2184 "declaration should be a VariableDeclaration, got {:?}",
2185 decl.declaration.map(|d| d.kind())
2186 );
2187 } else {
2188 panic!("expected ExportNamedDeclaration, got {:?}", stmt.kind());
2189 }
2190 }
2191
2192 #[test]
2193 fn export_function_declaration_parses() {
2194 use hermes_ast::context::Context;
2195 use hermes_ast::node::Node;
2196 let mut sm = hermes_support::manager::SourceErrorManager::new();
2197 let mut ctx = Context::new();
2198 let gc = ctx.lock();
2199 let stmt = parse_one_stmt(&gc, &mut sm, b"export function f(){}");
2200 if let Node::ExportNamedDeclaration(decl) = stmt {
2201 assert!(
2202 matches!(decl.declaration, Some(Node::FunctionDeclaration(_))),
2203 "declaration should be a FunctionDeclaration, got {:?}",
2204 decl.declaration.map(|d| d.kind())
2205 );
2206 } else {
2207 panic!("expected ExportNamedDeclaration, got {:?}", stmt.kind());
2208 }
2209 }
2210
2211 #[test]
2212 fn export_in_block_errors() {
2213 assert_parse_has_errors(
2217 b"{ export var x = 1; }",
2218 "export inside a block must be at top level of module",
2219 );
2220 }
2221
2222 fn assert_flow_export_kind(src: &[u8], kind: &[u8]) {
2228 use hermes_ast::context::Context;
2229 use hermes_ast::node::Node;
2230 let mut sm = hermes_support::manager::SourceErrorManager::new();
2231 let mut ctx = Context::new();
2232 ctx.set_parse_flow(true);
2233 let gc = ctx.lock();
2234 let stmt = flow_parse_stmt_at(&gc, &mut sm, src, 0);
2235 let Node::ExportNamedDeclaration(decl) = stmt else {
2236 panic!("expected ExportNamedDeclaration, got {:?}", stmt.kind())
2237 };
2238 assert_eq!(
2239 gc.ctx().atom_table.bytes(decl.export_kind.get()),
2240 kind,
2241 "exportKind for {:?}",
2242 String::from_utf8_lossy(src)
2243 );
2244 }
2245
2246 #[test]
2250 fn flow_export_type_alias_kind_is_type() {
2251 assert_flow_export_kind(b"export type A = number;", b"type");
2252 }
2253
2254 #[test]
2257 fn flow_export_opaque_type_kind_is_type() {
2258 assert_flow_export_kind(b"export opaque type B = string;", b"type");
2259 }
2260
2261 #[test]
2264 fn flow_export_interface_kind_is_type() {
2265 assert_flow_export_kind(b"export interface I { x: number }", b"type");
2266 }
2267
2268 #[test]
2270 fn flow_export_value_kinds_stay_value() {
2271 assert_flow_export_kind(b"export var x = 1;", b"value");
2272 assert_flow_export_kind(b"export function f(){}", b"value");
2273 }
2274
2275 #[test]
2279 fn export_type_without_flow_errors() {
2280 assert_parse_has_errors(
2281 b"export type A = 1;",
2282 "export type without Flow is not a declaration",
2283 );
2284 }
2285
2286 #[test]
2290 fn flow_export_type_clause_and_star_have_type_kind() {
2291 use hermes_ast::context::Context;
2292 use hermes_ast::node::Node;
2293 assert_flow_export_kind(b"export type {x};", b"type");
2294 assert_flow_export_kind(b"export type {x} from 'm';", b"type");
2295
2296 let mut sm = hermes_support::manager::SourceErrorManager::new();
2298 let mut ctx = Context::new();
2299 ctx.set_parse_flow(true);
2300 let gc = ctx.lock();
2301 let stmt =
2302 flow_parse_stmt_at(&gc, &mut sm, b"export type * from 'm';", 0);
2303 let Node::ExportAllDeclaration(decl) = stmt else {
2304 panic!("expected ExportAllDeclaration, got {:?}", stmt.kind())
2305 };
2306 assert_eq!(
2307 gc.ctx().atom_table.bytes(decl.export_kind.get()),
2308 b"type"
2309 );
2310 }
2311
2312 #[test]
2314 fn array_literal_parses() {
2315 use hermes_ast::context::Context;
2316 use hermes_support::manager::SourceErrorManager;
2317
2318 let mut sm = SourceErrorManager::new();
2319 let buf_id = sm.add_buffer_bytes("input", b"[1];");
2320 let mut ctx = Context::new();
2321 let gc = ctx.lock();
2322 let atoms = &gc.ctx().atom_table;
2323 let lexer = crate::lexer::JSLexer::new(
2324 buf_id,
2325 &mut sm,
2326 atoms,
2327 crate::lexer::GrammarContext::AllowRegExp,
2328 );
2329 let mut parser = JSParserImpl::new(&gc, lexer);
2330 assert!(
2331 parser.parse().is_some(),
2332 "array literal should parse successfully in P1.7"
2333 );
2334 assert_eq!(parser.error_count_pub(), 0);
2335 }
2336
2337 #[test]
2338 fn parses_sequence_expression() {
2339 use hermes_ast::context::Context;
2340 use hermes_ast::node::Node;
2341 use hermes_support::manager::SourceErrorManager;
2342
2343 let mut sm = SourceErrorManager::new();
2344 let buf_id = sm.add_buffer_bytes("input", b"1, 2, 3;");
2345 let mut ctx = Context::new();
2346 let gc = ctx.lock();
2347 let atoms = &gc.ctx().atom_table;
2348 let lexer = crate::lexer::JSLexer::new(
2349 buf_id,
2350 &mut sm,
2351 atoms,
2352 crate::lexer::GrammarContext::AllowRegExp,
2353 );
2354 let mut parser = JSParserImpl::new(&gc, lexer);
2355 let program = parser.parse().expect("1, 2, 3; parses");
2356 assert_eq!(parser.error_count_pub(), 0);
2357 if let Node::Program(p) = program {
2358 assert_eq!(p.body.iter().count(), 1);
2359 let stmt = p.body.iter().next().unwrap();
2360 if let Node::ExpressionStatement(es) = stmt {
2361 assert!(
2362 matches!(es.expression, Node::SequenceExpression(_)),
2363 "expected SequenceExpression"
2364 );
2365 } else {
2366 panic!("expected ExpressionStatement");
2367 }
2368 }
2369 }
2370
2371 #[test]
2372 fn use_strict_directive_sets_strict_mode() {
2373 use hermes_ast::context::Context;
2374 use hermes_ast::node::Node;
2375 use hermes_support::manager::SourceErrorManager;
2376
2377 let mut sm = SourceErrorManager::new();
2378 let buf_id = sm.add_buffer_bytes("input", b"\"use strict\"; 1;");
2379 let mut ctx = Context::new();
2380 let gc = ctx.lock();
2381 let atoms = &gc.ctx().atom_table;
2382 let lexer = crate::lexer::JSLexer::new(
2383 buf_id,
2384 &mut sm,
2385 atoms,
2386 crate::lexer::GrammarContext::AllowRegExp,
2387 );
2388 let mut parser = JSParserImpl::new(&gc, lexer);
2389 let program = parser.parse().expect("\"use strict\"; 1; parses");
2390 assert_eq!(parser.error_count_pub(), 0);
2391 if let Node::Program(p) = program {
2392 assert_eq!(p.body.iter().count(), 2);
2394 }
2395 assert!(parser.lexer.is_strict_mode());
2397 }
2398
2399 fn parse_expr_from<'gc>(
2404 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
2405 sm: &mut hermes_support::manager::SourceErrorManager,
2406 atoms: &hermes_atom_table::AtomTable,
2407 src: &[u8],
2408 ) -> &'gc hermes_ast::node::Node<'gc> {
2409 let buf_id = sm.add_buffer_bytes("input", src);
2410 let lexer = crate::lexer::JSLexer::new(
2411 buf_id,
2412 sm,
2413 atoms,
2414 crate::lexer::GrammarContext::AllowRegExp,
2415 );
2416 let mut parser = JSParserImpl::new(gc, lexer);
2417 let program = parser.parse().expect("parse succeeded");
2418 assert_eq!(parser.error_count_pub(), 0, "zero errors");
2419 if let hermes_ast::node::Node::Program(p) = program {
2420 let stmt = p.body.iter().next().expect("has statement");
2421 if let hermes_ast::node::Node::ExpressionStatement(es) = stmt {
2422 return es.expression;
2423 }
2424 }
2425 panic!("expected ExpressionStatement");
2426 }
2427
2428 #[test]
2429 fn parses_simple_assignment() {
2430 use hermes_ast::context::Context;
2431 use hermes_ast::node::Node;
2432 use hermes_support::manager::SourceErrorManager;
2433
2434 let mut sm = SourceErrorManager::new();
2435 let mut ctx = Context::new();
2436 let gc = ctx.lock();
2437 let atoms = &gc.ctx().atom_table;
2438
2439 let expr = parse_expr_from(&gc, &mut sm, atoms, b"a = b;");
2440 match expr {
2441 Node::AssignmentExpression(n) => {
2442 let op_bytes = gc.ctx().atom_table.bytes(n.operator.get());
2443 assert_eq!(op_bytes, b"=", "operator is =");
2444 assert!(
2445 matches!(n.left, Node::Identifier(_)),
2446 "left is Identifier"
2447 );
2448 assert!(
2449 matches!(n.right, Node::Identifier(_)),
2450 "right is Identifier"
2451 );
2452 }
2453 other => panic!("expected AssignmentExpression, got {:?}", other.kind()),
2454 }
2455 }
2456
2457 #[test]
2458 fn parses_compound_assignment_plus() {
2459 use hermes_ast::context::Context;
2460 use hermes_ast::node::Node;
2461 use hermes_support::manager::SourceErrorManager;
2462
2463 let mut sm = SourceErrorManager::new();
2464 let mut ctx = Context::new();
2465 let gc = ctx.lock();
2466 let atoms = &gc.ctx().atom_table;
2467
2468 let expr = parse_expr_from(&gc, &mut sm, atoms, b"a += 1;");
2469 match expr {
2470 Node::AssignmentExpression(n) => {
2471 let op_bytes = gc.ctx().atom_table.bytes(n.operator.get());
2472 assert_eq!(op_bytes, b"+=", "operator is +=");
2473 }
2474 other => panic!("expected AssignmentExpression, got {:?}", other.kind()),
2475 }
2476 }
2477
2478 #[test]
2479 fn parses_right_assoc_chain() {
2480 use hermes_ast::context::Context;
2482 use hermes_ast::node::Node;
2483 use hermes_support::manager::SourceErrorManager;
2484
2485 let mut sm = SourceErrorManager::new();
2486 let mut ctx = Context::new();
2487 let gc = ctx.lock();
2488 let atoms = &gc.ctx().atom_table;
2489
2490 let expr = parse_expr_from(&gc, &mut sm, atoms, b"a = b = c;");
2491 match expr {
2492 Node::AssignmentExpression(outer) => {
2493 assert!(
2495 matches!(outer.left, Node::Identifier(_)),
2496 "outer.left is Identifier(a)"
2497 );
2498 match outer.right {
2500 Node::AssignmentExpression(inner) => {
2501 let inner_left = match inner.left {
2502 Node::Identifier(id) => id,
2503 other => panic!(
2504 "expected Identifier(b), got {:?}",
2505 other.kind()
2506 ),
2507 };
2508 let b_bytes = gc.ctx().atom_table.bytes(inner_left.name.get());
2509 assert_eq!(b_bytes, b"b", "inner.left is b");
2510 assert!(
2511 matches!(inner.right, Node::Identifier(_)),
2512 "inner.right is Identifier(c)"
2513 );
2514 }
2515 other => panic!(
2516 "outer.right must be AssignmentExpression(b=c), got {:?}",
2517 other.kind()
2518 ),
2519 }
2520 }
2521 other => panic!("expected AssignmentExpression, got {:?}", other.kind()),
2522 }
2523 }
2524
2525 #[test]
2526 fn assignment_not_confused_with_equality() {
2527 use hermes_ast::context::Context;
2529 use hermes_ast::node::Node;
2530 use hermes_support::manager::SourceErrorManager;
2531
2532 let mut sm = SourceErrorManager::new();
2533 let mut ctx = Context::new();
2534 let gc = ctx.lock();
2535 let atoms = &gc.ctx().atom_table;
2536
2537 let expr = parse_expr_from(&gc, &mut sm, atoms, b"a == b;");
2538 assert!(
2539 matches!(expr, Node::BinaryExpression(_)),
2540 "== produces BinaryExpression, not AssignmentExpression"
2541 );
2542 }
2543
2544 #[test]
2545 fn arrow_expr_parses_after_p33() {
2546 use hermes_ast::context::Context;
2548 use hermes_support::manager::SourceErrorManager;
2549
2550 let mut sm = SourceErrorManager::new();
2551 let buf_id = sm.add_buffer_bytes("input", b"a => b;");
2552 let mut ctx = Context::new();
2553 let gc = ctx.lock();
2554 let atoms = &gc.ctx().atom_table;
2555 let lexer = crate::lexer::JSLexer::new(
2556 buf_id,
2557 &mut sm,
2558 atoms,
2559 crate::lexer::GrammarContext::AllowRegExp,
2560 );
2561 let mut parser = JSParserImpl::new(&gc, lexer);
2562 assert!(parser.parse().is_some(), "arrow should parse in P3.3");
2563 assert_eq!(parser.error_count_pub(), 0, "no errors");
2564 }
2565
2566 fn parse_snippet(sm: &mut hermes_support::manager::SourceErrorManager, src: &[u8]) -> bool {
2570 use hermes_ast::context::Context;
2571 let buf_id = sm.add_buffer_bytes("input", src);
2572 let mut ctx = Context::new();
2573 let gc = ctx.lock();
2574 let atoms = &gc.ctx().atom_table;
2575 let lexer = crate::lexer::JSLexer::new(
2576 buf_id,
2577 sm,
2578 atoms,
2579 crate::lexer::GrammarContext::AllowRegExp,
2580 );
2581 let mut parser = JSParserImpl::new(&gc, lexer);
2582 let result = parser.parse();
2583 result.is_some() && parser.error_count_pub() == 0
2584 }
2585
2586 #[test]
2587 fn object_literal_empty_parses() {
2588 let mut sm = hermes_support::manager::SourceErrorManager::new();
2589 assert!(parse_snippet(&mut sm, b"({});"), "empty object literal");
2590 }
2591
2592 #[test]
2593 fn object_literal_keyed_parses() {
2594 let mut sm = hermes_support::manager::SourceErrorManager::new();
2595 assert!(parse_snippet(&mut sm, b"({a: 1, b: 2});"), "keyed properties");
2596 }
2597
2598 #[test]
2599 fn object_literal_shorthand_parses() {
2600 let mut sm = hermes_support::manager::SourceErrorManager::new();
2601 assert!(parse_snippet(&mut sm, b"({a, b});"), "shorthand properties");
2602 }
2603
2604 #[test]
2605 fn object_literal_computed_parses() {
2606 let mut sm = hermes_support::manager::SourceErrorManager::new();
2607 assert!(parse_snippet(&mut sm, b"({[x]: 1});"), "computed key");
2608 }
2609
2610 #[test]
2611 fn object_literal_spread_parses() {
2612 let mut sm = hermes_support::manager::SourceErrorManager::new();
2613 assert!(parse_snippet(&mut sm, b"({...a});"), "spread element");
2614 }
2615
2616 #[test]
2617 fn object_literal_string_and_number_keys_parse() {
2618 let mut sm = hermes_support::manager::SourceErrorManager::new();
2619 assert!(
2620 parse_snippet(&mut sm, b"({\"s\": 1, 0: 2});"),
2621 "string and number keys"
2622 );
2623 }
2624
2625 #[test]
2626 fn object_literal_get_set_as_data_property() {
2627 let mut sm = hermes_support::manager::SourceErrorManager::new();
2629 assert!(
2630 parse_snippet(&mut sm, b"({get: 1, set: 2});"),
2631 "get/set as data properties"
2632 );
2633 assert!(
2634 parse_snippet(&mut sm, b"({get, set});"),
2635 "get/set shorthand"
2636 );
2637 }
2638
2639 #[test]
2640 fn object_literal_async_as_data_property() {
2641 let mut sm = hermes_support::manager::SourceErrorManager::new();
2643 assert!(
2644 parse_snippet(&mut sm, b"({async: 1});"),
2645 "async as data property"
2646 );
2647 assert!(
2648 parse_snippet(&mut sm, b"({async});"),
2649 "async shorthand"
2650 );
2651 }
2652
2653 #[test]
2654 fn object_literal_cover_initializer_parses() {
2655 let mut sm = hermes_support::manager::SourceErrorManager::new();
2657 assert!(
2658 parse_snippet(&mut sm, b"({a=1});"),
2659 "CoverInitializedName must parse"
2660 );
2661 }
2662
2663 fn parse_single_property<'gc>(
2668 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
2669 sm: &mut hermes_support::manager::SourceErrorManager,
2670 src: &[u8],
2671 ) -> &'gc hermes_ast::node::Property<'gc> {
2672 use hermes_ast::node::Node;
2673 let expr = parse_expr_ok(gc, sm, src);
2674 let Node::ObjectExpression(obj) = expr else {
2675 panic!("expected ObjectExpression, got {:?}", expr.kind());
2676 };
2677 let props: Vec<_> = obj.properties.iter().collect();
2678 assert_eq!(props.len(), 1, "expected exactly one property");
2679 match props[0] {
2680 Node::Property(p) => p,
2681 other => panic!("expected Property, got {:?}", other.kind()),
2682 }
2683 }
2684
2685 #[test]
2686 fn object_getter_parses() {
2687 use hermes_ast::context::Context;
2689 use hermes_ast::node::Node;
2690 let mut sm = hermes_support::manager::SourceErrorManager::new();
2691 let mut ctx = Context::new();
2692 let gc = ctx.lock();
2693 let p = parse_single_property(&gc, &mut sm, b"({get x() { return 1; }});");
2694 assert_eq!(gc.ctx().atom_table.bytes(p.kind.get()), b"get");
2695 assert!(!p.method.get(), "getter is not a method");
2696 assert!(!p.computed.get());
2697 let Node::FunctionExpression(f) = p.value else {
2698 panic!("getter value must be FunctionExpression");
2699 };
2700 assert_eq!(f.params.iter().count(), 0, "getter has no params");
2701 assert!(!f.generator.get());
2702 assert!(!f.r#async.get());
2703 }
2704
2705 #[test]
2706 fn object_setter_parses() {
2707 use hermes_ast::context::Context;
2709 use hermes_ast::node::Node;
2710 let mut sm = hermes_support::manager::SourceErrorManager::new();
2711 let mut ctx = Context::new();
2712 let gc = ctx.lock();
2713 let p = parse_single_property(&gc, &mut sm, b"({set x(v) {}});");
2714 assert_eq!(gc.ctx().atom_table.bytes(p.kind.get()), b"set");
2715 assert!(!p.method.get(), "setter is not a method");
2716 let Node::FunctionExpression(f) = p.value else {
2717 panic!("setter value must be FunctionExpression");
2718 };
2719 assert_eq!(f.params.iter().count(), 1, "setter has one param");
2720 }
2721
2722 #[test]
2723 fn object_method_parses() {
2724 use hermes_ast::context::Context;
2726 use hermes_ast::node::Node;
2727 let mut sm = hermes_support::manager::SourceErrorManager::new();
2728 let mut ctx = Context::new();
2729 let gc = ctx.lock();
2730 let p = parse_single_property(&gc, &mut sm, b"({m() {}});");
2731 assert_eq!(gc.ctx().atom_table.bytes(p.kind.get()), b"init");
2732 assert!(p.method.get(), "plain method has method=true");
2733 assert!(!p.shorthand.get());
2734 let Node::FunctionExpression(f) = p.value else {
2735 panic!("method value must be FunctionExpression");
2736 };
2737 assert!(!f.generator.get());
2738 assert!(!f.r#async.get());
2739 }
2740
2741 #[test]
2742 fn object_generator_method_parses() {
2743 use hermes_ast::context::Context;
2745 use hermes_ast::node::Node;
2746 let mut sm = hermes_support::manager::SourceErrorManager::new();
2747 let mut ctx = Context::new();
2748 let gc = ctx.lock();
2749 let p = parse_single_property(&gc, &mut sm, b"({*g() {}});");
2750 assert!(p.method.get());
2751 let Node::FunctionExpression(f) = p.value else {
2752 panic!("generator method value must be FunctionExpression");
2753 };
2754 assert!(f.generator.get(), "generator==true");
2755 assert!(!f.r#async.get());
2756 }
2757
2758 #[test]
2759 fn object_async_method_parses() {
2760 use hermes_ast::context::Context;
2762 use hermes_ast::node::Node;
2763 let mut sm = hermes_support::manager::SourceErrorManager::new();
2764 let mut ctx = Context::new();
2765 let gc = ctx.lock();
2766 let p = parse_single_property(&gc, &mut sm, b"({async a() {}});");
2767 assert!(p.method.get());
2768 let Node::FunctionExpression(f) = p.value else {
2769 panic!("async method value must be FunctionExpression");
2770 };
2771 assert!(f.r#async.get(), "async==true");
2772 assert!(!f.generator.get());
2773 }
2774
2775 #[test]
2776 fn object_async_generator_method_parses() {
2777 use hermes_ast::context::Context;
2779 use hermes_ast::node::Node;
2780 let mut sm = hermes_support::manager::SourceErrorManager::new();
2781 let mut ctx = Context::new();
2782 let gc = ctx.lock();
2783 let p = parse_single_property(&gc, &mut sm, b"({async *ag() {}});");
2784 assert!(p.method.get());
2785 let Node::FunctionExpression(f) = p.value else {
2786 panic!("async generator method value must be FunctionExpression");
2787 };
2788 assert!(f.r#async.get(), "async==true");
2789 assert!(f.generator.get(), "generator==true");
2790 }
2791
2792 #[test]
2793 fn object_computed_method_parses() {
2794 use hermes_ast::context::Context;
2796 use hermes_ast::node::Node;
2797 let mut sm = hermes_support::manager::SourceErrorManager::new();
2798 let mut ctx = Context::new();
2799 let gc = ctx.lock();
2800 let p = parse_single_property(&gc, &mut sm, b"({[k]() {}});");
2801 assert!(p.computed.get(), "computed key");
2802 assert!(p.method.get());
2803 assert!(matches!(p.value, Node::FunctionExpression(_)));
2804 }
2805
2806 #[test]
2807 fn object_string_and_numeric_methods_parse() {
2808 let mut sm = hermes_support::manager::SourceErrorManager::new();
2810 assert!(
2811 parse_snippet(&mut sm, b"({'s'() {}, 0() {}});"),
2812 "string- and numeric-keyed methods"
2813 );
2814 }
2815
2816 fn parse_expr_ok<'gc>(
2820 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
2821 sm: &mut hermes_support::manager::SourceErrorManager,
2822 src: &[u8],
2823 ) -> &'gc hermes_ast::node::Node<'gc> {
2824 let buf_id = sm.add_buffer_bytes("input", src);
2825 let atoms = &gc.ctx().atom_table;
2826 let lexer = crate::lexer::JSLexer::new(
2827 buf_id,
2828 sm,
2829 atoms,
2830 crate::lexer::GrammarContext::AllowRegExp,
2831 );
2832 let mut parser = JSParserImpl::new(gc, lexer);
2833 let program = parser.parse().expect("parse succeeded");
2834 assert_eq!(parser.error_count_pub(), 0, "zero errors");
2835 if let hermes_ast::node::Node::Program(p) = program {
2836 let stmt = p.body.iter().next().expect("has statement");
2837 if let hermes_ast::node::Node::ExpressionStatement(es) = stmt {
2838 return es.expression;
2839 }
2840 }
2841 panic!("expected ExpressionStatement");
2842 }
2843
2844 #[test]
2845 fn array_destructure_simple() {
2846 use hermes_ast::context::Context;
2848 use hermes_ast::node::Node;
2849 let mut sm = hermes_support::manager::SourceErrorManager::new();
2850 let mut ctx = Context::new();
2851 let gc = ctx.lock();
2852 let expr = parse_expr_ok(&gc, &mut sm, b"[a] = b;");
2853 match expr {
2854 Node::AssignmentExpression(asn) => {
2855 let op = gc.ctx().atom_table.bytes(asn.operator.get());
2856 assert_eq!(op, b"=");
2857 assert!(
2858 matches!(asn.left, Node::ArrayPattern(_)),
2859 "left is ArrayPattern, got {:?}",
2860 asn.left.kind()
2861 );
2862 }
2863 other => panic!("expected AssignmentExpression, got {:?}", other.kind()),
2864 }
2865 }
2866
2867 #[test]
2868 fn array_destructure_with_rest() {
2869 use hermes_ast::context::Context;
2871 use hermes_ast::node::Node;
2872 let mut sm = hermes_support::manager::SourceErrorManager::new();
2873 let mut ctx = Context::new();
2874 let gc = ctx.lock();
2875 let expr = parse_expr_ok(&gc, &mut sm, b"[a, ...b] = c;");
2876 if let Node::AssignmentExpression(asn) = expr {
2877 if let Node::ArrayPattern(ap) = asn.left {
2878 let elems: Vec<_> = ap.elements.iter().collect();
2879 assert_eq!(elems.len(), 2);
2880 assert!(matches!(elems[0], Node::Identifier(_)));
2881 assert!(matches!(elems[1], Node::RestElement(_)));
2882 } else {
2883 panic!("left must be ArrayPattern");
2884 }
2885 } else {
2886 panic!("expected AssignmentExpression");
2887 }
2888 }
2889
2890 #[test]
2891 fn array_destructure_with_hole() {
2892 use hermes_ast::context::Context;
2894 use hermes_ast::node::Node;
2895 let mut sm = hermes_support::manager::SourceErrorManager::new();
2896 let mut ctx = Context::new();
2897 let gc = ctx.lock();
2898 let expr = parse_expr_ok(&gc, &mut sm, b"[a, , b] = c;");
2899 if let Node::AssignmentExpression(asn) = expr {
2900 if let Node::ArrayPattern(ap) = asn.left {
2901 let elems: Vec<_> = ap.elements.iter().collect();
2902 assert_eq!(elems.len(), 3);
2903 assert!(matches!(elems[0], Node::Identifier(_)));
2904 assert!(matches!(elems[1], Node::Empty(_)));
2905 assert!(matches!(elems[2], Node::Identifier(_)));
2906 } else {
2907 panic!("left must be ArrayPattern");
2908 }
2909 } else {
2910 panic!("expected AssignmentExpression");
2911 }
2912 }
2913
2914 #[test]
2915 fn array_destructure_with_default() {
2916 use hermes_ast::context::Context;
2918 use hermes_ast::node::Node;
2919 let mut sm = hermes_support::manager::SourceErrorManager::new();
2920 let mut ctx = Context::new();
2921 let gc = ctx.lock();
2922 let expr = parse_expr_ok(&gc, &mut sm, b"[a = 1, b] = c;");
2923 if let Node::AssignmentExpression(asn) = expr {
2924 if let Node::ArrayPattern(ap) = asn.left {
2925 let elems: Vec<_> = ap.elements.iter().collect();
2926 assert_eq!(elems.len(), 2);
2927 assert!(
2928 matches!(elems[0], Node::AssignmentPattern(_)),
2929 "first element is AssignmentPattern"
2930 );
2931 assert!(matches!(elems[1], Node::Identifier(_)));
2932 } else {
2933 panic!("left must be ArrayPattern");
2934 }
2935 } else {
2936 panic!("expected AssignmentExpression");
2937 }
2938 }
2939
2940 #[test]
2941 fn object_destructure_shorthand() {
2942 use hermes_ast::context::Context;
2944 use hermes_ast::node::Node;
2945 let mut sm = hermes_support::manager::SourceErrorManager::new();
2946 let mut ctx = Context::new();
2947 let gc = ctx.lock();
2948 let expr = parse_expr_ok(&gc, &mut sm, b"({a} = b);");
2949 if let Node::AssignmentExpression(asn) = expr {
2950 let op = gc.ctx().atom_table.bytes(asn.operator.get());
2951 assert_eq!(op, b"=");
2952 assert!(
2953 matches!(asn.left, Node::ObjectPattern(_)),
2954 "left is ObjectPattern, got {:?}",
2955 asn.left.kind()
2956 );
2957 } else {
2958 panic!("expected AssignmentExpression");
2959 }
2960 }
2961
2962 #[test]
2963 fn object_destructure_cover_initializer() {
2964 use hermes_ast::context::Context;
2966 use hermes_ast::node::Node;
2967 let mut sm = hermes_support::manager::SourceErrorManager::new();
2968 let mut ctx = Context::new();
2969 let gc = ctx.lock();
2970 let expr = parse_expr_ok(&gc, &mut sm, b"({a = 1} = b);");
2971 if let Node::AssignmentExpression(asn) = expr {
2972 if let Node::ObjectPattern(op) = asn.left {
2973 let props: Vec<_> = op.properties.iter().collect();
2974 assert_eq!(props.len(), 1);
2975 if let Node::Property(p) = props[0] {
2976 assert!(
2977 matches!(p.value, Node::AssignmentPattern(_)),
2978 "property value is AssignmentPattern"
2979 );
2980 } else {
2981 panic!("expected Property");
2982 }
2983 } else {
2984 panic!("left must be ObjectPattern");
2985 }
2986 } else {
2987 panic!("expected AssignmentExpression");
2988 }
2989 }
2990
2991 #[test]
2992 fn object_destructure_with_rest() {
2993 use hermes_ast::context::Context;
2995 use hermes_ast::node::Node;
2996 let mut sm = hermes_support::manager::SourceErrorManager::new();
2997 let mut ctx = Context::new();
2998 let gc = ctx.lock();
2999 let expr = parse_expr_ok(&gc, &mut sm, b"({...r} = o);");
3000 if let Node::AssignmentExpression(asn) = expr {
3001 if let Node::ObjectPattern(op) = asn.left {
3002 let props: Vec<_> = op.properties.iter().collect();
3003 assert_eq!(props.len(), 1);
3004 assert!(
3005 matches!(props[0], Node::RestElement(_)),
3006 "property is RestElement"
3007 );
3008 } else {
3009 panic!("left must be ObjectPattern");
3010 }
3011 } else {
3012 panic!("expected AssignmentExpression");
3013 }
3014 }
3015
3016 #[test]
3017 fn nested_array_object_destructure() {
3018 use hermes_ast::context::Context;
3020 use hermes_ast::node::Node;
3021 let mut sm = hermes_support::manager::SourceErrorManager::new();
3022 let mut ctx = Context::new();
3023 let gc = ctx.lock();
3024 let expr = parse_expr_ok(&gc, &mut sm, b"[{a}, [b]] = c;");
3025 if let Node::AssignmentExpression(asn) = expr {
3026 if let Node::ArrayPattern(ap) = asn.left {
3027 let elems: Vec<_> = ap.elements.iter().collect();
3028 assert_eq!(elems.len(), 2);
3029 assert!(matches!(elems[0], Node::ObjectPattern(_)));
3030 assert!(matches!(elems[1], Node::ArrayPattern(_)));
3031 } else {
3032 panic!("left must be ArrayPattern");
3033 }
3034 } else {
3035 panic!("expected AssignmentExpression");
3036 }
3037 }
3038
3039 #[test]
3049 fn return_outside_function_reports_error_but_parses() {
3050 use hermes_ast::context::Context;
3051 use hermes_ast::node::Node;
3052 let mut sm = hermes_support::manager::SourceErrorManager::new();
3053 let buf_id = sm.add_buffer_bytes("input", b"return x;\n");
3054 let mut ctx = Context::new();
3055 let gc = ctx.lock();
3056 let atoms = &gc.ctx().atom_table;
3057 let lexer = crate::lexer::JSLexer::new(
3058 buf_id,
3059 &mut sm,
3060 atoms,
3061 crate::lexer::GrammarContext::AllowRegExp,
3062 );
3063 let mut parser = JSParserImpl::new(&gc, lexer);
3064 let program = parser.parse_program().expect("return still parses");
3065 assert!(
3066 parser.error_count_pub() >= 1,
3067 "top-level return reports an error"
3068 );
3069 if let Node::Program(p) = program {
3070 let stmt = p.body.iter().next().expect("has statement");
3071 assert!(
3072 matches!(stmt, Node::ReturnStatement(_)),
3073 "still produces a ReturnStatement"
3074 );
3075 } else {
3076 panic!("expected Program");
3077 }
3078 }
3079
3080 #[test]
3083 fn throw_newline_before_argument_fails() {
3084 use hermes_ast::context::Context;
3085 let mut sm = hermes_support::manager::SourceErrorManager::new();
3086 let buf_id = sm.add_buffer_bytes("input", b"throw\nx;\n");
3087 let mut ctx = Context::new();
3088 let gc = ctx.lock();
3089 let atoms = &gc.ctx().atom_table;
3090 let lexer = crate::lexer::JSLexer::new(
3091 buf_id,
3092 &mut sm,
3093 atoms,
3094 crate::lexer::GrammarContext::AllowRegExp,
3095 );
3096 let mut parser = JSParserImpl::new(&gc, lexer);
3097 assert!(
3098 parser.parse().is_none(),
3099 "throw with newline before argument fails"
3100 );
3101 assert!(parser.error_count_pub() >= 1);
3102 }
3103
3104 #[test]
3107 fn labelled_statement_parses() {
3108 use hermes_ast::context::Context;
3109 use hermes_ast::node::Node;
3110 let mut sm = hermes_support::manager::SourceErrorManager::new();
3111 let buf_id = sm.add_buffer_bytes("input", b"foo: x;\n");
3112 let mut ctx = Context::new();
3113 let gc = ctx.lock();
3114 let atoms = &gc.ctx().atom_table;
3115 let lexer = crate::lexer::JSLexer::new(
3116 buf_id,
3117 &mut sm,
3118 atoms,
3119 crate::lexer::GrammarContext::AllowRegExp,
3120 );
3121 let mut parser = JSParserImpl::new(&gc, lexer);
3122 let program = parser.parse().expect("labelled statement parses");
3123 assert_eq!(parser.error_count_pub(), 0, "zero errors");
3124 if let Node::Program(p) = program {
3125 let stmt = p.body.iter().next().expect("has statement");
3126 if let Node::LabeledStatement(ls) = stmt {
3127 if let Node::Identifier(id) = ls.label {
3128 assert_eq!(gc.ctx().atom_table.bytes(id.name.get()), b"foo");
3129 } else {
3130 panic!("label must be an Identifier");
3131 }
3132 assert!(
3133 matches!(ls.body, Node::ExpressionStatement(_)),
3134 "body is an ExpressionStatement"
3135 );
3136 } else {
3137 panic!("expected LabeledStatement");
3138 }
3139 } else {
3140 panic!("expected Program");
3141 }
3142 }
3143
3144 #[test]
3150 fn binding_array_pattern_basic() {
3151 use hermes_ast::context::Context;
3152 use hermes_ast::node::Node;
3153 use hermes_support::manager::SourceErrorManager;
3154
3155 let mut sm = SourceErrorManager::new();
3156 let buf_id = sm.add_buffer_bytes("input", b"[a, , ...b]");
3157 let mut ctx = Context::new();
3158 let gc = ctx.lock();
3159 let atoms = &gc.ctx().atom_table;
3160 let lexer = crate::lexer::JSLexer::new(
3161 buf_id,
3162 &mut sm,
3163 atoms,
3164 crate::lexer::GrammarContext::AllowRegExp,
3165 );
3166 let mut parser = JSParserImpl::new(&gc, lexer);
3167 let pat = parser
3168 .parse_binding_pattern_for_test()
3169 .expect("array binding pattern parses");
3170 assert_eq!(parser.error_count_pub(), 0, "no errors");
3171
3172 let ap = match pat {
3173 Node::ArrayPattern(ap) => ap,
3174 other => panic!("expected ArrayPattern, got {:?}", other.kind()),
3175 };
3176 let elems: Vec<&Node> = ap.elements.iter().collect();
3177 assert_eq!(elems.len(), 3, "three elements");
3178 assert!(
3179 matches!(elems[0], Node::Identifier(_)),
3180 "elem0 = Identifier(a)"
3181 );
3182 assert!(matches!(elems[1], Node::Empty(_)), "elem1 = Empty hole");
3183 match elems[2] {
3184 Node::RestElement(r) => {
3185 assert!(
3186 matches!(r.argument, Node::Identifier(_)),
3187 "rest arg = Identifier(b)"
3188 );
3189 }
3190 other => panic!("elem2 should be RestElement, got {:?}", other.kind()),
3191 }
3192 }
3193
3194 #[test]
3195 fn binding_array_pattern_default_initializer() {
3196 use hermes_ast::context::Context;
3197 use hermes_ast::node::Node;
3198 use hermes_support::manager::SourceErrorManager;
3199
3200 let mut sm = SourceErrorManager::new();
3201 let buf_id = sm.add_buffer_bytes("input", b"[a = 1]");
3202 let mut ctx = Context::new();
3203 let gc = ctx.lock();
3204 let atoms = &gc.ctx().atom_table;
3205 let lexer = crate::lexer::JSLexer::new(
3206 buf_id,
3207 &mut sm,
3208 atoms,
3209 crate::lexer::GrammarContext::AllowRegExp,
3210 );
3211 let mut parser = JSParserImpl::new(&gc, lexer);
3212 let pat = parser
3213 .parse_binding_pattern_for_test()
3214 .expect("array binding pattern with default parses");
3215 assert_eq!(parser.error_count_pub(), 0, "no errors");
3216
3217 let ap = match pat {
3218 Node::ArrayPattern(ap) => ap,
3219 other => panic!("expected ArrayPattern, got {:?}", other.kind()),
3220 };
3221 let elems: Vec<&Node> = ap.elements.iter().collect();
3222 assert_eq!(elems.len(), 1, "one element");
3223 match elems[0] {
3224 Node::AssignmentPattern(asn) => {
3225 assert!(
3226 matches!(asn.left, Node::Identifier(_)),
3227 "left = Identifier(a)"
3228 );
3229 assert!(
3230 matches!(asn.right, Node::NumericLiteral(_)),
3231 "right = NumericLiteral(1)"
3232 );
3233 }
3234 other => {
3235 panic!("elem0 should be AssignmentPattern, got {:?}", other.kind())
3236 }
3237 }
3238 }
3239
3240 #[test]
3241 fn binding_object_pattern_basic() {
3242 use hermes_ast::context::Context;
3243 use hermes_ast::node::Node;
3244 use hermes_support::manager::SourceErrorManager;
3245
3246 let mut sm = SourceErrorManager::new();
3247 let buf_id = sm.add_buffer_bytes("input", b"{a, b: c, d = 1, ...r}");
3248 let mut ctx = Context::new();
3249 let gc = ctx.lock();
3250 let atoms = &gc.ctx().atom_table;
3251 let lexer = crate::lexer::JSLexer::new(
3252 buf_id,
3253 &mut sm,
3254 atoms,
3255 crate::lexer::GrammarContext::AllowRegExp,
3256 );
3257 let mut parser = JSParserImpl::new(&gc, lexer);
3258 let pat = parser
3259 .parse_binding_pattern_for_test()
3260 .expect("object binding pattern parses");
3261 assert_eq!(parser.error_count_pub(), 0, "no errors");
3262
3263 let op = match pat {
3264 Node::ObjectPattern(op) => op,
3265 other => panic!("expected ObjectPattern, got {:?}", other.kind()),
3266 };
3267 let props: Vec<&Node> = op.properties.iter().collect();
3268 assert_eq!(props.len(), 4, "four properties");
3269
3270 match props[0] {
3272 Node::Property(p) => {
3273 assert!(p.shorthand.get(), "a is shorthand");
3274 assert!(!p.computed.get(), "a not computed");
3275 assert!(matches!(p.key, Node::Identifier(_)), "key = a");
3276 assert!(matches!(p.value, Node::Identifier(_)), "value = a");
3277 }
3278 other => panic!("prop0 should be Property, got {:?}", other.kind()),
3279 }
3280
3281 match props[1] {
3283 Node::Property(p) => {
3284 assert!(!p.shorthand.get(), "b:c not shorthand");
3285 assert!(matches!(p.key, Node::Identifier(_)), "key = b");
3286 assert!(matches!(p.value, Node::Identifier(_)), "value = c");
3287 }
3288 other => panic!("prop1 should be Property, got {:?}", other.kind()),
3289 }
3290
3291 match props[2] {
3293 Node::Property(p) => {
3294 assert!(p.shorthand.get(), "d = 1 is shorthand");
3295 match p.value {
3296 Node::AssignmentPattern(asn) => {
3297 assert!(
3298 matches!(asn.left, Node::Identifier(_)),
3299 "left = d"
3300 );
3301 assert!(
3302 matches!(asn.right, Node::NumericLiteral(_)),
3303 "right = 1"
3304 );
3305 }
3306 other => panic!(
3307 "prop2 value should be AssignmentPattern, got {:?}",
3308 other.kind()
3309 ),
3310 }
3311 }
3312 other => panic!("prop2 should be Property, got {:?}", other.kind()),
3313 }
3314
3315 match props[3] {
3317 Node::RestElement(r) => {
3318 assert!(
3319 matches!(r.argument, Node::Identifier(_)),
3320 "rest arg = r"
3321 );
3322 }
3323 other => panic!("prop3 should be RestElement, got {:?}", other.kind()),
3324 }
3325 }
3326
3327 fn parse_with_collector<'gc>(
3335 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
3336 sm: &mut hermes_support::manager::SourceErrorManager,
3337 atoms: &hermes_atom_table::AtomTable,
3338 src: &[u8],
3339 ) -> Option<&'gc hermes_ast::node::Node<'gc>> {
3340 sm.set_handler(Box::new(hermes_support::diag::CollectingHandler::new()));
3341 let buf_id = sm.add_buffer_bytes("input", src);
3342 let lexer = crate::lexer::JSLexer::new(
3343 buf_id,
3344 sm,
3345 atoms,
3346 crate::lexer::GrammarContext::AllowRegExp,
3347 );
3348 let mut parser = JSParserImpl::new(gc, lexer);
3349 parser.parse()
3350 }
3351
3352 #[test]
3355 fn var_array_pattern_declaration() {
3356 use hermes_ast::context::Context;
3357 use hermes_ast::node::Node;
3358 use hermes_support::manager::SourceErrorManager;
3359
3360 let mut sm = SourceErrorManager::new();
3361 let buf_id = sm.add_buffer_bytes("input", b"var [a] = b;");
3362 let mut ctx = Context::new();
3363 let gc = ctx.lock();
3364 let atoms = &gc.ctx().atom_table;
3365 let lexer = crate::lexer::JSLexer::new(
3366 buf_id,
3367 &mut sm,
3368 atoms,
3369 crate::lexer::GrammarContext::AllowRegExp,
3370 );
3371 let mut parser = JSParserImpl::new(&gc, lexer);
3372 let program = parser.parse().expect("var [a] = b; parses");
3373 assert_eq!(parser.error_count_pub(), 0);
3374
3375 let Node::Program(p) = program else {
3376 panic!("expected Program")
3377 };
3378 let stmt = p.body.iter().next().expect("one statement");
3379 let Node::VariableDeclaration(vd) = stmt else {
3380 panic!("expected VariableDeclaration, got {:?}", stmt.kind())
3381 };
3382 assert_eq!(
3383 gc.ctx().atom_table.bytes(vd.kind.get()),
3384 b"var",
3385 "kind should be 'var'"
3386 );
3387 let decl = vd.declarations.iter().next().expect("one declarator");
3388 let Node::VariableDeclarator(d) = decl else {
3389 panic!("expected VariableDeclarator")
3390 };
3391 assert!(
3392 matches!(d.id, Node::ArrayPattern(_)),
3393 "declarator id should be ArrayPattern, got {:?}",
3394 d.id.kind()
3395 );
3396 assert!(d.init.is_some(), "declarator should have an initializer");
3397 }
3398
3399 #[test]
3401 fn const_without_initializer_errors() {
3402 use hermes_ast::context::Context;
3403 use hermes_support::diag::{CollectingHandler, DiagKind};
3404 use hermes_support::manager::SourceErrorManager;
3405
3406 let mut sm = SourceErrorManager::new();
3407 let mut ctx = Context::new();
3408 let gc = ctx.lock();
3409 let atoms = &gc.ctx().atom_table;
3410 let _program = parse_with_collector(&gc, &mut sm, atoms, b"const x;");
3411
3412 let h = sm.handler_as::<CollectingHandler>().unwrap();
3413 let errs: Vec<_> = h
3414 .messages()
3415 .iter()
3416 .filter(|m| m.kind == DiagKind::Error)
3417 .collect();
3418 assert!(
3419 errs.iter()
3420 .any(|m| m.message == "missing initializer in const declaration"),
3421 "expected 'missing initializer in const declaration', got {:?}",
3422 errs.iter().map(|m| &m.message).collect::<Vec<_>>()
3423 );
3424 }
3425
3426 #[test]
3429 fn destructuring_without_initializer_errors() {
3430 use hermes_ast::context::Context;
3431 use hermes_support::diag::{CollectingHandler, DiagKind};
3432 use hermes_support::manager::SourceErrorManager;
3433
3434 let mut sm = SourceErrorManager::new();
3435 let mut ctx = Context::new();
3436 let gc = ctx.lock();
3437 let atoms = &gc.ctx().atom_table;
3438 let _program = parse_with_collector(&gc, &mut sm, atoms, b"var [a];");
3439
3440 let h = sm.handler_as::<CollectingHandler>().unwrap();
3441 let errs: Vec<_> = h
3442 .messages()
3443 .iter()
3444 .filter(|m| m.kind == DiagKind::Error)
3445 .collect();
3446 assert!(
3447 errs.iter()
3448 .any(|m| m.message == "destucturing declaration must be initialized"),
3449 "expected 'destucturing declaration must be initialized', got {:?}",
3450 errs.iter().map(|m| &m.message).collect::<Vec<_>>()
3451 );
3452 }
3453
3454 #[test]
3456 fn let_declaration_kind() {
3457 use hermes_ast::context::Context;
3458 use hermes_ast::node::Node;
3459 use hermes_support::manager::SourceErrorManager;
3460
3461 let mut sm = SourceErrorManager::new();
3462 let buf_id = sm.add_buffer_bytes("input", b"let x = 1;");
3463 let mut ctx = Context::new();
3464 let gc = ctx.lock();
3465 let atoms = &gc.ctx().atom_table;
3466 let lexer = crate::lexer::JSLexer::new(
3467 buf_id,
3468 &mut sm,
3469 atoms,
3470 crate::lexer::GrammarContext::AllowRegExp,
3471 );
3472 let mut parser = JSParserImpl::new(&gc, lexer);
3473 let program = parser.parse().expect("let x = 1; parses");
3474 assert_eq!(parser.error_count_pub(), 0);
3475
3476 let Node::Program(p) = program else {
3477 panic!("expected Program")
3478 };
3479 let stmt = p.body.iter().next().expect("one statement");
3480 let Node::VariableDeclaration(vd) = stmt else {
3481 panic!("expected VariableDeclaration, got {:?}", stmt.kind())
3482 };
3483 assert_eq!(
3484 gc.ctx().atom_table.bytes(vd.kind.get()),
3485 b"let",
3486 "kind should be 'let'"
3487 );
3488 }
3489
3490 #[test]
3495 fn loose_let_is_expression_statement() {
3496 use hermes_ast::context::Context;
3497 use hermes_ast::node::Node;
3498 use hermes_support::manager::SourceErrorManager;
3499
3500 let mut sm = SourceErrorManager::new();
3501 let buf_id = sm.add_buffer_bytes("input", b"let;\nlet x;");
3502 let mut ctx = Context::new();
3503 let gc = ctx.lock();
3504 let atoms = &gc.ctx().atom_table;
3505 let lexer = crate::lexer::JSLexer::new(
3506 buf_id,
3507 &mut sm,
3508 atoms,
3509 crate::lexer::GrammarContext::AllowRegExp,
3510 );
3511 let mut parser = JSParserImpl::new(&gc, lexer);
3512 let program = parser.parse().expect("let;\\nlet x; parses");
3513 assert_eq!(parser.error_count_pub(), 0);
3514
3515 let Node::Program(p) = program else {
3516 panic!("expected Program")
3517 };
3518 let mut it = p.body.iter();
3519 let first = it.next().expect("first statement");
3521 assert!(
3522 matches!(first, Node::ExpressionStatement(_)),
3523 "`let;` should be an ExpressionStatement, got {:?}",
3524 first.kind()
3525 );
3526 let second = it.next().expect("second statement");
3528 assert!(
3529 matches!(second, Node::VariableDeclaration(_)),
3530 "`let x;` should be a VariableDeclaration, got {:?}",
3531 second.kind()
3532 );
3533 }
3534
3535 fn parse_first_stmt<'gc>(
3542 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
3543 sm: &mut hermes_support::manager::SourceErrorManager,
3544 src: &[u8],
3545 ) -> &'gc hermes_ast::node::Node<'gc> {
3546 let buf_id = sm.add_buffer_bytes("input", src);
3547 let atoms = &gc.ctx().atom_table;
3548 let lexer = crate::lexer::JSLexer::new(
3549 buf_id,
3550 sm,
3551 atoms,
3552 crate::lexer::GrammarContext::AllowRegExp,
3553 );
3554 let mut parser = JSParserImpl::new(gc, lexer);
3555 let program = parser.parse().expect("parse succeeded");
3556 assert_eq!(parser.error_count_pub(), 0, "zero errors");
3557 if let hermes_ast::node::Node::Program(p) = program {
3558 return p.body.iter().next().expect("has statement");
3559 }
3560 panic!("expected Program");
3561 }
3562
3563 #[test]
3565 fn nested_block_statement() {
3566 use hermes_ast::context::Context;
3567 use hermes_ast::node::Node;
3568 let mut sm = hermes_support::manager::SourceErrorManager::new();
3569 let mut ctx = Context::new();
3570 let gc = ctx.lock();
3571 let stmt = parse_first_stmt(&gc, &mut sm, b"{{x;}}");
3572 let Node::BlockStatement(outer) = stmt else {
3573 panic!("expected BlockStatement, got {:?}", stmt.kind())
3574 };
3575 let inner = outer.body.iter().next().expect("one inner statement");
3576 assert!(
3577 matches!(inner, Node::BlockStatement(_)),
3578 "inner statement should be BlockStatement, got {:?}",
3579 inner.kind()
3580 );
3581 }
3582
3583 #[test]
3585 fn if_with_else() {
3586 use hermes_ast::context::Context;
3587 use hermes_ast::node::Node;
3588 let mut sm = hermes_support::manager::SourceErrorManager::new();
3589 let mut ctx = Context::new();
3590 let gc = ctx.lock();
3591 let stmt = parse_first_stmt(&gc, &mut sm, b"if(a)b;else c;");
3592 let Node::IfStatement(iff) = stmt else {
3593 panic!("expected IfStatement, got {:?}", stmt.kind())
3594 };
3595 assert!(iff.alternate.is_some(), "alternate should be present");
3596 }
3597
3598 #[test]
3600 fn dangling_else_binds_to_inner_if() {
3601 use hermes_ast::context::Context;
3602 use hermes_ast::node::Node;
3603 let mut sm = hermes_support::manager::SourceErrorManager::new();
3604 let mut ctx = Context::new();
3605 let gc = ctx.lock();
3606 let stmt = parse_first_stmt(&gc, &mut sm, b"if(a)if(b)c;else d;");
3607 let Node::IfStatement(outer) = stmt else {
3608 panic!("expected IfStatement, got {:?}", stmt.kind())
3609 };
3610 assert!(
3612 outer.alternate.is_none(),
3613 "outer if should have no alternate"
3614 );
3615 let Node::IfStatement(inner) = outer.consequent else {
3616 panic!(
3617 "outer consequent should be IfStatement, got {:?}",
3618 outer.consequent.kind()
3619 )
3620 };
3621 assert!(
3622 inner.alternate.is_some(),
3623 "else should bind to the inner if"
3624 );
3625 }
3626
3627 #[test]
3631 fn while_body_and_test_not_swapped() {
3632 use hermes_ast::context::Context;
3633 use hermes_ast::node::Node;
3634 let mut sm = hermes_support::manager::SourceErrorManager::new();
3635 let mut ctx = Context::new();
3636 let gc = ctx.lock();
3637 let stmt = parse_first_stmt(&gc, &mut sm, b"while(x)y;");
3638 let Node::WhileStatement(w) = stmt else {
3639 panic!("expected WhileStatement, got {:?}", stmt.kind())
3640 };
3641 let Node::Identifier(id) = w.test else {
3643 panic!("test should be Identifier(x), got {:?}", w.test.kind())
3644 };
3645 assert_eq!(gc.ctx().atom_table.bytes(id.name.get()), b"x");
3646 assert!(
3648 matches!(w.body, Node::ExpressionStatement(_)),
3649 "body should be ExpressionStatement, got {:?}",
3650 w.body.kind()
3651 );
3652 }
3653
3654 #[test]
3657 fn switch_duplicate_default_errors() {
3658 use hermes_ast::context::Context;
3659 use hermes_support::diag::{CollectingHandler, DiagKind};
3660 let mut sm = hermes_support::manager::SourceErrorManager::new();
3661 let mut ctx = Context::new();
3662 let gc = ctx.lock();
3663 let atoms = &gc.ctx().atom_table;
3664 let _program = parse_with_collector(
3665 &gc,
3666 &mut sm,
3667 atoms,
3668 b"switch(x){default:;default:;}",
3669 );
3670 let h = sm.handler_as::<CollectingHandler>().unwrap();
3671 let errs: Vec<_> = h
3672 .messages()
3673 .iter()
3674 .filter(|m| m.kind == DiagKind::Error)
3675 .collect();
3676 assert!(
3677 errs.iter().any(|m| m.message
3678 == "more than one 'default' clause in 'switch'"),
3679 "expected duplicate-default error, got {:?}",
3680 errs.iter().map(|m| &m.message).collect::<Vec<_>>()
3681 );
3682 }
3683
3684 #[test]
3686 fn try_without_handler_errors() {
3687 use hermes_ast::context::Context;
3688 use hermes_support::diag::{CollectingHandler, DiagKind};
3689 let mut sm = hermes_support::manager::SourceErrorManager::new();
3690 let mut ctx = Context::new();
3691 let gc = ctx.lock();
3692 let atoms = &gc.ctx().atom_table;
3693 let _program = parse_with_collector(&gc, &mut sm, atoms, b"try{}");
3694 let h = sm.handler_as::<CollectingHandler>().unwrap();
3695 let errs: Vec<_> = h
3696 .messages()
3697 .iter()
3698 .filter(|m| m.kind == DiagKind::Error)
3699 .collect();
3700 assert!(
3701 errs.iter().any(|m| m
3702 .message
3703 .contains("'catch' or 'finally' expected")),
3704 "expected catch/finally error, got {:?}",
3705 errs.iter().map(|m| &m.message).collect::<Vec<_>>()
3706 );
3707 }
3708
3709 #[test]
3712 fn for_in_basic() {
3713 use hermes_ast::context::Context;
3714 use hermes_ast::node::Node;
3715 let mut sm = hermes_support::manager::SourceErrorManager::new();
3716 let mut ctx = Context::new();
3717 let gc = ctx.lock();
3718 let stmt = parse_first_stmt(&gc, &mut sm, b"for(a in b)c;");
3719 let Node::ForInStatement(f) = stmt else {
3720 panic!("expected ForInStatement, got {:?}", stmt.kind())
3721 };
3722 let Node::Identifier(left) = f.left else {
3723 panic!("left should be Identifier(a), got {:?}", f.left.kind())
3724 };
3725 assert_eq!(gc.ctx().atom_table.bytes(left.name.get()), b"a");
3726 let Node::Identifier(right) = f.right else {
3727 panic!("right should be Identifier(b), got {:?}", f.right.kind())
3728 };
3729 assert_eq!(gc.ctx().atom_table.bytes(right.name.get()), b"b");
3730 }
3731
3732 #[test]
3735 fn for_of_array_pattern_left() {
3736 use hermes_ast::context::Context;
3737 use hermes_ast::node::Node;
3738 let mut sm = hermes_support::manager::SourceErrorManager::new();
3739 let mut ctx = Context::new();
3740 let gc = ctx.lock();
3741 let stmt = parse_first_stmt(&gc, &mut sm, b"for([a] of b)c;");
3742 let Node::ForOfStatement(f) = stmt else {
3743 panic!("expected ForOfStatement, got {:?}", stmt.kind())
3744 };
3745 assert!(
3746 matches!(f.left, Node::ArrayPattern(_)),
3747 "left should be ArrayPattern, got {:?}",
3748 f.left.kind()
3749 );
3750 assert!(!f.r#await.get(), "await should be false");
3751 }
3752
3753 #[test]
3756 fn for_in_multiple_bindings_errors() {
3757 use hermes_ast::context::Context;
3758 use hermes_support::diag::{CollectingHandler, DiagKind};
3759 let mut sm = hermes_support::manager::SourceErrorManager::new();
3760 let mut ctx = Context::new();
3761 let gc = ctx.lock();
3762 let atoms = &gc.ctx().atom_table;
3763 let _program =
3764 parse_with_collector(&gc, &mut sm, atoms, b"for(var a, b in c);");
3765 let h = sm.handler_as::<CollectingHandler>().unwrap();
3766 let errs: Vec<_> = h
3767 .messages()
3768 .iter()
3769 .filter(|m| m.kind == DiagKind::Error)
3770 .collect();
3771 assert!(
3772 errs.iter().any(|m| m.message
3773 == "Only one binding must be declared in a for-in/for-of loop"),
3774 "expected single-binding error, got {:?}",
3775 errs.iter().map(|m| &m.message).collect::<Vec<_>>()
3776 );
3777 }
3778
3779 #[test]
3781 fn for_empty_head() {
3782 use hermes_ast::context::Context;
3783 use hermes_ast::node::Node;
3784 let mut sm = hermes_support::manager::SourceErrorManager::new();
3785 let mut ctx = Context::new();
3786 let gc = ctx.lock();
3787 let stmt = parse_first_stmt(&gc, &mut sm, b"for(;;);");
3788 let Node::ForStatement(f) = stmt else {
3789 panic!("expected ForStatement, got {:?}", stmt.kind())
3790 };
3791 assert!(f.init.is_none(), "init should be None");
3792 assert!(f.test.is_none(), "test should be None");
3793 assert!(f.update.is_none(), "update should be None");
3794 assert!(
3795 matches!(f.body, Node::EmptyStatement(_)),
3796 "body should be EmptyStatement, got {:?}",
3797 f.body.kind()
3798 );
3799 }
3800
3801 #[test]
3804 fn for_c_style_var_init() {
3805 use hermes_ast::context::Context;
3806 use hermes_ast::node::Node;
3807 let mut sm = hermes_support::manager::SourceErrorManager::new();
3808 let mut ctx = Context::new();
3809 let gc = ctx.lock();
3810 let stmt = parse_first_stmt(&gc, &mut sm, b"for(var i=0;i<2;i++);");
3811 let Node::ForStatement(f) = stmt else {
3812 panic!("expected ForStatement, got {:?}", stmt.kind())
3813 };
3814 let init = f.init.expect("init should be Some");
3815 assert!(
3816 matches!(init, Node::VariableDeclaration(_)),
3817 "init should be VariableDeclaration, got {:?}",
3818 init.kind()
3819 );
3820 assert!(f.test.is_some(), "test should be Some");
3821 assert!(f.update.is_some(), "update should be Some");
3822 }
3823
3824 fn first_yield<'gc>(
3831 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
3832 sm: &mut hermes_support::manager::SourceErrorManager,
3833 src: &[u8],
3834 ) -> &'gc hermes_ast::node::YieldExpression<'gc> {
3835 use hermes_ast::node::Node;
3836 let decl = parse_first_stmt(gc, sm, src);
3837 let Node::FunctionDeclaration(f) = decl else {
3838 panic!("expected FunctionDeclaration, got {:?}", decl.kind())
3839 };
3840 let Node::BlockStatement(block) = f.body else {
3841 panic!("expected BlockStatement body, got {:?}", f.body.kind())
3842 };
3843 let first = block.body.iter().next().expect("body has a statement");
3844 let Node::ExpressionStatement(es) = first else {
3845 panic!("expected ExpressionStatement, got {:?}", first.kind())
3846 };
3847 let Node::YieldExpression(y) = es.expression else {
3848 panic!(
3849 "expected YieldExpression, got {:?}",
3850 es.expression.kind()
3851 )
3852 };
3853 y
3854 }
3855
3856 #[test]
3858 fn yield_delegate() {
3859 use hermes_ast::context::Context;
3860 let mut sm = hermes_support::manager::SourceErrorManager::new();
3861 let mut ctx = Context::new();
3862 let gc = ctx.lock();
3863 let y = first_yield(&gc, &mut sm, b"function* g(){ yield* a; }");
3864 assert!(y.delegate.get(), "yield* should set delegate=true");
3865 assert!(y.argument.is_some(), "yield* a has an argument");
3866 }
3867
3868 #[test]
3870 fn yield_no_argument() {
3871 use hermes_ast::context::Context;
3872 let mut sm = hermes_support::manager::SourceErrorManager::new();
3873 let mut ctx = Context::new();
3874 let gc = ctx.lock();
3875 let y = first_yield(&gc, &mut sm, b"function* g(){ yield; }");
3876 assert!(y.argument.is_none(), "bare yield has no argument");
3877 assert!(!y.delegate.get(), "bare yield is not delegating");
3878 }
3879
3880 #[test]
3882 fn yield_with_argument() {
3883 use hermes_ast::context::Context;
3884 let mut sm = hermes_support::manager::SourceErrorManager::new();
3885 let mut ctx = Context::new();
3886 let gc = ctx.lock();
3887 let y = first_yield(&gc, &mut sm, b"function* g(){ yield 1; }");
3888 assert!(y.argument.is_some(), "yield 1 has an argument");
3889 assert!(!y.delegate.get(), "yield 1 is not delegating");
3890 }
3891
3892 fn first_arrow<'gc>(
3899 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
3900 sm: &mut hermes_support::manager::SourceErrorManager,
3901 src: &[u8],
3902 ) -> &'gc hermes_ast::node::ArrowFunctionExpression<'gc> {
3903 use hermes_ast::node::Node;
3904 let stmt = parse_first_stmt(gc, sm, src);
3905 let Node::ExpressionStatement(es) = stmt else {
3906 panic!("expected ExpressionStatement, got {:?}", stmt.kind())
3907 };
3908 let Node::ArrowFunctionExpression(a) = es.expression else {
3909 panic!(
3910 "expected ArrowFunctionExpression, got {:?}",
3911 es.expression.kind()
3912 )
3913 };
3914 a
3915 }
3916
3917 #[test]
3919 fn arrow_single_ident() {
3920 use hermes_ast::context::Context;
3921 use hermes_ast::node::Node;
3922 let mut sm = hermes_support::manager::SourceErrorManager::new();
3923 let mut ctx = Context::new();
3924 let gc = ctx.lock();
3925 let a = first_arrow(&gc, &mut sm, b"a => a;");
3926 assert!(a.expression.get(), "concise body is an expression");
3927 assert!(!a.r#async.get(), "not async");
3928 let params: Vec<_> = a.params.iter().collect();
3929 assert_eq!(params.len(), 1, "one param");
3930 assert!(
3931 matches!(params[0], Node::Identifier(_)),
3932 "param is Identifier, got {:?}",
3933 params[0].kind()
3934 );
3935 }
3936
3937 #[test]
3939 fn arrow_empty_params() {
3940 use hermes_ast::context::Context;
3941 let mut sm = hermes_support::manager::SourceErrorManager::new();
3942 let mut ctx = Context::new();
3943 let gc = ctx.lock();
3944 let a = first_arrow(&gc, &mut sm, b"() => 0;");
3945 assert_eq!(a.params.iter().count(), 0, "no params");
3946 assert!(a.expression.get(), "concise body");
3947 }
3948
3949 #[test]
3951 fn arrow_rest_param() {
3952 use hermes_ast::context::Context;
3953 use hermes_ast::node::Node;
3954 let mut sm = hermes_support::manager::SourceErrorManager::new();
3955 let mut ctx = Context::new();
3956 let gc = ctx.lock();
3957 let a = first_arrow(&gc, &mut sm, b"(a, ...b) => b;");
3958 let params: Vec<_> = a.params.iter().collect();
3959 assert_eq!(params.len(), 2, "two params");
3960 assert!(
3961 matches!(params[0], Node::Identifier(_)),
3962 "first param Identifier, got {:?}",
3963 params[0].kind()
3964 );
3965 assert!(
3966 matches!(params[1], Node::RestElement(_)),
3967 "second param RestElement, got {:?}",
3968 params[1].kind()
3969 );
3970 }
3971
3972 #[test]
3974 fn arrow_default_param() {
3975 use hermes_ast::context::Context;
3976 use hermes_ast::node::Node;
3977 let mut sm = hermes_support::manager::SourceErrorManager::new();
3978 let mut ctx = Context::new();
3979 let gc = ctx.lock();
3980 let a = first_arrow(&gc, &mut sm, b"(a = 1) => a;");
3981 let params: Vec<_> = a.params.iter().collect();
3982 assert_eq!(params.len(), 1, "one param");
3983 assert!(
3984 matches!(params[0], Node::AssignmentPattern(_)),
3985 "param AssignmentPattern, got {:?}",
3986 params[0].kind()
3987 );
3988 }
3989
3990 #[test]
3992 fn arrow_object_pattern_param() {
3993 use hermes_ast::context::Context;
3994 use hermes_ast::node::Node;
3995 let mut sm = hermes_support::manager::SourceErrorManager::new();
3996 let mut ctx = Context::new();
3997 let gc = ctx.lock();
3998 let a = first_arrow(&gc, &mut sm, b"({x}) => x;");
3999 let params: Vec<_> = a.params.iter().collect();
4000 assert_eq!(params.len(), 1, "one param");
4001 assert!(
4002 matches!(params[0], Node::ObjectPattern(_)),
4003 "param ObjectPattern, got {:?}",
4004 params[0].kind()
4005 );
4006 }
4007
4008 #[test]
4010 fn arrow_block_body() {
4011 use hermes_ast::context::Context;
4012 use hermes_ast::node::Node;
4013 let mut sm = hermes_support::manager::SourceErrorManager::new();
4014 let mut ctx = Context::new();
4015 let gc = ctx.lock();
4016 let a = first_arrow(&gc, &mut sm, b"a => { return a; };");
4017 assert!(!a.expression.get(), "block body is not an expression");
4018 assert!(
4019 matches!(a.body, Node::BlockStatement(_)),
4020 "block body, got {:?}",
4021 a.body.kind()
4022 );
4023 }
4024
4025 #[test]
4027 fn arrow_async_single_ident() {
4028 use hermes_ast::context::Context;
4029 let mut sm = hermes_support::manager::SourceErrorManager::new();
4030 let mut ctx = Context::new();
4031 let gc = ctx.lock();
4032 let a = first_arrow(&gc, &mut sm, b"async a => a;");
4033 assert!(a.r#async.get(), "async arrow");
4034 assert_eq!(a.params.iter().count(), 1, "one param");
4035 }
4036
4037 #[test]
4040 fn arrow_async_paren() {
4041 use hermes_ast::context::Context;
4042 use hermes_ast::node::Node;
4043 let mut sm = hermes_support::manager::SourceErrorManager::new();
4044 let mut ctx = Context::new();
4045 let gc = ctx.lock();
4046 let a = first_arrow(&gc, &mut sm, b"async (a) => a;");
4047 assert!(a.r#async.get(), "async arrow");
4048 let params: Vec<_> = a.params.iter().collect();
4049 assert_eq!(params.len(), 1, "one param");
4050 assert!(
4051 matches!(params[0], Node::Identifier(_)),
4052 "param Identifier, got {:?}",
4053 params[0].kind()
4054 );
4055 }
4056
4057 #[test]
4059 fn paren_ident_not_arrow() {
4060 use hermes_ast::context::Context;
4061 use hermes_ast::node::Node;
4062 let mut sm = hermes_support::manager::SourceErrorManager::new();
4063 let mut ctx = Context::new();
4064 let gc = ctx.lock();
4065 let stmt = parse_first_stmt(&gc, &mut sm, b"(a);");
4066 let Node::ExpressionStatement(es) = stmt else {
4067 panic!("expected ExpressionStatement, got {:?}", stmt.kind())
4068 };
4069 assert!(
4070 matches!(es.expression, Node::Identifier(_)),
4071 "expression is Identifier, got {:?}",
4072 es.expression.kind()
4073 );
4074 assert_eq!(
4075 es.expression.metadata().parens.get(),
4076 1,
4077 "one paren recorded"
4078 );
4079 }
4080
4081 #[test]
4083 fn paren_sequence_not_arrow() {
4084 use hermes_ast::context::Context;
4085 use hermes_ast::node::Node;
4086 let mut sm = hermes_support::manager::SourceErrorManager::new();
4087 let mut ctx = Context::new();
4088 let gc = ctx.lock();
4089 let stmt = parse_first_stmt(&gc, &mut sm, b"(a, b);");
4090 let Node::ExpressionStatement(es) = stmt else {
4091 panic!("expected ExpressionStatement, got {:?}", stmt.kind())
4092 };
4093 assert!(
4094 matches!(es.expression, Node::SequenceExpression(_)),
4095 "expression is SequenceExpression, got {:?}",
4096 es.expression.kind()
4097 );
4098 }
4099
4100 #[test]
4104 fn paren_trailing_comma_not_arrow() {
4105 use hermes_ast::context::Context;
4106 use hermes_ast::node::Node;
4107 let mut sm = hermes_support::manager::SourceErrorManager::new();
4108 let mut ctx = Context::new();
4109 let gc = ctx.lock();
4110 let stmt = parse_first_stmt(&gc, &mut sm, b"(a,);");
4111 let Node::ExpressionStatement(es) = stmt else {
4112 panic!("expected ExpressionStatement, got {:?}", stmt.kind())
4113 };
4114 let Node::SequenceExpression(seq) = es.expression else {
4115 panic!(
4116 "expected SequenceExpression, got {:?}",
4117 es.expression.kind()
4118 )
4119 };
4120 let elems: Vec<_> = seq.expressions.iter().collect();
4121 assert_eq!(elems.len(), 2, "[a, CoverTrailingComma]");
4122 assert!(
4123 matches!(elems[1], Node::CoverTrailingComma(_)),
4124 "last element CoverTrailingComma, got {:?}",
4125 elems[1].kind()
4126 );
4127 }
4128
4129 #[cfg(test)]
4132 fn return_arg_in_object_method<'gc>(
4133 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
4134 sm: &mut hermes_support::manager::SourceErrorManager,
4135 src: &[u8],
4136 ) -> &'gc hermes_ast::node::Node<'gc> {
4137 use hermes_ast::node::Node;
4138 let stmt = parse_first_stmt(gc, sm, src);
4139 let Node::ExpressionStatement(es) = stmt else {
4140 panic!("expected ExpressionStatement, got {:?}", stmt.kind())
4141 };
4142 let Node::ObjectExpression(obj) = es.expression else {
4143 panic!("expected ObjectExpression, got {:?}", es.expression.kind())
4144 };
4145 let prop = obj.properties.iter().next().expect("has property");
4146 let Node::Property(prop) = prop else {
4147 panic!("expected Property, got {:?}", prop.kind())
4148 };
4149 let Node::FunctionExpression(func) = prop.value else {
4150 panic!("expected FunctionExpression, got {:?}", prop.value.kind())
4151 };
4152 let Node::BlockStatement(block) = func.body else {
4153 panic!("expected BlockStatement, got {:?}", func.body.kind())
4154 };
4155 let ret = block.body.iter().next().expect("has return statement");
4156 let Node::ReturnStatement(ret) = ret else {
4157 panic!("expected ReturnStatement, got {:?}", ret.kind())
4158 };
4159 ret.argument.expect("return has argument")
4160 }
4161
4162 #[test]
4165 fn super_member_dot() {
4166 use hermes_ast::context::Context;
4167 use hermes_ast::node::Node;
4168 let mut sm = hermes_support::manager::SourceErrorManager::new();
4169 let mut ctx = Context::new();
4170 let gc = ctx.lock();
4171 let arg = return_arg_in_object_method(
4172 &gc,
4173 &mut sm,
4174 b"({ m() { return super.x; } });",
4175 );
4176 let Node::MemberExpression(member) = arg else {
4177 panic!("expected MemberExpression, got {:?}", arg.kind())
4178 };
4179 assert!(
4180 matches!(member.object, Node::Super(_)),
4181 "object is Super, got {:?}",
4182 member.object.kind()
4183 );
4184 assert!(!member.computed.get(), "super.x is not computed");
4185 }
4186
4187 #[test]
4190 fn super_member_computed() {
4191 use hermes_ast::context::Context;
4192 use hermes_ast::node::Node;
4193 let mut sm = hermes_support::manager::SourceErrorManager::new();
4194 let mut ctx = Context::new();
4195 let gc = ctx.lock();
4196 let arg = return_arg_in_object_method(
4197 &gc,
4198 &mut sm,
4199 b"({ m() { return super['y']; } });",
4200 );
4201 let Node::MemberExpression(member) = arg else {
4202 panic!("expected MemberExpression, got {:?}", arg.kind())
4203 };
4204 assert!(
4205 matches!(member.object, Node::Super(_)),
4206 "object is Super, got {:?}",
4207 member.object.kind()
4208 );
4209 assert!(member.computed.get(), "super['y'] is computed");
4210 }
4211
4212 fn assert_flow_parse_has_errors(src: &[u8], why: &str) {
4218 assert_parse_has_errors_impl(src, why, true);
4219 }
4220
4221 #[test]
4224 fn flow_type_alias_number() {
4225 use hermes_ast::context::Context;
4226 use hermes_ast::node::Node;
4227 let mut sm = hermes_support::manager::SourceErrorManager::new();
4228 let mut ctx = Context::new();
4229 ctx.set_parse_flow(true);
4230 let gc = ctx.lock();
4231 let stmt = parse_one_stmt(&gc, &mut sm, b"type X = number;");
4232 let Node::TypeAlias(alias) = stmt else {
4233 panic!("expected TypeAlias, got {:?}", stmt.kind())
4234 };
4235 assert_eq!(ident_bytes(&gc, alias.id), b"X");
4236 assert!(alias.type_parameters.is_none(), "no type parameters");
4237 assert!(
4238 matches!(alias.right, Node::NumberTypeAnnotation(_)),
4239 "right is NumberTypeAnnotation, got {:?}",
4240 alias.right.kind()
4241 );
4242 }
4243
4244 #[test]
4247 fn flow_type_alias_string_literal() {
4248 use hermes_ast::context::Context;
4249 use hermes_ast::node::Node;
4250 let mut sm = hermes_support::manager::SourceErrorManager::new();
4251 let mut ctx = Context::new();
4252 ctx.set_parse_flow(true);
4253 let gc = ctx.lock();
4254 let stmt = parse_one_stmt(&gc, &mut sm, b"type X = 'hi';");
4255 let Node::TypeAlias(alias) = stmt else {
4256 panic!("expected TypeAlias, got {:?}", stmt.kind())
4257 };
4258 let Node::StringLiteralTypeAnnotation(lit) = alias.right else {
4259 panic!(
4260 "expected StringLiteralTypeAnnotation, got {:?}",
4261 alias.right.kind()
4262 )
4263 };
4264 assert_eq!(gc.ctx().atom_table.bytes(lit.value.get()), b"hi");
4265 assert_eq!(gc.ctx().atom_table.bytes(lit.raw.get()), b"'hi'");
4266 }
4267
4268 #[test]
4272 fn flow_disabled_type_alias_is_plain_js() {
4273 assert_parse_has_errors(
4274 b"type X = number;",
4275 "'type X' must not parse as a declaration without parse_flow",
4276 );
4277 }
4278
4279 #[test]
4281 fn flow_disabled_type_is_plain_identifier() {
4282 use hermes_ast::context::Context;
4283 use hermes_ast::node::Node;
4284 let mut sm = hermes_support::manager::SourceErrorManager::new();
4285 let mut ctx = Context::new();
4286 let gc = ctx.lock();
4287 let stmt = parse_one_stmt(&gc, &mut sm, b"var type = 1;");
4288 assert!(
4289 matches!(stmt, Node::VariableDeclaration(_)),
4290 "expected VariableDeclaration, got {:?}",
4291 stmt.kind()
4292 );
4293 }
4294
4295 fn flow_enum<'gc>(
4303 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
4304 sm: &mut hermes_support::manager::SourceErrorManager,
4305 src: &[u8],
4306 ) -> (&'gc hermes_ast::node::Node<'gc>, &'gc hermes_ast::node::Node<'gc>) {
4307 let stmt = parse_one_stmt(gc, sm, src);
4308 let hermes_ast::node::Node::EnumDeclaration(decl) = stmt else {
4309 panic!("expected EnumDeclaration, got {:?}", stmt.kind())
4310 };
4311 (stmt, decl.body)
4312 }
4313
4314 #[test]
4317 fn flow_enum_empty() {
4318 use hermes_ast::context::Context;
4319 use hermes_ast::node::Node;
4320 let mut sm = hermes_support::manager::SourceErrorManager::new();
4321 let mut ctx = Context::new();
4322 ctx.set_parse_flow(true);
4323 let gc = ctx.lock();
4324 let (_, body) = flow_enum(&gc, &mut sm, b"enum E {}");
4325 let Node::EnumStringBody(b) = body else {
4326 panic!("expected EnumStringBody, got {:?}", body.kind())
4327 };
4328 assert!(b.members.is_empty(), "no members");
4329 assert!(!b.explicit_type.get(), "no explicit type");
4330 assert!(!b.has_unknown_members.get(), "no unknown members");
4331 assert_eq!(sm.error_count(), 0, "no errors");
4332 }
4333
4334 #[test]
4336 fn flow_enum_defaulted() {
4337 use hermes_ast::context::Context;
4338 use hermes_ast::node::Node;
4339 let mut sm = hermes_support::manager::SourceErrorManager::new();
4340 let mut ctx = Context::new();
4341 ctx.set_parse_flow(true);
4342 let gc = ctx.lock();
4343 let (_, body) = flow_enum(&gc, &mut sm, b"enum E { A, B, C }");
4344 let Node::EnumStringBody(b) = body else {
4345 panic!("expected EnumStringBody, got {:?}", body.kind())
4346 };
4347 assert_eq!(b.members.iter().count(), 3, "three members");
4348 for m in b.members.iter() {
4349 assert!(
4350 matches!(m, Node::EnumDefaultedMember(_)),
4351 "member is defaulted, got {:?}",
4352 m.kind()
4353 );
4354 }
4355 assert_eq!(sm.error_count(), 0);
4356 }
4357
4358 #[test]
4361 fn flow_enum_number_typed() {
4362 use hermes_ast::context::Context;
4363 use hermes_ast::node::Node;
4364 let mut sm = hermes_support::manager::SourceErrorManager::new();
4365 let mut ctx = Context::new();
4366 ctx.set_parse_flow(true);
4367 let gc = ctx.lock();
4368 let (_, body) =
4369 flow_enum(&gc, &mut sm, b"enum N of number { A = 1, B = 2 }");
4370 let Node::EnumNumberBody(b) = body else {
4371 panic!("expected EnumNumberBody, got {:?}", body.kind())
4372 };
4373 assert!(b.explicit_type.get(), "explicit type");
4374 assert_eq!(b.members.iter().count(), 2);
4375 for m in b.members.iter() {
4376 assert!(
4377 matches!(m, Node::EnumNumberMember(_)),
4378 "member is EnumNumberMember, got {:?}",
4379 m.kind()
4380 );
4381 }
4382 assert_eq!(sm.error_count(), 0);
4383 }
4384
4385 #[test]
4387 fn flow_enum_boolean_typed() {
4388 use hermes_ast::context::Context;
4389 use hermes_ast::node::Node;
4390 let mut sm = hermes_support::manager::SourceErrorManager::new();
4391 let mut ctx = Context::new();
4392 ctx.set_parse_flow(true);
4393 let gc = ctx.lock();
4394 let (_, body) = flow_enum(
4395 &gc,
4396 &mut sm,
4397 b"enum B of boolean { A = true, B = false }",
4398 );
4399 let Node::EnumBooleanBody(b) = body else {
4400 panic!("expected EnumBooleanBody, got {:?}", body.kind())
4401 };
4402 assert!(b.explicit_type.get());
4403 assert!(matches!(
4404 b.members.iter().next().unwrap(),
4405 Node::EnumBooleanMember(_)
4406 ));
4407 assert_eq!(sm.error_count(), 0);
4408 }
4409
4410 #[test]
4413 fn flow_enum_symbol_body_has_no_explicit_type() {
4414 use hermes_ast::context::Context;
4415 use hermes_ast::node::Node;
4416 let mut sm = hermes_support::manager::SourceErrorManager::new();
4417 let mut ctx = Context::new();
4418 ctx.set_parse_flow(true);
4419 let gc = ctx.lock();
4420 let (_, body) = flow_enum(&gc, &mut sm, b"enum Y of symbol { A, B }");
4421 let Node::EnumSymbolBody(b) = body else {
4422 panic!("expected EnumSymbolBody, got {:?}", body.kind())
4423 };
4424 assert_eq!(b.members.iter().count(), 2);
4428 assert!(!b.has_unknown_members.get());
4429 assert_eq!(sm.error_count(), 0);
4430 }
4431
4432 #[test]
4434 fn flow_enum_inexact() {
4435 use hermes_ast::context::Context;
4436 use hermes_ast::node::Node;
4437 let mut sm = hermes_support::manager::SourceErrorManager::new();
4438 let mut ctx = Context::new();
4439 ctx.set_parse_flow(true);
4440 let gc = ctx.lock();
4441 let (_, body) =
4442 flow_enum(&gc, &mut sm, b"enum E { A = 1, B = 2, ... }");
4443 let Node::EnumNumberBody(b) = body else {
4444 panic!("expected EnumNumberBody, got {:?}", body.kind())
4445 };
4446 assert!(b.has_unknown_members.get(), "has unknown members");
4447 assert_eq!(b.members.iter().count(), 2, "two real members");
4448 assert_eq!(sm.error_count(), 0);
4449 }
4450
4451 #[test]
4453 fn flow_enum_negative_member() {
4454 use hermes_ast::context::Context;
4455 use hermes_ast::node::Node;
4456 let mut sm = hermes_support::manager::SourceErrorManager::new();
4457 let mut ctx = Context::new();
4458 ctx.set_parse_flow(true);
4459 let gc = ctx.lock();
4460 let (_, body) = flow_enum(&gc, &mut sm, b"enum E { A = -1, B = 2 }");
4461 let Node::EnumNumberBody(b) = body else {
4462 panic!("expected EnumNumberBody, got {:?}", body.kind())
4463 };
4464 let first = b.members.iter().next().unwrap();
4465 let Node::EnumNumberMember(m) = first else {
4466 panic!("expected EnumNumberMember, got {:?}", first.kind())
4467 };
4468 let Node::NumericLiteral(lit) = m.init else {
4469 panic!("expected NumericLiteral, got {:?}", m.init.kind())
4470 };
4471 assert_eq!(lit.value.get(), -1.0, "negated literal");
4472 assert_eq!(sm.error_count(), 0);
4473 }
4474
4475 #[test]
4477 fn flow_enum_kind_mismatch_errors() {
4478 assert_flow_parse_has_errors(
4479 b"enum N of number { A = 1, B = \"x\" }",
4480 "string initializer in number enum must error",
4481 );
4482 }
4483
4484 #[test]
4486 fn flow_enum_inconsistent_initializers_errors() {
4487 assert_flow_parse_has_errors(
4488 b"enum E { A = 1, B }",
4489 "mixed initialized/defaulted members must error",
4490 );
4491 }
4492
4493 #[test]
4495 fn flow_enum_defaulted_number_errors() {
4496 assert_flow_parse_has_errors(
4497 b"enum N of number { A, B }",
4498 "number enums must use initializers",
4499 );
4500 }
4501
4502 #[test]
4504 fn flow_disabled_enum_is_plain_identifier() {
4505 use hermes_ast::context::Context;
4506 use hermes_ast::node::Node;
4507 let mut sm = hermes_support::manager::SourceErrorManager::new();
4508 let mut ctx = Context::new();
4509 let gc = ctx.lock();
4510 let stmt = parse_one_stmt(&gc, &mut sm, b"var enum2 = 1;");
4511 assert!(
4512 matches!(stmt, Node::VariableDeclaration(_)),
4513 "expected VariableDeclaration, got {:?}",
4514 stmt.kind()
4515 );
4516 }
4517
4518 fn flow_ambiguous_expr<'gc>(
4526 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
4527 sm: &mut hermes_support::manager::SourceErrorManager,
4528 src: &[u8],
4529 ) -> &'gc hermes_ast::node::Node<'gc> {
4530 let stmt = parse_one_stmt(gc, sm, src);
4531 let hermes_ast::node::Node::ExpressionStatement(es) = stmt else {
4532 panic!("expected ExpressionStatement, got {:?}", stmt.kind())
4533 };
4534 es.expression
4535 }
4536
4537 #[test]
4539 fn flow_as_expression() {
4540 use hermes_ast::context::Context;
4541 use hermes_ast::node::Node;
4542 let mut sm = hermes_support::manager::SourceErrorManager::new();
4543 let mut ctx = Context::new();
4544 ctx.set_parse_flow(true);
4545 ctx.set_parse_flow_ambiguous(true);
4546 let gc = ctx.lock();
4547 let expr = flow_ambiguous_expr(&gc, &mut sm, b"x as number;");
4548 let Node::AsExpression(as_expr) = expr else {
4549 panic!("expected AsExpression, got {:?}", expr.kind())
4550 };
4551 assert_eq!(ident_bytes(&gc, as_expr.expression), b"x");
4552 assert!(
4553 matches!(as_expr.type_annotation, Node::NumberTypeAnnotation(_)),
4554 "type is NumberTypeAnnotation, got {:?}",
4555 as_expr.type_annotation.kind()
4556 );
4557 }
4558
4559 #[test]
4562 fn flow_as_const_expression() {
4563 use hermes_ast::context::Context;
4564 use hermes_ast::node::Node;
4565 let mut sm = hermes_support::manager::SourceErrorManager::new();
4566 let mut ctx = Context::new();
4567 ctx.set_parse_flow(true);
4568 ctx.set_parse_flow_ambiguous(true);
4569 let gc = ctx.lock();
4570 let expr = flow_ambiguous_expr(&gc, &mut sm, b"y as const;");
4571 let Node::AsConstExpression(as_const) = expr else {
4572 panic!("expected AsConstExpression, got {:?}", expr.kind())
4573 };
4574 assert_eq!(ident_bytes(&gc, as_const.expression), b"y");
4575 }
4576
4577 #[test]
4580 fn flow_call_type_args_vs_comparison() {
4581 use hermes_ast::context::Context;
4582 use hermes_ast::node::Node;
4583 {
4585 let mut sm = hermes_support::manager::SourceErrorManager::new();
4586 let mut ctx = Context::new();
4587 ctx.set_parse_flow(true);
4588 ctx.set_parse_flow_ambiguous(true);
4589 let gc = ctx.lock();
4590 let expr = flow_ambiguous_expr(&gc, &mut sm, b"f<T>();");
4591 let Node::CallExpression(call) = expr else {
4592 panic!("expected CallExpression, got {:?}", expr.kind())
4593 };
4594 assert!(
4595 call.type_arguments.is_some(),
4596 "f<T>() must keep type arguments"
4597 );
4598 }
4599 {
4601 let mut sm = hermes_support::manager::SourceErrorManager::new();
4602 let mut ctx = Context::new();
4603 ctx.set_parse_flow(true);
4604 ctx.set_parse_flow_ambiguous(true);
4605 let gc = ctx.lock();
4606 let expr = flow_ambiguous_expr(&gc, &mut sm, b"a < b;");
4607 assert!(
4608 matches!(expr, Node::BinaryExpression(_)),
4609 "a < b must be a BinaryExpression, got {:?}",
4610 expr.kind()
4611 );
4612 }
4613 }
4614
4615 #[test]
4618 fn flow_new_type_args() {
4619 use hermes_ast::context::Context;
4620 use hermes_ast::node::Node;
4621 {
4623 let mut sm = hermes_support::manager::SourceErrorManager::new();
4624 let mut ctx = Context::new();
4625 ctx.set_parse_flow(true);
4626 ctx.set_parse_flow_ambiguous(true);
4627 let gc = ctx.lock();
4628 let expr = flow_ambiguous_expr(&gc, &mut sm, b"new C<T>;");
4629 let Node::NewExpression(new_expr) = expr else {
4630 panic!("expected NewExpression, got {:?}", expr.kind())
4631 };
4632 assert!(
4633 new_expr.type_arguments.is_some(),
4634 "new C<T> must keep type arguments"
4635 );
4636 assert_eq!(new_expr.arguments.iter().count(), 0, "no args");
4637 }
4638 {
4640 let mut sm = hermes_support::manager::SourceErrorManager::new();
4641 let mut ctx = Context::new();
4642 ctx.set_parse_flow(true);
4643 ctx.set_parse_flow_ambiguous(true);
4644 let gc = ctx.lock();
4645 let expr = flow_ambiguous_expr(&gc, &mut sm, b"new C<T>(x);");
4646 let Node::NewExpression(new_expr) = expr else {
4647 panic!("expected NewExpression, got {:?}", expr.kind())
4648 };
4649 assert!(new_expr.type_arguments.is_some(), "type args kept");
4650 assert_eq!(new_expr.arguments.iter().count(), 1, "one arg");
4651 }
4652 }
4653
4654 #[test]
4657 fn flow_optional_call_type_args() {
4658 use hermes_ast::context::Context;
4659 use hermes_ast::node::Node;
4660 let mut sm = hermes_support::manager::SourceErrorManager::new();
4661 let mut ctx = Context::new();
4662 ctx.set_parse_flow(true);
4663 ctx.set_parse_flow_ambiguous(true);
4664 let gc = ctx.lock();
4665 let expr = flow_ambiguous_expr(&gc, &mut sm, b"obj?.foo<T>(x);");
4666 let Node::OptionalCallExpression(call) = expr else {
4669 panic!("expected OptionalCallExpression, got {:?}", expr.kind())
4670 };
4671 assert!(
4672 call.type_arguments.is_some(),
4673 "obj?.foo<T>(x) must keep type arguments"
4674 );
4675 assert_eq!(call.arguments.iter().count(), 1, "one argument");
4676 }
4677
4678 #[test]
4681 fn flow_ambiguous_off_keeps_comparison() {
4682 use hermes_ast::context::Context;
4683 use hermes_ast::node::Node;
4684 let mut sm = hermes_support::manager::SourceErrorManager::new();
4686 let mut ctx = Context::new();
4687 ctx.set_parse_flow(true);
4688 let gc = ctx.lock();
4690 let expr = flow_ambiguous_expr(&gc, &mut sm, b"f < T > (g);");
4691 assert!(
4693 matches!(expr, Node::BinaryExpression(_)),
4694 "without ambiguous flag, f<T>(g) is a comparison, got {:?}",
4695 expr.kind()
4696 );
4697 }
4698
4699 fn flow_const_init<'gc>(
4708 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
4709 sm: &mut hermes_support::manager::SourceErrorManager,
4710 src: &[u8],
4711 ) -> &'gc hermes_ast::node::Node<'gc> {
4712 let stmt = parse_one_stmt(gc, sm, src);
4713 let hermes_ast::node::Node::VariableDeclaration(vd) = stmt else {
4714 panic!("expected VariableDeclaration, got {:?}", stmt.kind())
4715 };
4716 let decl = vd.declarations.iter().next().expect("one declarator");
4717 let hermes_ast::node::Node::VariableDeclarator(d) = decl else {
4718 panic!("expected VariableDeclarator, got {:?}", decl.kind())
4719 };
4720 d.init.expect("declarator has an init")
4721 }
4722
4723 #[test]
4726 fn flow_typed_arrow_full() {
4727 use hermes_ast::context::Context;
4728 use hermes_ast::node::Node;
4729 let mut sm = hermes_support::manager::SourceErrorManager::new();
4730 let mut ctx = Context::new();
4731 ctx.set_parse_flow(true);
4732 let gc = ctx.lock();
4733 let init =
4734 flow_const_init(&gc, &mut sm, b"const f = <T>(x: T): T => x;");
4735 let Node::ArrowFunctionExpression(arrow) = init else {
4736 panic!("expected ArrowFunctionExpression, got {:?}", init.kind())
4737 };
4738 assert!(arrow.type_parameters.is_some(), "has type parameters");
4739 assert!(arrow.return_type.is_some(), "has return type");
4740 assert!(arrow.predicate.is_none(), "no predicate");
4741 assert!(arrow.expression.get(), "concise (expression) body");
4742 assert!(!arrow.r#async.get(), "not async");
4743 }
4744
4745 #[test]
4748 fn flow_typed_arrow_predicate() {
4749 use hermes_ast::context::Context;
4750 use hermes_ast::node::Node;
4751 let mut sm = hermes_support::manager::SourceErrorManager::new();
4752 let mut ctx = Context::new();
4753 ctx.set_parse_flow(true);
4754 let gc = ctx.lock();
4755 let init = flow_const_init(
4756 &gc,
4757 &mut sm,
4758 b"const g = (x): x is number => true;",
4759 );
4760 let Node::ArrowFunctionExpression(arrow) = init else {
4761 panic!("expected ArrowFunctionExpression, got {:?}", init.kind())
4762 };
4763 assert!(arrow.type_parameters.is_none(), "no type parameters");
4764 let rt = arrow.return_type.expect("predicate sets return_type");
4767 let Node::TypeAnnotation(ta) = rt else {
4768 panic!("return_type wraps a TypeAnnotation, got {:?}", rt.kind())
4769 };
4770 assert!(
4771 matches!(ta.type_annotation, Node::TypePredicate(_)),
4772 "return type is a TypePredicate, got {:?}",
4773 ta.type_annotation.kind()
4774 );
4775 assert!(arrow.predicate.is_none(), "no %checks predicate");
4776 }
4777
4778 #[test]
4781 fn flow_typed_arrow_void_block() {
4782 use hermes_ast::context::Context;
4783 use hermes_ast::node::Node;
4784 let mut sm = hermes_support::manager::SourceErrorManager::new();
4785 let mut ctx = Context::new();
4786 ctx.set_parse_flow(true);
4787 let gc = ctx.lock();
4788 let init = flow_const_init(&gc, &mut sm, b"const e = (): void => {};");
4789 let Node::ArrowFunctionExpression(arrow) = init else {
4790 panic!("expected ArrowFunctionExpression, got {:?}", init.kind())
4791 };
4792 assert!(arrow.return_type.is_some(), "has return type");
4793 assert!(!arrow.expression.get(), "block body");
4794 }
4795
4796 #[test]
4798 fn flow_typed_async_arrow() {
4799 use hermes_ast::context::Context;
4800 use hermes_ast::node::Node;
4801 let mut sm = hermes_support::manager::SourceErrorManager::new();
4802 let mut ctx = Context::new();
4803 ctx.set_parse_flow(true);
4804 let gc = ctx.lock();
4805 let init =
4806 flow_const_init(&gc, &mut sm, b"const f = async <T>(x: T): T => x;");
4807 let Node::ArrowFunctionExpression(arrow) = init else {
4808 panic!("expected ArrowFunctionExpression, got {:?}", init.kind())
4809 };
4810 assert!(arrow.r#async.get(), "is async");
4811 assert!(arrow.type_parameters.is_some(), "has type parameters");
4812 assert!(arrow.return_type.is_some(), "has return type");
4813 }
4814
4815 #[test]
4817 fn flow_typed_async_arrow_no_generics() {
4818 use hermes_ast::context::Context;
4819 use hermes_ast::node::Node;
4820 let mut sm = hermes_support::manager::SourceErrorManager::new();
4821 let mut ctx = Context::new();
4822 ctx.set_parse_flow(true);
4823 let gc = ctx.lock();
4824 let init =
4825 flow_const_init(&gc, &mut sm, b"const g = async (x: number) => x;");
4826 let Node::ArrowFunctionExpression(arrow) = init else {
4827 panic!("expected ArrowFunctionExpression, got {:?}", init.kind())
4828 };
4829 assert!(arrow.r#async.get(), "is async");
4830 assert!(arrow.type_parameters.is_none(), "no type parameters");
4831 }
4832
4833 #[test]
4836 fn flow_plain_async_arrow_still_works() {
4837 use hermes_ast::context::Context;
4838 use hermes_ast::node::Node;
4839 let mut sm = hermes_support::manager::SourceErrorManager::new();
4840 let mut ctx = Context::new();
4841 ctx.set_parse_flow(true);
4842 let gc = ctx.lock();
4843 let init = flow_const_init(&gc, &mut sm, b"const g = async (x) => x;");
4844 let Node::ArrowFunctionExpression(arrow) = init else {
4845 panic!("expected ArrowFunctionExpression, got {:?}", init.kind())
4846 };
4847 assert!(arrow.r#async.get(), "is async");
4848 assert!(arrow.type_parameters.is_none(), "no type parameters");
4849 assert!(arrow.return_type.is_none(), "no return type");
4850 }
4851
4852 #[test]
4855 fn flow_async_as_identifier() {
4856 use hermes_ast::context::Context;
4857 use hermes_ast::node::Node;
4858 let mut sm = hermes_support::manager::SourceErrorManager::new();
4859 let mut ctx = Context::new();
4860 ctx.set_parse_flow(true);
4861 let gc = ctx.lock();
4862 let init = flow_const_init(&gc, &mut sm, b"const a = async;");
4863 assert!(
4864 matches!(init, Node::Identifier(_)),
4865 "bare `async` is an Identifier, got {:?}",
4866 init.kind()
4867 );
4868 }
4869
4870 #[test]
4872 fn flow_type_cast() {
4873 use hermes_ast::context::Context;
4874 use hermes_ast::node::Node;
4875 let mut sm = hermes_support::manager::SourceErrorManager::new();
4876 let mut ctx = Context::new();
4877 ctx.set_parse_flow(true);
4878 let gc = ctx.lock();
4879 let init = flow_const_init(&gc, &mut sm, b"const a = (x: number);");
4880 let Node::TypeCastExpression(cast) = init else {
4881 panic!("expected TypeCastExpression, got {:?}", init.kind())
4882 };
4883 assert_eq!(ident_bytes(&gc, cast.expression), b"x");
4884 assert!(
4885 matches!(cast.type_annotation, Node::TypeAnnotation(_)),
4886 "type is wrapped in a TypeAnnotation, got {:?}",
4887 cast.type_annotation.kind()
4888 );
4889 }
4890
4891 #[test]
4894 fn flow_type_cast_object() {
4895 use hermes_ast::context::Context;
4896 use hermes_ast::node::Node;
4897 let mut sm = hermes_support::manager::SourceErrorManager::new();
4898 let mut ctx = Context::new();
4899 ctx.set_parse_flow(true);
4900 let gc = ctx.lock();
4901 let init = flow_const_init(&gc, &mut sm, b"const b = ({p}: O);");
4902 let Node::TypeCastExpression(cast) = init else {
4903 panic!("expected TypeCastExpression, got {:?}", init.kind())
4904 };
4905 assert!(
4906 matches!(cast.expression, Node::ObjectExpression(_)),
4907 "expr is ObjectExpression, got {:?}",
4908 cast.expression.kind()
4909 );
4910 }
4911
4912 #[test]
4915 fn flow_conditional_consequent_cover() {
4916 use hermes_ast::context::Context;
4917 use hermes_ast::node::Node;
4918 let mut sm = hermes_support::manager::SourceErrorManager::new();
4919 let mut ctx = Context::new();
4920 ctx.set_parse_flow(true);
4921 let gc = ctx.lock();
4922 let init =
4923 flow_const_init(&gc, &mut sm, b"const c = cond ? (a: T) => a : b;");
4924 let Node::ConditionalExpression(cond) = init else {
4925 panic!("expected ConditionalExpression, got {:?}", init.kind())
4926 };
4927 assert!(
4928 matches!(cond.consequent, Node::ArrowFunctionExpression(_)),
4929 "consequent is a typed arrow, got {:?}",
4930 cond.consequent.kind()
4931 );
4932 assert_eq!(ident_bytes(&gc, cond.alternate), b"b");
4933 }
4934
4935 #[test]
4939 fn flow_typed_arrow_disambiguation_comparison() {
4940 use hermes_ast::context::Context;
4941 use hermes_ast::node::Node;
4942 let mut sm = hermes_support::manager::SourceErrorManager::new();
4943 let mut ctx = Context::new();
4944 ctx.set_parse_flow(true);
4945 let gc = ctx.lock();
4946 let init =
4947 flow_const_init(&gc, &mut sm, b"const r = (a < b, c > (d));");
4948 assert!(
4951 matches!(init, Node::SequenceExpression(_)),
4952 "comparison sequence, got {:?}",
4953 init.kind()
4954 );
4955 }
4956
4957 #[test]
4960 fn flow_typed_arrow_lt_not_arrow() {
4961 use hermes_ast::context::Context;
4962 use hermes_ast::node::Node;
4963 let mut sm = hermes_support::manager::SourceErrorManager::new();
4964 let mut ctx = Context::new();
4965 ctx.set_parse_flow(true);
4966 let gc = ctx.lock();
4967 let init = flow_const_init(&gc, &mut sm, b"const r = a < b;");
4968 assert!(
4969 matches!(init, Node::BinaryExpression(_)),
4970 "a < b is a comparison, got {:?}",
4971 init.kind()
4972 );
4973 }
4974
4975 fn flow_alias_right<'gc>(
4980 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
4981 sm: &mut hermes_support::manager::SourceErrorManager,
4982 src: &[u8],
4983 ) -> &'gc hermes_ast::node::Node<'gc> {
4984 let stmt = parse_one_stmt(gc, sm, src);
4985 let hermes_ast::node::Node::TypeAlias(alias) = stmt else {
4986 panic!("expected TypeAlias, got {:?}", stmt.kind())
4987 };
4988 alias.right
4989 }
4990
4991 fn assert_generic_named<'gc>(
4994 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
4995 node: &hermes_ast::node::Node<'gc>,
4996 name: &[u8],
4997 ) {
4998 use hermes_ast::node::Node;
4999 let Node::GenericTypeAnnotation(g) = node else {
5000 panic!("expected GenericTypeAnnotation, got {:?}", node.kind())
5001 };
5002 assert!(g.type_parameters.is_none(), "no type args");
5003 assert_eq!(ident_bytes(gc, g.id), name);
5004 }
5005
5006 #[test]
5009 fn flow_union_intersection_types() {
5010 use hermes_ast::context::Context;
5011 use hermes_ast::node::Node;
5012 let mut sm = hermes_support::manager::SourceErrorManager::new();
5013 let mut ctx = Context::new();
5014 ctx.set_parse_flow(true);
5015 let gc = ctx.lock();
5016
5017 let ty = flow_alias_right(&gc, &mut sm, b"type A = X | Y | Z;");
5019 let Node::UnionTypeAnnotation(u) = ty else {
5020 panic!("expected UnionTypeAnnotation, got {:?}", ty.kind())
5021 };
5022 let members: Vec<_> = u.types.iter().collect();
5023 assert_eq!(members.len(), 3);
5024 assert_generic_named(&gc, members[0], b"X");
5025 assert_generic_named(&gc, members[2], b"Z");
5026
5027 let ty = flow_alias_right(&gc, &mut sm, b"type A = | X | Y;");
5029 let Node::UnionTypeAnnotation(u) = ty else {
5030 panic!("expected UnionTypeAnnotation, got {:?}", ty.kind())
5031 };
5032 assert_eq!(u.types.iter().count(), 2);
5033
5034 let ty = flow_alias_right(&gc, &mut sm, b"type A = | X;");
5036 assert_generic_named(&gc, ty, b"X");
5037
5038 let ty = flow_alias_right(&gc, &mut sm, b"type A = X & Y | Z;");
5040 let Node::UnionTypeAnnotation(u) = ty else {
5041 panic!("expected UnionTypeAnnotation, got {:?}", ty.kind())
5042 };
5043 let members: Vec<_> = u.types.iter().collect();
5044 assert_eq!(members.len(), 2);
5045 let Node::IntersectionTypeAnnotation(i) = members[0] else {
5046 panic!(
5047 "expected IntersectionTypeAnnotation, got {:?}",
5048 members[0].kind()
5049 )
5050 };
5051 assert_eq!(i.types.iter().count(), 2);
5052 assert_generic_named(&gc, members[1], b"Z");
5053 }
5054
5055 #[test]
5057 fn flow_nullable_nesting() {
5058 use hermes_ast::context::Context;
5059 use hermes_ast::node::Node;
5060 let mut sm = hermes_support::manager::SourceErrorManager::new();
5061 let mut ctx = Context::new();
5062 ctx.set_parse_flow(true);
5063 let gc = ctx.lock();
5064
5065 let ty = flow_alias_right(&gc, &mut sm, b"type A = ??X;");
5066 let Node::NullableTypeAnnotation(outer) = ty else {
5067 panic!("expected NullableTypeAnnotation, got {:?}", ty.kind())
5068 };
5069 let Node::NullableTypeAnnotation(inner) = outer.type_annotation else {
5070 panic!(
5071 "expected nested NullableTypeAnnotation, got {:?}",
5072 outer.type_annotation.kind()
5073 )
5074 };
5075 assert_generic_named(&gc, inner.type_annotation, b"X");
5076 }
5077
5078 #[test]
5081 fn flow_postfix_types() {
5082 use hermes_ast::context::Context;
5083 use hermes_ast::node::Node;
5084 let mut sm = hermes_support::manager::SourceErrorManager::new();
5085 let mut ctx = Context::new();
5086 ctx.set_parse_flow(true);
5087 let gc = ctx.lock();
5088
5089 let ty = flow_alias_right(&gc, &mut sm, b"type A = X[][];");
5091 let Node::ArrayTypeAnnotation(outer) = ty else {
5092 panic!("expected ArrayTypeAnnotation, got {:?}", ty.kind())
5093 };
5094 let Node::ArrayTypeAnnotation(inner) = outer.element_type else {
5095 panic!(
5096 "expected nested ArrayTypeAnnotation, got {:?}",
5097 outer.element_type.kind()
5098 )
5099 };
5100 assert_generic_named(&gc, inner.element_type, b"X");
5101
5102 let ty = flow_alias_right(&gc, &mut sm, b"type A = X[K];");
5104 let Node::IndexedAccessType(idx) = ty else {
5105 panic!("expected IndexedAccessType, got {:?}", ty.kind())
5106 };
5107 assert_generic_named(&gc, idx.object_type, b"X");
5108 assert_generic_named(&gc, idx.index_type, b"K");
5109
5110 let ty = flow_alias_right(&gc, &mut sm, b"type A = X?.[K];");
5112 let Node::OptionalIndexedAccessType(opt) = ty else {
5113 panic!("expected OptionalIndexedAccessType, got {:?}", ty.kind())
5114 };
5115 assert!(opt.optional.get(), "?.[ access is optional");
5116
5117 let ty = flow_alias_right(&gc, &mut sm, b"type A = X?.[A][B];");
5120 let Node::OptionalIndexedAccessType(outer) = ty else {
5121 panic!("expected OptionalIndexedAccessType, got {:?}", ty.kind())
5122 };
5123 assert!(!outer.optional.get(), "[B] itself is not optional");
5124 let Node::OptionalIndexedAccessType(inner) = outer.object_type else {
5125 panic!(
5126 "expected inner OptionalIndexedAccessType, got {:?}",
5127 outer.object_type.kind()
5128 )
5129 };
5130 assert!(inner.optional.get(), "?.[A] is optional");
5131 }
5132
5133 #[test]
5137 fn flow_generic_types() {
5138 use hermes_ast::context::Context;
5139 use hermes_ast::node::Node;
5140 let mut sm = hermes_support::manager::SourceErrorManager::new();
5141 let mut ctx = Context::new();
5142 ctx.set_parse_flow(true);
5143 let gc = ctx.lock();
5144
5145 let ty = flow_alias_right(&gc, &mut sm, b"type A = Foo.Bar.Baz;");
5147 let Node::GenericTypeAnnotation(g) = ty else {
5148 panic!("expected GenericTypeAnnotation, got {:?}", ty.kind())
5149 };
5150 assert!(g.type_parameters.is_none());
5151 let Node::QualifiedTypeIdentifier(outer) = g.id else {
5152 panic!("expected QualifiedTypeIdentifier, got {:?}", g.id.kind())
5153 };
5154 assert_eq!(ident_bytes(&gc, outer.id), b"Baz");
5155 let Node::QualifiedTypeIdentifier(inner) = outer.qualification else {
5156 panic!(
5157 "expected inner QualifiedTypeIdentifier, got {:?}",
5158 outer.qualification.kind()
5159 )
5160 };
5161 assert_eq!(ident_bytes(&gc, inner.qualification), b"Foo");
5162 assert_eq!(ident_bytes(&gc, inner.id), b"Bar");
5163
5164 let ty = flow_alias_right(&gc, &mut sm, b"type A = Foo<>;");
5166 let Node::GenericTypeAnnotation(g) = ty else {
5167 panic!("expected GenericTypeAnnotation, got {:?}", ty.kind())
5168 };
5169 let args = g.type_parameters.expect("has type args");
5170 let Node::TypeParameterInstantiation(inst) = args else {
5171 panic!("expected TypeParameterInstantiation, got {:?}", args.kind())
5172 };
5173 assert_eq!(inst.params.iter().count(), 0, "`Foo<>` has no args");
5174
5175 let ty = flow_alias_right(&gc, &mut sm, b"type A = Foo<X, Y>;");
5177 let Node::GenericTypeAnnotation(g) = ty else {
5178 panic!("expected GenericTypeAnnotation, got {:?}", ty.kind())
5179 };
5180 let Node::TypeParameterInstantiation(inst) =
5181 g.type_parameters.expect("has type args")
5182 else {
5183 panic!("expected TypeParameterInstantiation")
5184 };
5185 assert_eq!(inst.params.iter().count(), 2);
5186 }
5187
5188 #[test]
5193 fn flow_nested_generic_type_args() {
5194 use hermes_ast::context::Context;
5195 use hermes_ast::node::Node;
5196 let mut sm = hermes_support::manager::SourceErrorManager::new();
5197 let mut ctx = Context::new();
5198 ctx.set_parse_flow(true);
5199 let gc = ctx.lock();
5200
5201 let ty = flow_alias_right(&gc, &mut sm, b"type A = Foo<Bar<Baz<U>>>;");
5204 let mut node = ty;
5205 for name in [&b"Foo"[..], b"Bar", b"Baz"] {
5206 let Node::GenericTypeAnnotation(g) = node else {
5207 panic!("expected GenericTypeAnnotation, got {:?}", node.kind())
5208 };
5209 assert_eq!(ident_bytes(&gc, g.id), name);
5210 let Node::TypeParameterInstantiation(inst) =
5211 g.type_parameters.expect("has type args")
5212 else {
5213 panic!("expected TypeParameterInstantiation")
5214 };
5215 assert_eq!(inst.params.iter().count(), 1, "one arg at each level");
5216 node = inst.params.iter().next().unwrap();
5217 }
5218 assert_generic_named(&gc, node, b"U");
5220 }
5221
5222 #[test]
5225 fn flow_typeof_types() {
5226 use hermes_ast::context::Context;
5227 use hermes_ast::node::Node;
5228 let mut sm = hermes_support::manager::SourceErrorManager::new();
5229 let mut ctx = Context::new();
5230 ctx.set_parse_flow(true);
5231 let gc = ctx.lock();
5232
5233 let ty = flow_alias_right(&gc, &mut sm, b"type A = typeof x.y;");
5235 let Node::TypeofTypeAnnotation(t) = ty else {
5236 panic!("expected TypeofTypeAnnotation, got {:?}", ty.kind())
5237 };
5238 assert!(t.type_arguments.is_none());
5239 let Node::QualifiedTypeofIdentifier(q) = t.argument else {
5240 panic!(
5241 "expected QualifiedTypeofIdentifier, got {:?}",
5242 t.argument.kind()
5243 )
5244 };
5245 assert_eq!(ident_bytes(&gc, q.qualification), b"x");
5246 assert_eq!(ident_bytes(&gc, q.id), b"y");
5247
5248 let ty = flow_alias_right(&gc, &mut sm, b"type A = typeof (x);");
5250 let Node::TypeofTypeAnnotation(t) = ty else {
5251 panic!("expected TypeofTypeAnnotation, got {:?}", ty.kind())
5252 };
5253 assert!(matches!(t.argument, Node::Identifier(_)));
5254 assert_eq!(t.argument.metadata().parens.get(), 1, "one paren recorded");
5255
5256 let ty = flow_alias_right(&gc, &mut sm, b"type A = typeof x<Y>;");
5258 let Node::TypeofTypeAnnotation(t) = ty else {
5259 panic!("expected TypeofTypeAnnotation, got {:?}", ty.kind())
5260 };
5261 let Node::TypeParameterInstantiation(inst) =
5262 t.type_arguments.expect("has type args")
5263 else {
5264 panic!("expected TypeParameterInstantiation")
5265 };
5266 assert_eq!(inst.params.iter().count(), 1);
5267 }
5268
5269 #[test]
5272 fn flow_tuple_types() {
5273 use hermes_ast::context::Context;
5274 use hermes_ast::node::Node;
5275 let mut sm = hermes_support::manager::SourceErrorManager::new();
5276 let mut ctx = Context::new();
5277 ctx.set_parse_flow(true);
5278 let gc = ctx.lock();
5279
5280 let ty = flow_alias_right(&gc, &mut sm, b"type A = [X, Y];");
5282 let Node::TupleTypeAnnotation(t) = ty else {
5283 panic!("expected TupleTypeAnnotation, got {:?}", ty.kind())
5284 };
5285 assert!(!t.inexact.get());
5286 let elems: Vec<_> = t.element_types.iter().collect();
5287 assert_eq!(elems.len(), 2);
5288 assert_generic_named(&gc, elems[0], b"X");
5289
5290 let ty = flow_alias_right(&gc, &mut sm, b"type A = [a: X, b?: Y];");
5292 let Node::TupleTypeAnnotation(t) = ty else {
5293 panic!("expected TupleTypeAnnotation, got {:?}", ty.kind())
5294 };
5295 let elems: Vec<_> = t.element_types.iter().collect();
5296 assert_eq!(elems.len(), 2);
5297 let Node::TupleTypeLabeledElement(first) = elems[0] else {
5298 panic!(
5299 "expected TupleTypeLabeledElement, got {:?}",
5300 elems[0].kind()
5301 )
5302 };
5303 assert_eq!(ident_bytes(&gc, first.label), b"a");
5304 assert!(!first.optional.get());
5305 assert!(first.variance.is_none());
5306 let Node::TupleTypeLabeledElement(second) = elems[1] else {
5307 panic!(
5308 "expected TupleTypeLabeledElement, got {:?}",
5309 elems[1].kind()
5310 )
5311 };
5312 assert!(second.optional.get(), "b? is optional");
5313
5314 let ty = flow_alias_right(&gc, &mut sm, b"type A = [X, ...Y];");
5316 let Node::TupleTypeAnnotation(t) = ty else {
5317 panic!("expected TupleTypeAnnotation, got {:?}", ty.kind())
5318 };
5319 let elems: Vec<_> = t.element_types.iter().collect();
5320 let Node::TupleTypeSpreadElement(spread) = elems[1] else {
5321 panic!(
5322 "expected TupleTypeSpreadElement, got {:?}",
5323 elems[1].kind()
5324 )
5325 };
5326 assert!(spread.label.is_none());
5327 assert_generic_named(&gc, spread.type_annotation, b"Y");
5328
5329 let ty = flow_alias_right(&gc, &mut sm, b"type A = [...rest: Y];");
5330 let Node::TupleTypeAnnotation(t) = ty else {
5331 panic!("expected TupleTypeAnnotation, got {:?}", ty.kind())
5332 };
5333 let elems: Vec<_> = t.element_types.iter().collect();
5334 let Node::TupleTypeSpreadElement(spread) = elems[0] else {
5335 panic!(
5336 "expected TupleTypeSpreadElement, got {:?}",
5337 elems[0].kind()
5338 )
5339 };
5340 assert_eq!(ident_bytes(&gc, spread.label.expect("labeled")), b"rest");
5341
5342 let ty = flow_alias_right(&gc, &mut sm, b"type A = [+a: X, -b: Y];");
5344 let Node::TupleTypeAnnotation(t) = ty else {
5345 panic!("expected TupleTypeAnnotation, got {:?}", ty.kind())
5346 };
5347 let elems: Vec<_> = t.element_types.iter().collect();
5348 let Node::TupleTypeLabeledElement(first) = elems[0] else {
5349 panic!("expected TupleTypeLabeledElement")
5350 };
5351 let Node::Variance(v) = first.variance.expect("has variance") else {
5352 panic!("expected Variance")
5353 };
5354 assert_eq!(gc.ctx().atom_table.bytes(v.kind.get()), b"plus");
5355 let Node::TupleTypeLabeledElement(second) = elems[1] else {
5356 panic!("expected TupleTypeLabeledElement")
5357 };
5358 let Node::Variance(v) = second.variance.expect("has variance") else {
5359 panic!("expected Variance")
5360 };
5361 assert_eq!(gc.ctx().atom_table.bytes(v.kind.get()), b"minus");
5362
5363 let ty = flow_alias_right(&gc, &mut sm, b"type A = [X, ...];");
5365 let Node::TupleTypeAnnotation(t) = ty else {
5366 panic!("expected TupleTypeAnnotation, got {:?}", ty.kind())
5367 };
5368 assert!(t.inexact.get(), "trailing ... makes the tuple inexact");
5369 assert_eq!(t.element_types.iter().count(), 1);
5370
5371 let ty = flow_alias_right(&gc, &mut sm, b"type A = [];");
5373 let Node::TupleTypeAnnotation(t) = ty else {
5374 panic!("expected TupleTypeAnnotation, got {:?}", ty.kind())
5375 };
5376 assert_eq!(t.element_types.iter().count(), 0);
5377 assert!(!t.inexact.get());
5378 }
5379
5380 #[test]
5383 fn flow_tuple_errors() {
5384 use hermes_ast::context::Context;
5385 use hermes_support::diag::{CollectingHandler, DiagKind};
5386 use hermes_support::manager::SourceErrorManager;
5387
5388 {
5390 let mut sm = SourceErrorManager::new();
5391 let mut ctx = Context::new();
5392 ctx.set_parse_flow(true);
5393 let gc = ctx.lock();
5394 let atoms = &gc.ctx().atom_table;
5395 let _ = parse_with_collector(&gc, &mut sm, atoms, b"type A = [X, ..., Y];");
5396 let h = sm.handler_as::<CollectingHandler>().unwrap();
5397 assert!(
5398 h.messages().iter().any(|m| m.kind == DiagKind::Error
5399 && m.message
5400 == "trailing commas after inexact tuple types are not allowed"),
5401 "got {:?}",
5402 h.messages().iter().map(|m| &m.message).collect::<Vec<_>>()
5403 );
5404 }
5405
5406 {
5408 let mut sm = SourceErrorManager::new();
5409 let mut ctx = Context::new();
5410 ctx.set_parse_flow(true);
5411 let gc = ctx.lock();
5412 let atoms = &gc.ctx().atom_table;
5413 let _ = parse_with_collector(&gc, &mut sm, atoms, b"type A = [+X];");
5414 let h = sm.handler_as::<CollectingHandler>().unwrap();
5415 assert!(
5416 h.messages().iter().any(|m| m.kind == DiagKind::Error
5417 && m.message
5418 == "Variance can only be used with labeled tuple elements"),
5419 "got {:?}",
5420 h.messages().iter().map(|m| &m.message).collect::<Vec<_>>()
5421 );
5422 }
5423
5424 {
5426 let mut sm = SourceErrorManager::new();
5427 let mut ctx = Context::new();
5428 ctx.set_parse_flow(true);
5429 let gc = ctx.lock();
5430 let atoms = &gc.ctx().atom_table;
5431 let _ = parse_with_collector(&gc, &mut sm, atoms, b"type A = [1: X];");
5432 let h = sm.handler_as::<CollectingHandler>().unwrap();
5433 assert!(
5434 h.messages().iter().any(|m| m.kind == DiagKind::Error
5435 && m.message == "identifier expected"),
5436 "got {:?}",
5437 h.messages().iter().map(|m| &m.message).collect::<Vec<_>>()
5438 );
5439 }
5440 }
5441
5442 #[test]
5444 fn flow_keyof_type() {
5445 use hermes_ast::context::Context;
5446 use hermes_ast::node::Node;
5447 let mut sm = hermes_support::manager::SourceErrorManager::new();
5448 let mut ctx = Context::new();
5449 ctx.set_parse_flow(true);
5450 let gc = ctx.lock();
5451
5452 let ty = flow_alias_right(&gc, &mut sm, b"type A = keyof X;");
5453 let Node::KeyofTypeAnnotation(k) = ty else {
5454 panic!("expected KeyofTypeAnnotation, got {:?}", ty.kind())
5455 };
5456 assert_generic_named(&gc, k.argument, b"X");
5457 }
5458
5459 #[test]
5462 fn flow_conditional_type() {
5463 use hermes_ast::context::Context;
5464 use hermes_ast::node::Node;
5465 let mut sm = hermes_support::manager::SourceErrorManager::new();
5466 let mut ctx = Context::new();
5467 ctx.set_parse_flow(true);
5468 let gc = ctx.lock();
5469
5470 let ty =
5471 flow_alias_right(&gc, &mut sm, b"type T = X extends Y ? A : B;");
5472 let Node::ConditionalTypeAnnotation(c) = ty else {
5473 panic!("expected ConditionalTypeAnnotation, got {:?}", ty.kind())
5474 };
5475 assert_generic_named(&gc, c.check_type, b"X");
5476 assert_generic_named(&gc, c.extends_type, b"Y");
5477 assert_generic_named(&gc, c.true_type, b"A");
5478 assert_generic_named(&gc, c.false_type, b"B");
5479 }
5480
5481 #[test]
5485 fn flow_infer_type_bound_and_backtrack() {
5486 use hermes_ast::context::Context;
5487 use hermes_ast::node::Node;
5488 let mut sm = hermes_support::manager::SourceErrorManager::new();
5489 let mut ctx = Context::new();
5490 ctx.set_parse_flow(true);
5491 let gc = ctx.lock();
5492
5493 fn infer_param<'gc>(node: &'gc Node<'gc>) -> &'gc hermes_ast::node::TypeParameter<'gc> {
5495 let Node::InferTypeAnnotation(i) = node else {
5496 panic!("expected InferTypeAnnotation, got {:?}", node.kind())
5497 };
5498 let Node::TypeParameter(p) = i.type_parameter else {
5499 panic!(
5500 "expected TypeParameter, got {:?}",
5501 i.type_parameter.kind()
5502 )
5503 };
5504 p
5505 }
5506
5507 let ty = flow_alias_right(
5509 &gc,
5510 &mut sm,
5511 b"type T = X extends infer U ? U : never;",
5512 );
5513 let Node::ConditionalTypeAnnotation(c) = ty else {
5514 panic!("expected ConditionalTypeAnnotation, got {:?}", ty.kind())
5515 };
5516 let p = infer_param(c.extends_type);
5517 assert_eq!(gc.ctx().atom_table.bytes(p.name.get()), b"U");
5518 assert!(p.bound.is_none());
5519 assert!(p.uses_extends_bound.get());
5520
5521 let ty = flow_alias_right(
5525 &gc,
5526 &mut sm,
5527 b"type T = X extends infer U extends V ? U : never;",
5528 );
5529 let Node::ConditionalTypeAnnotation(c) = ty else {
5530 panic!("expected ConditionalTypeAnnotation, got {:?}", ty.kind())
5531 };
5532 let p = infer_param(c.extends_type);
5533 let bound = p.bound.expect("bound kept");
5534 assert_generic_named(&gc, bound, b"V");
5535
5536 let ty = flow_alias_right(
5541 &gc,
5542 &mut sm,
5543 b"type T = infer U extends V ? A : B;",
5544 );
5545 let Node::ConditionalTypeAnnotation(c) = ty else {
5546 panic!("expected ConditionalTypeAnnotation, got {:?}", ty.kind())
5547 };
5548 let p = infer_param(c.check_type);
5549 assert!(p.bound.is_none(), "bound backtracked away");
5550 assert_generic_named(&gc, c.extends_type, b"V");
5551
5552 let ty =
5554 flow_alias_right(&gc, &mut sm, b"type T = infer U extends V;");
5555 let p = infer_param(ty);
5556 assert!(p.bound.is_some(), "no `?` follows — bound kept");
5557 }
5558
5559 #[test]
5562 fn flow_negative_literal_types() {
5563 use hermes_ast::context::Context;
5564 use hermes_ast::node::Node;
5565 let mut sm = hermes_support::manager::SourceErrorManager::new();
5566 let mut ctx = Context::new();
5567 ctx.set_parse_flow(true);
5568 let gc = ctx.lock();
5569
5570 let ty = flow_alias_right(&gc, &mut sm, b"type A = -3;");
5571 let Node::NumberLiteralTypeAnnotation(n) = ty else {
5572 panic!(
5573 "expected NumberLiteralTypeAnnotation, got {:?}",
5574 ty.kind()
5575 )
5576 };
5577 assert_eq!(n.value.get(), -3.0);
5578 assert_eq!(gc.ctx().atom_table.bytes(n.raw.get()), b"-3");
5579
5580 let ty = flow_alias_right(&gc, &mut sm, b"type A = -2n;");
5581 let Node::BigIntLiteralTypeAnnotation(b) = ty else {
5582 panic!(
5583 "expected BigIntLiteralTypeAnnotation, got {:?}",
5584 ty.kind()
5585 )
5586 };
5587 assert_eq!(gc.ctx().atom_table.bytes(b.raw.get()), b"-2n");
5588 }
5589
5590 fn as_fta<'gc, 'n>(
5595 node: &'n hermes_ast::node::Node<'gc>,
5596 ) -> &'n hermes_ast::node::FunctionTypeAnnotation<'gc> {
5597 let hermes_ast::node::Node::FunctionTypeAnnotation(fta) = node else {
5598 panic!("expected FunctionTypeAnnotation, got {:?}", node.kind())
5599 };
5600 fta
5601 }
5602
5603 fn as_ftp<'gc, 'n>(
5605 node: &'n hermes_ast::node::Node<'gc>,
5606 ) -> &'n hermes_ast::node::FunctionTypeParam<'gc> {
5607 let hermes_ast::node::Node::FunctionTypeParam(ftp) = node else {
5608 panic!("expected FunctionTypeParam, got {:?}", node.kind())
5609 };
5610 ftp
5611 }
5612
5613 #[test]
5616 fn flow_function_type_full_shape() {
5617 use hermes_ast::context::Context;
5618 use hermes_ast::node::Node;
5619 let mut sm = hermes_support::manager::SourceErrorManager::new();
5620 let mut ctx = Context::new();
5621 ctx.set_parse_flow(true);
5622 let gc = ctx.lock();
5623
5624 let ty = flow_alias_right(
5625 &gc,
5626 &mut sm,
5627 b"type A = <T>(this: X, a: B, c?: D, ...rest: E) => R;",
5628 );
5629 let fta = as_fta(ty);
5630
5631 let tp = fta.type_parameters.expect("has type params");
5633 let Node::TypeParameterDeclaration(tpd) = tp else {
5634 panic!("expected TypeParameterDeclaration, got {:?}", tp.kind())
5635 };
5636 assert_eq!(tpd.params.iter().count(), 1);
5637
5638 let this_param = as_ftp(fta.this.expect("has this constraint"));
5640 assert!(this_param.name.is_none(), "this constraint has no name");
5641 assert_generic_named(&gc, this_param.type_annotation, b"X");
5642
5643 let params: Vec<_> = fta.params.iter().collect();
5645 assert_eq!(params.len(), 2);
5646 let a = as_ftp(params[0]);
5647 assert_eq!(ident_bytes(&gc, a.name.expect("a named")), b"a");
5648 assert!(!a.optional.get());
5649 let c = as_ftp(params[1]);
5650 assert_eq!(ident_bytes(&gc, c.name.expect("c named")), b"c");
5651 assert!(c.optional.get());
5652
5653 let rest = as_ftp(fta.rest.expect("has rest"));
5655 assert_eq!(ident_bytes(&gc, rest.name.expect("rest named")), b"rest");
5656
5657 assert_generic_named(&gc, fta.return_type, b"R");
5659
5660 let ty = flow_alias_right(&gc, &mut sm, b"type C = (number) => string;");
5662 let fta = as_fta(ty);
5663 assert!(fta.this.is_none());
5664 assert!(fta.rest.is_none());
5665 assert!(fta.type_parameters.is_none());
5666 let params: Vec<_> = fta.params.iter().collect();
5667 assert_eq!(params.len(), 1);
5668 let p = as_ftp(params[0]);
5669 assert!(p.name.is_none(), "bare type param has no name");
5670 assert!(matches!(p.type_annotation, Node::NumberTypeAnnotation(_)));
5671 }
5672
5673 #[test]
5676 fn flow_group_vs_function_type() {
5677 use hermes_ast::context::Context;
5678 let mut sm = hermes_support::manager::SourceErrorManager::new();
5679 let mut ctx = Context::new();
5680 ctx.set_parse_flow(true);
5681 let gc = ctx.lock();
5682
5683 let ty = flow_alias_right(&gc, &mut sm, b"type A = (X);");
5685 assert_generic_named(&gc, ty, b"X");
5686 assert_eq!(ty.metadata().parens.get(), 1, "group bumps parens");
5687
5688 let ty = flow_alias_right(&gc, &mut sm, b"type B = (x: X) => R;");
5690 let fta = as_fta(ty);
5691 let params: Vec<_> = fta.params.iter().collect();
5692 assert_eq!(ident_bytes(&gc, as_ftp(params[0]).name.unwrap()), b"x");
5693
5694 let ty = flow_alias_right(&gc, &mut sm, b"type C = (X) => R;");
5696 let fta = as_fta(ty);
5697 assert!(as_ftp(fta.params.iter().next().unwrap()).name.is_none());
5698
5699 let ty = flow_alias_right(&gc, &mut sm, b"type D = () => R;");
5701 assert!(as_fta(ty).params.is_empty());
5702 }
5703
5704 #[test]
5706 fn flow_anon_function_type() {
5707 use hermes_ast::context::Context;
5708 let mut sm = hermes_support::manager::SourceErrorManager::new();
5709 let mut ctx = Context::new();
5710 ctx.set_parse_flow(true);
5711 let gc = ctx.lock();
5712
5713 let ty = flow_alias_right(&gc, &mut sm, b"type A = T => U => V;");
5714 let outer = as_fta(ty);
5715 let param = as_ftp(outer.params.iter().next().expect("one param"));
5716 assert!(param.name.is_none());
5717 assert_generic_named(&gc, param.type_annotation, b"T");
5718 let inner = as_fta(outer.return_type);
5719 assert_generic_named(&gc, inner.return_type, b"V");
5720 }
5721
5722 #[test]
5725 fn flow_object_type_properties() {
5726 use hermes_ast::context::Context;
5727 use hermes_ast::node::Node;
5728 let mut sm = hermes_support::manager::SourceErrorManager::new();
5729 let mut ctx = Context::new();
5730 ctx.set_parse_flow(true);
5731 let gc = ctx.lock();
5732
5733 let ty = flow_alias_right(
5734 &gc,
5735 &mut sm,
5736 b"type A = { x: B, y?: C, m(): D, get g(): E, set s(v: F): void, +ro: G };",
5737 );
5738 let Node::ObjectTypeAnnotation(obj) = ty else {
5739 panic!("expected ObjectTypeAnnotation, got {:?}", ty.kind())
5740 };
5741 assert!(!obj.exact.get());
5742 assert!(!obj.inexact.get());
5743 assert!(obj.indexers.is_empty());
5744 assert!(obj.call_properties.is_empty());
5745 assert!(obj.internal_slots.is_empty());
5746
5747 let props: Vec<_> = obj.properties.iter().collect();
5748 assert_eq!(props.len(), 6);
5749 let prop = |i: usize| -> &hermes_ast::node::ObjectTypeProperty<'_> {
5750 let Node::ObjectTypeProperty(p) = props[i] else {
5751 panic!("expected ObjectTypeProperty, got {:?}", props[i].kind())
5752 };
5753 p
5754 };
5755
5756 let x = prop(0);
5758 assert_eq!(ident_bytes(&gc, x.key), b"x");
5759 assert!(!x.method.get() && !x.optional.get());
5760 assert!(!x.r#static.get() && !x.proto.get());
5761 assert!(x.variance.is_none());
5762 assert_eq!(gc.ctx().atom_table.bytes(x.kind.get()), b"init");
5763
5764 let y = prop(1);
5766 assert!(y.optional.get());
5767
5768 let m = prop(2);
5770 assert!(m.method.get());
5771 assert_generic_named(&gc, as_fta(m.value).return_type, b"D");
5772 assert_eq!(gc.ctx().atom_table.bytes(m.kind.get()), b"init");
5773
5774 let g = prop(3);
5776 assert!(!g.method.get());
5777 assert_eq!(ident_bytes(&gc, g.key), b"g");
5778 assert_eq!(gc.ctx().atom_table.bytes(g.kind.get()), b"get");
5779
5780 let s = prop(4);
5782 assert_eq!(gc.ctx().atom_table.bytes(s.kind.get()), b"set");
5783 assert_eq!(as_fta(s.value).params.iter().count(), 1);
5784
5785 let ro = prop(5);
5787 let variance = ro.variance.expect("has variance");
5788 let Node::Variance(v) = variance else {
5789 panic!("expected Variance, got {:?}", variance.kind())
5790 };
5791 assert_eq!(gc.ctx().atom_table.bytes(v.kind.get()), b"plus");
5792 }
5793
5794 #[test]
5798 fn flow_object_type_member_families() {
5799 use hermes_ast::context::Context;
5800 use hermes_ast::node::Node;
5801 let mut sm = hermes_support::manager::SourceErrorManager::new();
5802 let mut ctx = Context::new();
5803 ctx.set_parse_flow(true);
5804 let gc = ctx.lock();
5805
5806 let obj_of = |sm: &mut hermes_support::manager::SourceErrorManager,
5807 src: &[u8]| {
5808 let ty = flow_alias_right(&gc, sm, src);
5809 let Node::ObjectTypeAnnotation(obj) = ty else {
5810 panic!("expected ObjectTypeAnnotation, got {:?}", ty.kind())
5811 };
5812 obj
5813 };
5814
5815 let obj = obj_of(&mut sm, b"type A = { [k: string]: V };");
5817 let idx = obj.indexers.iter().next().expect("one indexer");
5818 let Node::ObjectTypeIndexer(idx) = idx else {
5819 panic!("expected ObjectTypeIndexer, got {:?}", idx.kind())
5820 };
5821 assert_eq!(ident_bytes(&gc, idx.id.expect("has id")), b"k");
5822 assert!(matches!(idx.key, Node::StringTypeAnnotation(_)));
5823 assert!(!idx.r#static.get());
5824
5825 let obj = obj_of(&mut sm, b"type B = { [K]: V };");
5827 let idx = obj.indexers.iter().next().expect("one indexer");
5828 let Node::ObjectTypeIndexer(idx) = idx else {
5829 panic!("expected ObjectTypeIndexer, got {:?}", idx.kind())
5830 };
5831 assert!(idx.id.is_none());
5832 assert_generic_named(&gc, idx.key, b"K");
5833
5834 for (src, sigil) in [
5837 (b"type C = { [K in T]: V };".as_slice(), None),
5838 (b"type D = { [K in T]?: V };", Some(b"Optional".as_slice())),
5839 (b"type E = { [K in T]+?: V };", Some(b"PlusOptional")),
5840 (b"type F = { [K in T]-?: V };", Some(b"MinusOptional")),
5841 ] {
5842 let obj = obj_of(&mut sm, src);
5843 let prop = obj.properties.iter().next().expect("one property");
5844 let Node::ObjectTypeMappedTypeProperty(mapped) = prop else {
5845 panic!(
5846 "expected ObjectTypeMappedTypeProperty, got {:?}",
5847 prop.kind()
5848 )
5849 };
5850 let Node::TypeParameter(key_tparam) = mapped.key_tparam else {
5851 panic!("expected TypeParameter")
5852 };
5853 assert_eq!(
5854 gc.ctx().atom_table.bytes(key_tparam.name.get()),
5855 b"K"
5856 );
5857 assert_generic_named(&gc, mapped.source_type, b"T");
5858 assert_generic_named(&gc, mapped.prop_type, b"V");
5859 match sigil {
5860 None => assert_eq!(
5861 mapped.optional.get(),
5862 hermes_atom_table::INVALID_ATOM_BYTES,
5863 "no sigil dumps as null"
5864 ),
5865 Some(s) => assert_eq!(
5866 gc.ctx().atom_table.bytes(mapped.optional.get()),
5867 s
5868 ),
5869 }
5870 }
5871
5872 let obj = obj_of(&mut sm, b"type G = { +[K in T]: V };");
5874 let prop = obj.properties.iter().next().expect("one property");
5875 let Node::ObjectTypeMappedTypeProperty(mapped) = prop else {
5876 panic!("expected ObjectTypeMappedTypeProperty")
5877 };
5878 assert!(mapped.variance.is_some());
5879
5880 let obj =
5882 obj_of(&mut sm, b"type H = { (x: A): R, [[slot]]: T, ...S };");
5883 let call = obj.call_properties.iter().next().expect("one call");
5884 let Node::ObjectTypeCallProperty(call) = call else {
5885 panic!("expected ObjectTypeCallProperty, got {:?}", call.kind())
5886 };
5887 assert_eq!(as_fta(call.value).params.iter().count(), 1);
5888 let slot = obj.internal_slots.iter().next().expect("one slot");
5889 let Node::ObjectTypeInternalSlot(slot) = slot else {
5890 panic!("expected ObjectTypeInternalSlot, got {:?}", slot.kind())
5891 };
5892 assert_eq!(ident_bytes(&gc, slot.id), b"slot");
5893 assert!(!slot.method.get() && !slot.optional.get());
5894 let spread = obj.properties.iter().next().expect("one spread");
5895 let Node::ObjectTypeSpreadProperty(spread) = spread else {
5896 panic!("expected ObjectTypeSpreadProperty, got {:?}", spread.kind())
5897 };
5898 assert_generic_named(&gc, spread.argument, b"S");
5899
5900 let obj = obj_of(&mut sm, b"type I = { [[m]](): R };");
5902 let slot = obj.internal_slots.iter().next().expect("one slot");
5903 let Node::ObjectTypeInternalSlot(slot) = slot else {
5904 panic!("expected ObjectTypeInternalSlot")
5905 };
5906 assert!(slot.method.get());
5907
5908 let obj = obj_of(&mut sm, b"type J = {| a: T |};");
5910 assert!(obj.exact.get());
5911 let obj = obj_of(&mut sm, b"type K = { a: T, ... };");
5912 assert!(obj.inexact.get());
5913 let obj = obj_of(&mut sm, b"type L = { ... };");
5914 assert!(obj.inexact.get());
5915 assert!(obj.properties.is_empty());
5916 }
5917
5918 #[test]
5921 fn flow_object_type_modifier_name_fallbacks() {
5922 use hermes_ast::context::Context;
5923 use hermes_ast::node::Node;
5924 let mut sm = hermes_support::manager::SourceErrorManager::new();
5925 let mut ctx = Context::new();
5926 ctx.set_parse_flow(true);
5927 let gc = ctx.lock();
5928
5929 for (src, name, method) in [
5930 (b"type A = { static: T };".as_slice(), b"static".as_slice(), false),
5931 (b"type B = { proto: T };", b"proto", false),
5932 (b"type C = { static(): R };", b"static", true),
5933 (b"type D = { readonly: T };", b"readonly", false),
5934 ] {
5935 let ty = flow_alias_right(&gc, &mut sm, src);
5936 let Node::ObjectTypeAnnotation(obj) = ty else {
5937 panic!("expected ObjectTypeAnnotation, got {:?}", ty.kind())
5938 };
5939 let prop = obj.properties.iter().next().expect("one property");
5940 let Node::ObjectTypeProperty(prop) = prop else {
5941 panic!("expected ObjectTypeProperty, got {:?}", prop.kind())
5942 };
5943 assert_eq!(ident_bytes(&gc, prop.key), name);
5944 assert_eq!(prop.method.get(), method);
5945 assert!(!prop.r#static.get(), "the keyword was the name");
5946 assert!(!prop.proto.get(), "the keyword was the name");
5947 }
5948 }
5949
5950 #[test]
5954 fn flow_type_param_declarations() {
5955 use hermes_ast::context::Context;
5956 use hermes_ast::node::Node;
5957 let mut sm = hermes_support::manager::SourceErrorManager::new();
5958 let mut ctx = Context::new();
5959 ctx.set_parse_flow(true);
5960 let gc = ctx.lock();
5961
5962 let params_of = |sm: &mut hermes_support::manager::SourceErrorManager,
5963 src: &[u8]| {
5964 let stmt = parse_one_stmt(&gc, sm, src);
5965 let Node::TypeAlias(alias) = stmt else {
5966 panic!("expected TypeAlias, got {:?}", stmt.kind())
5967 };
5968 let tp = alias.type_parameters.expect("has type params");
5969 let Node::TypeParameterDeclaration(tpd) = tp else {
5970 panic!("expected TypeParameterDeclaration, got {:?}", tp.kind())
5971 };
5972 tpd.params.iter().collect::<Vec<_>>()
5973 };
5974 let tparam = |node: &'_ hermes_ast::node::Node<'_>| {
5975 let Node::TypeParameter(p) = node else {
5976 panic!("expected TypeParameter, got {:?}", node.kind())
5977 };
5978 let name = gc.ctx().atom_table.bytes(p.name.get()).to_vec();
5979 let variance = p.variance.map(|v| {
5980 let Node::Variance(v) = v else {
5981 panic!("expected Variance, got {:?}", v.kind())
5982 };
5983 gc.ctx().atom_table.bytes(v.kind.get()).to_vec()
5984 });
5985 (name, variance)
5986 };
5987
5988 let params = params_of(&mut sm, b"type A<T,> = T;");
5990 assert_eq!(params.len(), 1);
5991 assert_eq!(tparam(params[0]), (b"T".to_vec(), None));
5992
5993 let params = params_of(&mut sm, b"type B<const T> = T;");
5995 let Node::TypeParameter(p) = params[0] else { unreachable!() };
5996 assert!(p.r#const.get());
5997
5998 let params = params_of(&mut sm, b"type C<+T, -U> = [T, U];");
6000 assert_eq!(tparam(params[0]), (b"T".to_vec(), Some(b"plus".to_vec())));
6001 assert_eq!(tparam(params[1]), (b"U".to_vec(), Some(b"minus".to_vec())));
6002
6003 let params = params_of(&mut sm, b"type D<in T, out U> = [T, U];");
6005 assert_eq!(tparam(params[0]), (b"T".to_vec(), Some(b"in".to_vec())));
6006 assert_eq!(tparam(params[1]), (b"U".to_vec(), Some(b"out".to_vec())));
6007
6008 let params = params_of(&mut sm, b"type E<in> = X;");
6010 assert_eq!(tparam(params[0]), (b"in".to_vec(), None));
6011 let params = params_of(&mut sm, b"type F<out = X> = out;");
6012 assert_eq!(tparam(params[0]), (b"out".to_vec(), None));
6013 let Node::TypeParameter(p) = params[0] else { unreachable!() };
6014 assert!(p.default.is_some(), "`= X` is the default");
6015
6016 let params = params_of(&mut sm, b"type G<T: number> = T;");
6018 let Node::TypeParameter(p) = params[0] else { unreachable!() };
6019 let bound = p.bound.expect("has bound");
6020 let Node::TypeAnnotation(bound) = bound else {
6021 panic!("expected TypeAnnotation, got {:?}", bound.kind())
6022 };
6023 assert!(matches!(
6024 bound.type_annotation,
6025 Node::NumberTypeAnnotation(_)
6026 ));
6027 assert!(!p.uses_extends_bound.get());
6028
6029 let params = params_of(&mut sm, b"type H<T extends U> = T;");
6030 let Node::TypeParameter(p) = params[0] else { unreachable!() };
6031 assert!(p.bound.is_some());
6032 assert!(p.uses_extends_bound.get());
6033
6034 let params = params_of(&mut sm, b"type I<T = string> = T;");
6036 let Node::TypeParameter(p) = params[0] else { unreachable!() };
6037 assert!(matches!(
6038 p.default.expect("has default"),
6039 Node::StringTypeAnnotation(_)
6040 ));
6041 }
6042
6043 #[test]
6046 fn flow_type_predicates() {
6047 use hermes_ast::context::Context;
6048 use hermes_ast::node::Node;
6049 let mut sm = hermes_support::manager::SourceErrorManager::new();
6050 let mut ctx = Context::new();
6051 ctx.set_parse_flow(true);
6052 let gc = ctx.lock();
6053
6054 let predicate_of = |sm: &mut hermes_support::manager::SourceErrorManager,
6055 src: &[u8]| {
6056 let ty = flow_alias_right(&gc, sm, src);
6057 as_fta(ty).return_type
6058 };
6059
6060 let ret = predicate_of(&mut sm, b"type A = (x: mixed) => x is number;");
6063 let Node::TypePredicate(p) = ret else {
6064 panic!("expected TypePredicate, got {:?}", ret.kind())
6065 };
6066 assert_eq!(ident_bytes(&gc, p.parameter_name), b"x");
6067 assert!(matches!(
6068 p.type_annotation.expect("has type"),
6069 Node::NumberTypeAnnotation(_)
6070 ));
6071 assert_eq!(p.kind.get(), hermes_atom_table::INVALID_ATOM_BYTES);
6072
6073 let ret =
6075 predicate_of(&mut sm, b"type B = (x: mixed) => asserts x is T;");
6076 let Node::TypePredicate(p) = ret else {
6077 panic!("expected TypePredicate, got {:?}", ret.kind())
6078 };
6079 assert_eq!(gc.ctx().atom_table.bytes(p.kind.get()), b"asserts");
6080 assert!(p.type_annotation.is_some());
6081
6082 let ret = predicate_of(&mut sm, b"type C = (x: mixed) => asserts x;");
6083 let Node::TypePredicate(p) = ret else {
6084 panic!("expected TypePredicate, got {:?}", ret.kind())
6085 };
6086 assert!(p.type_annotation.is_none());
6087
6088 let ret = predicate_of(&mut sm, b"type D = (x: mixed) => asserts;");
6090 assert_generic_named(&gc, ret, b"asserts");
6091
6092 let ret =
6094 predicate_of(&mut sm, b"type E = (x: mixed) => implies x is T;");
6095 let Node::TypePredicate(p) = ret else {
6096 panic!("expected TypePredicate, got {:?}", ret.kind())
6097 };
6098 assert_eq!(gc.ctx().atom_table.bytes(p.kind.get()), b"implies");
6099 assert!(p.type_annotation.is_some());
6100 }
6101
6102 #[test]
6106 fn flow_checks_predicates() {
6107 use hermes_ast::context::Context;
6108 use hermes_ast::node::Node;
6109 use hermes_support::manager::SourceErrorManager;
6110
6111 let parse_predicate = |src: &[u8]| -> (&'static str, bool) {
6112 let mut sm = SourceErrorManager::new();
6113 let buf_id = sm.add_buffer_bytes("input", src);
6114 let mut ctx = Context::new();
6115 ctx.set_parse_flow(true);
6116 let gc = ctx.lock();
6117 let atoms = &gc.ctx().atom_table;
6118 let lexer = crate::lexer::JSLexer::new(
6119 buf_id,
6120 &mut sm,
6121 atoms,
6122 crate::lexer::GrammarContext::AllowRegExp,
6123 );
6124 let mut parser = JSParserImpl::new(&gc, lexer);
6125 parser.advance(crate::lexer::GrammarContext::Type);
6128 let pred =
6129 parser.parse_predicate_flow().expect("predicate parses");
6130 let kind = match pred {
6131 Node::DeclaredPredicate(d) => {
6132 assert!(
6133 matches!(d.value, Node::Identifier(_)),
6134 "the checks expression is parsed as a JS expression"
6135 );
6136 "declared"
6137 }
6138 Node::InferredPredicate(_) => "inferred",
6139 other => panic!("unexpected predicate {:?}", other.kind()),
6140 };
6141 (kind, parser.error_count_pub() == 0)
6142 };
6143
6144 assert_eq!(parse_predicate(b"x %checks(y)"), ("declared", true));
6145 assert_eq!(parse_predicate(b"x %checks"), ("inferred", true));
6146 }
6147
6148 #[test]
6150 fn flow_p52_errors() {
6151 use hermes_ast::context::Context;
6152 use hermes_support::diag::{CollectingHandler, DiagKind};
6153 use hermes_support::manager::SourceErrorManager;
6154
6155 let assert_error = |src: &[u8], expected: &str| {
6156 let mut sm = SourceErrorManager::new();
6157 let mut ctx = Context::new();
6158 ctx.set_parse_flow(true);
6159 let gc = ctx.lock();
6160 let atoms = &gc.ctx().atom_table;
6161 let _ = parse_with_collector(&gc, &mut sm, atoms, src);
6162 let h = sm.handler_as::<CollectingHandler>().unwrap();
6163 assert!(
6164 h.messages()
6165 .iter()
6166 .any(|m| m.kind == DiagKind::Error && m.message == expected),
6167 "expected {:?}, got {:?}",
6168 expected,
6169 h.messages().iter().map(|m| &m.message).collect::<Vec<_>>()
6170 );
6171 };
6172
6173 assert_error(
6174 b"type A = {| a: T, ... |};",
6175 "Explicit inexact syntax cannot appear inside an explicit exact object type",
6176 );
6177 assert_error(
6178 b"type A = { get x(a: B): T };",
6179 "Getter must have 0 parameters",
6180 );
6181 assert_error(
6182 b"type A = { set x(): void };",
6183 "Setter must have 1 parameter",
6184 );
6185 assert_error(
6186 b"type A = { get x(this: B): T };",
6187 "Accessors must not have 'this' annotations",
6188 );
6189 assert_error(
6190 b"type A = (this?: X) => Y;",
6191 "'this' constraint may not be optional",
6192 );
6193 assert_error(
6194 b"type A = (a: X, this: Y) => Z;",
6195 "'this' constraint must be the first parameter",
6196 );
6197 assert_error(
6198 b"type A = { +(): R };",
6199 "call property must not specify variance",
6200 );
6201 assert_error(
6202 b"type A = { +get x(): T };",
6203 "accessor property must not specify variance",
6204 );
6205 assert_error(b"type A = { proto x: T };", "invalid 'proto' modifier");
6206 assert_error(b"type A = { static x: T };", "invalid 'static' modifier");
6207 assert_error(b"type A = { +[[s]]: T };", "Unexpected variance sigil");
6208 assert_error(
6211 b"type A = (x) => implies<T> x is U;",
6212 "invalid return annotation. 'implies' type guard needs to be followed by identifier",
6213 );
6214 assert_error(
6215 b"type A = (x) => implies x;",
6216 "expecting 'is' after parameter of 'implies' type guard",
6217 );
6218 }
6219
6220 fn flow_parse_stmt_at<'gc>(
6227 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
6228 sm: &mut hermes_support::manager::SourceErrorManager,
6229 src: &[u8],
6230 idx: usize,
6231 ) -> &'gc hermes_ast::node::Node<'gc> {
6232 let buf_id = sm.add_buffer_bytes("input", src);
6233 let atoms = &gc.ctx().atom_table;
6234 let lexer = crate::lexer::JSLexer::new(
6235 buf_id,
6236 sm,
6237 atoms,
6238 crate::lexer::GrammarContext::AllowRegExp,
6239 );
6240 let mut parser = JSParserImpl::new(gc, lexer);
6241 let program = parser.parse().expect("parse succeeded");
6242 assert_eq!(parser.error_count_pub(), 0, "zero errors");
6243 if let hermes_ast::node::Node::Program(p) = program {
6244 return p.body.iter().nth(idx).expect("has enough statements");
6245 }
6246 panic!("expected Program");
6247 }
6248
6249 #[test]
6252 fn flow_opaque_type_shapes() {
6253 use hermes_ast::context::Context;
6254 use hermes_ast::node::Node;
6255 use hermes_support::manager::SourceErrorManager;
6256
6257 let check = |src: &[u8],
6259 has_tp: bool,
6260 has_lower: bool,
6261 has_upper: bool,
6262 has_super: bool| {
6263 let mut sm = SourceErrorManager::new();
6264 let mut ctx = Context::new();
6265 ctx.set_parse_flow(true);
6266 let gc = ctx.lock();
6267 let stmt = parse_one_stmt(&gc, &mut sm, src);
6268 let Node::OpaqueType(o) = stmt else {
6269 panic!("expected OpaqueType, got {:?}", stmt.kind())
6270 };
6271 assert_eq!(o.type_parameters.is_some(), has_tp, "{src:?} tp");
6272 assert_eq!(o.lower_bound.is_some(), has_lower, "{src:?} lower");
6273 assert_eq!(o.upper_bound.is_some(), has_upper, "{src:?} upper");
6274 assert_eq!(o.supertype.is_some(), has_super, "{src:?} super");
6275 };
6276
6277 check(b"opaque type A = number;", false, false, false, false);
6278 check(b"opaque type B<T> = T;", true, false, false, false);
6279 check(b"opaque type C: number = 1;", false, false, false, true);
6280 check(b"opaque type D super X = Y;", false, true, false, false);
6281 check(b"opaque type E extends F = G;", false, false, true, false);
6282 check(
6283 b"opaque type H super X extends F = G;",
6284 false,
6285 true,
6286 true,
6287 false,
6288 );
6289
6290 let mut sm = SourceErrorManager::new();
6292 let mut ctx = Context::new();
6293 ctx.set_parse_flow(true);
6294 let gc = ctx.lock();
6295 let stmt = parse_one_stmt(&gc, &mut sm, b"opaque type C: number = 1;");
6296 let Node::OpaqueType(o) = stmt else {
6297 panic!("expected OpaqueType, got {:?}", stmt.kind())
6298 };
6299 assert_eq!(ident_bytes(&gc, o.id), b"C");
6300 assert!(
6301 matches!(o.supertype, Some(Node::NumberTypeAnnotation(_))),
6302 "supertype is NumberTypeAnnotation"
6303 );
6304 assert!(
6305 matches!(o.impltype, Node::NumberLiteralTypeAnnotation(_)),
6306 "impltype is NumberLiteralTypeAnnotation, got {:?}",
6307 o.impltype.kind()
6308 );
6309 }
6310
6311 #[test]
6314 fn flow_interface_declaration() {
6315 use hermes_ast::context::Context;
6316 use hermes_ast::node::Node;
6317 use hermes_support::manager::SourceErrorManager;
6318
6319 let mut sm = SourceErrorManager::new();
6320 let mut ctx = Context::new();
6321 ctx.set_parse_flow(true);
6322 let gc = ctx.lock();
6323
6324 let stmt = parse_one_stmt(&gc, &mut sm, b"interface I { x: number }");
6326 let Node::InterfaceDeclaration(decl) = stmt else {
6327 panic!("expected InterfaceDeclaration, got {:?}", stmt.kind())
6328 };
6329 assert_eq!(ident_bytes(&gc, decl.id), b"I");
6330 assert!(decl.type_parameters.is_none(), "no type params");
6331 assert!(decl.extends.is_empty(), "no extends");
6332 let Node::ObjectTypeAnnotation(body) = decl.body else {
6333 panic!("expected ObjectTypeAnnotation body")
6334 };
6335 assert_eq!(body.properties.iter().count(), 1, "one property");
6336
6337 let stmt = parse_one_stmt(
6340 &gc,
6341 &mut sm,
6342 b"interface J<T> extends K, L<T> { m(): void }",
6343 );
6344 let Node::InterfaceDeclaration(decl) = stmt else {
6345 panic!("expected InterfaceDeclaration, got {:?}", stmt.kind())
6346 };
6347 assert_eq!(ident_bytes(&gc, decl.id), b"J");
6348 assert!(decl.type_parameters.is_some(), "has type params");
6349 let extends: Vec<_> = decl.extends.iter().collect();
6350 assert_eq!(extends.len(), 2, "two extends entries");
6351 let Node::InterfaceExtends(e0) = extends[0] else {
6352 panic!("expected InterfaceExtends, got {:?}", extends[0].kind())
6353 };
6354 assert_eq!(ident_bytes(&gc, e0.id), b"K");
6355 assert!(e0.type_parameters.is_none(), "K has no type args");
6356 let Node::InterfaceExtends(e1) = extends[1] else {
6357 panic!("expected InterfaceExtends, got {:?}", extends[1].kind())
6358 };
6359 assert_eq!(ident_bytes(&gc, e1.id), b"L");
6360 assert!(e1.type_parameters.is_some(), "L<T> keeps its type args");
6361
6362 let stmt = parse_one_stmt(&gc, &mut sm, b"interface E {}");
6364 let Node::InterfaceDeclaration(decl) = stmt else {
6365 panic!("expected InterfaceDeclaration, got {:?}", stmt.kind())
6366 };
6367 let Node::ObjectTypeAnnotation(body) = decl.body else {
6368 panic!("expected ObjectTypeAnnotation body")
6369 };
6370 assert!(body.properties.is_empty(), "empty body");
6371 }
6372
6373 #[test]
6378 fn flow_interface_type_annotation() {
6379 use hermes_ast::context::Context;
6380 use hermes_ast::node::Node;
6381 use hermes_support::manager::SourceErrorManager;
6382
6383 let mut sm = SourceErrorManager::new();
6384 let mut ctx = Context::new();
6385 ctx.set_parse_flow(true);
6386 let gc = ctx.lock();
6387
6388 let right =
6390 flow_alias_right(&gc, &mut sm, b"type A = interface { x: number };");
6391 let Node::InterfaceTypeAnnotation(ita) = right else {
6392 panic!("expected InterfaceTypeAnnotation, got {:?}", right.kind())
6393 };
6394 assert!(ita.extends.is_empty(), "no extends");
6395 assert!(
6396 matches!(ita.body, Some(Node::ObjectTypeAnnotation(_))),
6397 "body is ObjectTypeAnnotation"
6398 );
6399
6400 let right = flow_alias_right(
6402 &gc,
6403 &mut sm,
6404 b"type B = interface extends I { y: T };",
6405 );
6406 let Node::InterfaceTypeAnnotation(ita) = right else {
6407 panic!("expected InterfaceTypeAnnotation, got {:?}", right.kind())
6408 };
6409 let extends: Vec<_> = ita.extends.iter().collect();
6410 assert_eq!(extends.len(), 1, "one extends entry");
6411 assert!(matches!(extends[0], Node::InterfaceExtends(_)));
6412
6413 let stmt = flow_parse_stmt_at(
6415 &gc,
6416 &mut sm,
6417 b"'use strict'; type C = interface { x: number };",
6418 1,
6419 );
6420 let Node::TypeAlias(alias) = stmt else {
6421 panic!("expected TypeAlias, got {:?}", stmt.kind())
6422 };
6423 assert!(
6424 matches!(alias.right, Node::InterfaceTypeAnnotation(_)),
6425 "rw_interface arm builds InterfaceTypeAnnotation, got {:?}",
6426 alias.right.kind()
6427 );
6428
6429 let stmt = flow_parse_stmt_at(
6431 &gc,
6432 &mut sm,
6433 b"'use strict'; interface S { x: number }",
6434 1,
6435 );
6436 assert!(
6437 matches!(stmt, Node::InterfaceDeclaration(_)),
6438 "rw_interface declaration parses, got {:?}",
6439 stmt.kind()
6440 );
6441 }
6442
6443 #[test]
6446 fn flow_class_implements() {
6447 use hermes_ast::context::Context;
6448 use hermes_ast::node::Node;
6449 use hermes_support::manager::SourceErrorManager;
6450
6451 let parse_impl = |src: &[u8], expect_args: bool| {
6452 let mut sm = SourceErrorManager::new();
6453 let buf_id = sm.add_buffer_bytes("input", src);
6454 let mut ctx = Context::new();
6455 ctx.set_parse_flow(true);
6456 let gc = ctx.lock();
6457 let atoms = &gc.ctx().atom_table;
6458 let lexer = crate::lexer::JSLexer::new(
6459 buf_id,
6460 &mut sm,
6461 atoms,
6462 crate::lexer::GrammarContext::AllowRegExp,
6463 );
6464 let mut parser = JSParserImpl::new(&gc, lexer);
6465 let node = parser
6466 .parse_class_implements_flow()
6467 .expect("class implements parses");
6468 let Node::ClassImplements(ci) = node else {
6469 panic!("expected ClassImplements, got {:?}", node.kind())
6470 };
6471 assert_eq!(ident_bytes(&gc, ci.id), b"I");
6472 assert_eq!(
6473 ci.type_parameters.is_some(),
6474 expect_args,
6475 "{src:?} type args"
6476 );
6477 assert_eq!(parser.error_count_pub(), 0, "zero errors");
6478 };
6479
6480 parse_impl(b"I", false);
6481 parse_impl(b"I<T>", true);
6482 }
6483
6484 #[test]
6486 fn flow_p53_errors() {
6487 use hermes_ast::context::Context;
6488 use hermes_support::diag::{CollectingHandler, DiagKind};
6489 use hermes_support::manager::SourceErrorManager;
6490
6491 let assert_error = |src: &[u8], expected: &str| {
6492 let mut sm = SourceErrorManager::new();
6493 let mut ctx = Context::new();
6494 ctx.set_parse_flow(true);
6495 let gc = ctx.lock();
6496 let atoms = &gc.ctx().atom_table;
6497 let _ = parse_with_collector(&gc, &mut sm, atoms, src);
6498 let h = sm.handler_as::<CollectingHandler>().unwrap();
6499 assert!(
6500 h.messages()
6501 .iter()
6502 .any(|m| m.kind == DiagKind::Error && m.message == expected),
6503 "expected {:?}, got {:?}",
6504 expected,
6505 h.messages().iter().map(|m| &m.message).collect::<Vec<_>>()
6506 );
6507 };
6508
6509 assert_error(
6512 b"interface I { ...T }",
6513 "Spreading a type is only allowed inside an object type",
6514 );
6515 assert_error(b"opaque type X;", "'=' expected in type alias");
6517 assert_error(
6519 b"opaque interface I {}",
6520 "invalid token in opaque type declaration",
6521 );
6522 }
6523
6524 #[test]
6530 fn flow_function_signature() {
6531 use hermes_ast::context::Context;
6532 use hermes_ast::node::Node;
6533 use hermes_support::manager::SourceErrorManager;
6534
6535 let mut sm = SourceErrorManager::new();
6536 let mut ctx = Context::new();
6537 ctx.set_parse_flow(true);
6538 let gc = ctx.lock();
6539 let stmt = parse_one_stmt(
6540 &gc,
6541 &mut sm,
6542 b"function f<T>(x: T): T { return x; }",
6543 );
6544 let Node::FunctionDeclaration(f) = stmt else {
6545 panic!("expected FunctionDeclaration, got {:?}", stmt.kind())
6546 };
6547 assert!(f.type_parameters.is_some(), "type params");
6548 assert!(f.return_type.is_some(), "return type");
6549 assert!(f.predicate.is_none(), "no predicate");
6550 let param = f.params.iter().next().expect("one param");
6551 let Node::Identifier(p) = param else {
6552 panic!("expected Identifier param, got {:?}", param.kind())
6553 };
6554 assert!(p.type_annotation.is_some(), "param annotation");
6555 assert!(!p.optional.get(), "param not optional");
6556 }
6557
6558 #[test]
6561 fn flow_function_predicates() {
6562 use hermes_ast::context::Context;
6563 use hermes_ast::node::Node;
6564 use hermes_support::manager::SourceErrorManager;
6565
6566 {
6568 let mut sm = SourceErrorManager::new();
6569 let mut ctx = Context::new();
6570 ctx.set_parse_flow(true);
6571 let gc = ctx.lock();
6572 let stmt = parse_one_stmt(
6573 &gc,
6574 &mut sm,
6575 b"function p(x: mixed): boolean %checks { return !!x; }",
6576 );
6577 let Node::FunctionDeclaration(f) = stmt else {
6578 panic!("expected FunctionDeclaration, got {:?}", stmt.kind())
6579 };
6580 assert!(f.return_type.is_some(), "return type");
6581 assert!(
6582 matches!(f.predicate, Some(Node::InferredPredicate(_))),
6583 "inferred predicate"
6584 );
6585 }
6586
6587 {
6589 let mut sm = SourceErrorManager::new();
6590 let mut ctx = Context::new();
6591 ctx.set_parse_flow(true);
6592 let gc = ctx.lock();
6593 let stmt = parse_one_stmt(
6594 &gc,
6595 &mut sm,
6596 b"function q(x: mixed): %checks (x === 1) {}",
6597 );
6598 let Node::FunctionDeclaration(f) = stmt else {
6599 panic!("expected FunctionDeclaration, got {:?}", stmt.kind())
6600 };
6601 assert!(f.return_type.is_none(), "no return type");
6602 assert!(
6603 matches!(f.predicate, Some(Node::DeclaredPredicate(_))),
6604 "declared predicate"
6605 );
6606 }
6607 }
6608
6609 #[test]
6612 fn flow_this_param() {
6613 use hermes_ast::context::Context;
6614 use hermes_ast::node::Node;
6615 use hermes_support::manager::SourceErrorManager;
6616
6617 let mut sm = SourceErrorManager::new();
6618 let mut ctx = Context::new();
6619 ctx.set_parse_flow(true);
6620 let gc = ctx.lock();
6621 let stmt = parse_one_stmt(
6622 &gc,
6623 &mut sm,
6624 b"function g(this: Object, a: number): void {}",
6625 );
6626 let Node::FunctionDeclaration(f) = stmt else {
6627 panic!("expected FunctionDeclaration, got {:?}", stmt.kind())
6628 };
6629 let params: Vec<_> = f.params.iter().collect();
6630 assert_eq!(params.len(), 2, "two params");
6631 let Node::Identifier(this_param) = params[0] else {
6632 panic!("expected Identifier, got {:?}", params[0].kind())
6633 };
6634 assert_eq!(
6635 gc.ctx().atom_table.bytes(this_param.name.get()),
6636 b"this",
6637 "first param is 'this'"
6638 );
6639 assert!(this_param.type_annotation.is_some(), "'this' annotation");
6640 assert!(!this_param.optional.get());
6641 let Node::Identifier(a_param) = params[1] else {
6642 panic!("expected Identifier, got {:?}", params[1].kind())
6643 };
6644 assert_eq!(gc.ctx().atom_table.bytes(a_param.name.get()), b"a");
6645 }
6646
6647 #[test]
6650 fn flow_binding_annotations() {
6651 use hermes_ast::context::Context;
6652 use hermes_ast::node::Node;
6653 use hermes_support::manager::SourceErrorManager;
6654
6655 fn decl_id<'gc>(
6657 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
6658 src: &[u8],
6659 ) -> &'gc Node<'gc> {
6660 let mut sm = SourceErrorManager::new();
6661 let stmt = parse_one_stmt(gc, &mut sm, src);
6662 let Node::VariableDeclaration(d) = stmt else {
6663 panic!("expected VariableDeclaration, got {:?}", stmt.kind())
6664 };
6665 let Node::VariableDeclarator(declarator) =
6666 d.declarations.iter().next().expect("one declarator")
6667 else {
6668 panic!("expected VariableDeclarator")
6669 };
6670 declarator.id
6671 }
6672
6673 let mut ctx = Context::new();
6674 ctx.set_parse_flow(true);
6675 let gc = ctx.lock();
6676
6677 let id = decl_id(&gc, b"var a?: number;");
6679 let Node::Identifier(id) = id else {
6680 panic!("expected Identifier, got {:?}", id.kind())
6681 };
6682 assert!(id.optional.get(), "optional");
6683 assert!(id.type_annotation.is_some(), "id annotation");
6684
6685 let pat = decl_id(&gc, b"var [x, y]: T = c;");
6687 let Node::ArrayPattern(pat) = pat else {
6688 panic!("expected ArrayPattern, got {:?}", pat.kind())
6689 };
6690 assert!(pat.type_annotation.is_some(), "array pattern annotation");
6691
6692 let pat = decl_id(&gc, b"var {x}: T = c;");
6694 let Node::ObjectPattern(pat) = pat else {
6695 panic!("expected ObjectPattern, got {:?}", pat.kind())
6696 };
6697 assert!(pat.type_annotation.is_some(), "object pattern annotation");
6698
6699 let mut sm = SourceErrorManager::new();
6701 let stmt = parse_one_stmt(&gc, &mut sm, b"function fd(a?: T) {}");
6702 let Node::FunctionDeclaration(f) = stmt else {
6703 panic!("expected FunctionDeclaration, got {:?}", stmt.kind())
6704 };
6705 let param = f.params.iter().next().expect("one param");
6706 let Node::Identifier(p) = param else {
6707 panic!("expected Identifier param, got {:?}", param.kind())
6708 };
6709 assert!(p.optional.get(), "optional param");
6710 assert!(p.type_annotation.is_some(), "optional param annotation");
6711 }
6712
6713 #[test]
6717 fn flow_class_integration() {
6718 use hermes_ast::context::Context;
6719 use hermes_ast::node::Node;
6720 use hermes_support::manager::SourceErrorManager;
6721
6722 let mut sm = SourceErrorManager::new();
6723 let mut ctx = Context::new();
6724 ctx.set_parse_flow(true);
6725 let gc = ctx.lock();
6726 let stmt = parse_one_stmt(
6727 &gc,
6728 &mut sm,
6729 b"class C<T> extends B<T> implements I, J<T> {\n\
6730 \x20 x: number;\n\
6731 \x20 +ro: T;\n\
6732 \x20 readonly r: V;\n\
6733 \x20 #p: T;\n\
6734 \x20 static: number;\n\
6735 \x20 m<U>(a: U): U { return a; }\n\
6736 \x20 get g(): T { return this.x; }\n\
6737 }",
6738 );
6739 let Node::ClassDeclaration(c) = stmt else {
6740 panic!("expected ClassDeclaration, got {:?}", stmt.kind())
6741 };
6742 assert!(c.type_parameters.is_some(), "class type params");
6743 assert!(c.super_class.is_some(), "super class");
6744 assert!(c.super_type_arguments.is_some(), "super type args");
6745
6746 let impls: Vec<_> = c.implements.iter().collect();
6748 assert_eq!(impls.len(), 2, "two implements entries");
6749 let Node::ClassImplements(i0) = impls[0] else {
6750 panic!("expected ClassImplements, got {:?}", impls[0].kind())
6751 };
6752 assert!(i0.type_parameters.is_none(), "I has no type args");
6753 let Node::ClassImplements(i1) = impls[1] else {
6754 panic!("expected ClassImplements, got {:?}", impls[1].kind())
6755 };
6756 assert!(i1.type_parameters.is_some(), "J<T> has type args");
6757
6758 let Node::ClassBody(body) = c.body else {
6759 panic!("expected ClassBody")
6760 };
6761 let elems: Vec<_> = body.body.iter().collect();
6762 assert_eq!(elems.len(), 7, "seven class elements");
6763
6764 let Node::ClassProperty(x) = elems[0] else {
6766 panic!("expected ClassProperty, got {:?}", elems[0].kind())
6767 };
6768 assert!(x.type_annotation.is_some(), "x annotation");
6769 assert!(x.variance.is_none(), "x has no variance");
6770
6771 let Node::ClassProperty(ro) = elems[1] else {
6773 panic!("expected ClassProperty, got {:?}", elems[1].kind())
6774 };
6775 let Some(Node::Variance(v)) = ro.variance else {
6776 panic!("expected Variance on +ro")
6777 };
6778 assert_eq!(gc.ctx().atom_table.bytes(v.kind.get()), b"plus");
6779
6780 let Node::ClassProperty(r) = elems[2] else {
6782 panic!("expected ClassProperty, got {:?}", elems[2].kind())
6783 };
6784 let Some(Node::Variance(v)) = r.variance else {
6785 panic!("expected Variance on readonly r")
6786 };
6787 assert_eq!(gc.ctx().atom_table.bytes(v.kind.get()), b"readonly");
6788
6789 let Node::ClassPrivateProperty(p) = elems[3] else {
6791 panic!("expected ClassPrivateProperty, got {:?}", elems[3].kind())
6792 };
6793 assert!(p.type_annotation.is_some(), "#p annotation");
6794
6795 let Node::ClassProperty(s) = elems[4] else {
6797 panic!("expected ClassProperty, got {:?}", elems[4].kind())
6798 };
6799 let Node::Identifier(s_key) = s.key else {
6800 panic!("expected Identifier key")
6801 };
6802 assert_eq!(gc.ctx().atom_table.bytes(s_key.name.get()), b"static");
6803 assert!(!s.r#static.get(), "'static' is the name, not a modifier");
6804 assert!(s.type_annotation.is_some(), "static-field annotation");
6805
6806 let Node::MethodDefinition(m) = elems[5] else {
6808 panic!("expected MethodDefinition, got {:?}", elems[5].kind())
6809 };
6810 let Node::FunctionExpression(mf) = m.value else {
6811 panic!("expected FunctionExpression")
6812 };
6813 assert!(mf.type_parameters.is_some(), "method type params");
6814 assert!(mf.return_type.is_some(), "method return type");
6815
6816 let Node::MethodDefinition(getter) = elems[6] else {
6818 panic!("expected MethodDefinition, got {:?}", elems[6].kind())
6819 };
6820 assert_eq!(gc.ctx().atom_table.bytes(getter.kind.get()), b"get");
6821 let Node::FunctionExpression(gf) = getter.value else {
6822 panic!("expected FunctionExpression")
6823 };
6824 assert!(gf.return_type.is_some(), "getter return type");
6825 }
6826
6827 #[test]
6830 fn flow_class_expression_heritage() {
6831 use hermes_ast::context::Context;
6832 use hermes_ast::node::Node;
6833 use hermes_support::manager::SourceErrorManager;
6834
6835 let mut sm = SourceErrorManager::new();
6836 let mut ctx = Context::new();
6837 ctx.set_parse_flow(true);
6838 let gc = ctx.lock();
6839 let atoms = &gc.ctx().atom_table;
6840 let expr = parse_expr_from(
6841 &gc,
6842 &mut sm,
6843 atoms,
6844 b"(class <T> implements K { y: T; });",
6845 );
6846 let Node::ClassExpression(c) = expr else {
6847 panic!("expected ClassExpression, got {:?}", expr.kind())
6848 };
6849 assert!(c.id.is_none(), "anonymous");
6850 assert!(c.type_parameters.is_some(), "type params");
6851 assert_eq!(c.implements.iter().count(), 1, "one implements entry");
6852 }
6853
6854 #[test]
6857 fn flow_object_literal_methods() {
6858 use hermes_ast::context::Context;
6859 use hermes_ast::node::Node;
6860 use hermes_support::manager::SourceErrorManager;
6861
6862 let mut sm = SourceErrorManager::new();
6863 let mut ctx = Context::new();
6864 ctx.set_parse_flow(true);
6865 let gc = ctx.lock();
6866 let atoms = &gc.ctx().atom_table;
6867 let expr = parse_expr_from(
6868 &gc,
6869 &mut sm,
6870 atoms,
6871 b"({ m<T>(x: T): T { return x; },\n\
6872 \x20 get x(): number { return 1; },\n\
6873 \x20 set y(v: number): void {},\n\
6874 \x20 get<T>(x) { return x; } });",
6875 );
6876 let Node::ObjectExpression(obj) = expr else {
6877 panic!("expected ObjectExpression, got {:?}", expr.kind())
6878 };
6879 let props: Vec<_> = obj.properties.iter().collect();
6880 assert_eq!(props.len(), 4, "four properties");
6881
6882 let Node::Property(m) = props[0] else {
6884 panic!("expected Property")
6885 };
6886 assert!(m.method.get(), "m is a method");
6887 let Node::FunctionExpression(mf) = m.value else {
6888 panic!("expected FunctionExpression")
6889 };
6890 assert!(mf.type_parameters.is_some(), "method type params");
6891 assert!(mf.return_type.is_some(), "method return type");
6892
6893 let Node::Property(g) = props[1] else {
6895 panic!("expected Property")
6896 };
6897 assert_eq!(gc.ctx().atom_table.bytes(g.kind.get()), b"get");
6898 let Node::FunctionExpression(gf) = g.value else {
6899 panic!("expected FunctionExpression")
6900 };
6901 assert!(gf.return_type.is_some(), "getter return type");
6902
6903 let Node::Property(s) = props[2] else {
6905 panic!("expected Property")
6906 };
6907 assert_eq!(gc.ctx().atom_table.bytes(s.kind.get()), b"set");
6908 let Node::FunctionExpression(sf) = s.value else {
6909 panic!("expected FunctionExpression")
6910 };
6911 assert!(sf.return_type.is_some(), "setter return type");
6912
6913 let Node::Property(gm) = props[3] else {
6915 panic!("expected Property")
6916 };
6917 assert!(gm.method.get(), "get<T> is a method");
6918 let Node::Identifier(gm_key) = gm.key else {
6919 panic!("expected Identifier key")
6920 };
6921 assert_eq!(gc.ctx().atom_table.bytes(gm_key.name.get()), b"get");
6922 let Node::FunctionExpression(gmf) = gm.value else {
6923 panic!("expected FunctionExpression")
6924 };
6925 assert!(gmf.type_parameters.is_some(), "get<T> type params");
6926 }
6927
6928 #[test]
6930 fn flow_p54_errors() {
6931 use hermes_ast::context::Context;
6932 use hermes_support::diag::{CollectingHandler, DiagKind};
6933 use hermes_support::manager::SourceErrorManager;
6934
6935 let assert_error = |src: &[u8], expected: &str| {
6936 let mut sm = SourceErrorManager::new();
6937 let mut ctx = Context::new();
6938 ctx.set_parse_flow(true);
6939 let gc = ctx.lock();
6940 let atoms = &gc.ctx().atom_table;
6941 let _ = parse_with_collector(&gc, &mut sm, atoms, src);
6942 let h = sm.handler_as::<CollectingHandler>().unwrap();
6943 assert!(
6944 h.messages()
6945 .iter()
6946 .any(|m| m.kind == DiagKind::Error && m.message == expected),
6947 "expected {:?}, got {:?}",
6948 expected,
6949 h.messages().iter().map(|m| &m.message).collect::<Vec<_>>()
6950 );
6951 };
6952
6953 assert_error(
6955 b"class C { get x<T>() { return 1; } }",
6956 "accessor method may not have type parameters",
6957 );
6958 assert_error(b"class C { +m() {} }", "Unexpected variance sigil");
6960 }
6961
6962 fn comp_parse_stmt_at<'gc>(
6970 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
6971 sm: &mut hermes_support::manager::SourceErrorManager,
6972 src: &[u8],
6973 idx: usize,
6974 ) -> &'gc hermes_ast::node::Node<'gc> {
6975 let buf_id = sm.add_buffer_bytes("input", src);
6976 let atoms = &gc.ctx().atom_table;
6977 let lexer = crate::lexer::JSLexer::new(
6978 buf_id,
6979 sm,
6980 atoms,
6981 crate::lexer::GrammarContext::AllowRegExp,
6982 );
6983 let mut parser = JSParserImpl::new(gc, lexer);
6984 let program = parser.parse().expect("parse succeeded");
6985 assert_eq!(parser.error_count_pub(), 0, "zero errors for {src:?}");
6986 if let hermes_ast::node::Node::Program(p) = program {
6987 return p.body.iter().nth(idx).expect("has enough statements");
6988 }
6989 panic!("expected Program");
6990 }
6991
6992 fn comp_ctx() -> hermes_ast::context::Context<'static> {
6994 let mut ctx = hermes_ast::context::Context::new();
6995 ctx.set_parse_flow(true);
6996 ctx.set_parse_flow_component_syntax(true);
6997 ctx
6998 }
6999
7000 #[test]
7002 fn flow_component_basic() {
7003 use hermes_ast::node::Node;
7004 let mut sm = hermes_support::manager::SourceErrorManager::new();
7005 let mut ctx = comp_ctx();
7006 let gc = ctx.lock();
7007 let stmt = comp_parse_stmt_at(&gc, &mut sm, b"component Foo() {}", 0);
7008 let Node::ComponentDeclaration(c) = stmt else {
7009 panic!("expected ComponentDeclaration, got {:?}", stmt.kind())
7010 };
7011 assert_eq!(ident_bytes(&gc, c.id), b"Foo");
7012 assert_eq!(c.params.iter().count(), 0);
7013 assert!(c.type_parameters.is_none());
7014 assert!(c.renders_type.is_none());
7015 assert!(!c.r#async.get());
7016 }
7017
7018 #[test]
7022 fn flow_component_parameters() {
7023 use hermes_ast::node::Node;
7024 let mut sm = hermes_support::manager::SourceErrorManager::new();
7025 let mut ctx = comp_ctx();
7026 let gc = ctx.lock();
7027 let stmt = comp_parse_stmt_at(
7028 &gc,
7029 &mut sm,
7030 b"component Foo(\"data-id\" as id, name?: string, x: number = 5, ...rest: Props) {}",
7031 0,
7032 );
7033 let Node::ComponentDeclaration(c) = stmt else {
7034 panic!("expected ComponentDeclaration, got {:?}", stmt.kind())
7035 };
7036 let params: Vec<_> = c.params.iter().collect();
7037 assert_eq!(params.len(), 4);
7038
7039 let Node::ComponentParameter(p0) = params[0] else {
7041 panic!("expected ComponentParameter, got {:?}", params[0].kind())
7042 };
7043 assert!(matches!(p0.name, Node::StringLiteral(_)));
7044 assert!(!p0.shorthand.get());
7045
7046 let Node::ComponentParameter(p1) = params[1] else {
7048 panic!("expected ComponentParameter, got {:?}", params[1].kind())
7049 };
7050 assert!(p1.shorthand.get());
7051 let Node::Identifier(local1) = p1.local else {
7052 panic!("expected Identifier local, got {:?}", p1.local.kind())
7053 };
7054 assert!(local1.optional.get());
7055 assert!(local1.type_annotation.is_some());
7056
7057 let Node::ComponentParameter(p2) = params[2] else {
7059 panic!("expected ComponentParameter, got {:?}", params[2].kind())
7060 };
7061 assert!(p2.shorthand.get());
7062 assert!(matches!(p2.local, Node::AssignmentPattern(_)));
7063
7064 assert!(matches!(params[3], Node::RestElement(_)));
7067 }
7068
7069 #[test]
7072 fn flow_component_renders_operators() {
7073 use hermes_ast::node::Node;
7074 let check = |src: &[u8], op: &[u8]| {
7075 let mut sm = hermes_support::manager::SourceErrorManager::new();
7076 let mut ctx = comp_ctx();
7077 let gc = ctx.lock();
7078 let stmt = comp_parse_stmt_at(&gc, &mut sm, src, 0);
7079 let Node::ComponentDeclaration(c) = stmt else {
7080 panic!("expected ComponentDeclaration, got {:?}", stmt.kind())
7081 };
7082 let renders = c.renders_type.expect("has renders type");
7083 let Node::TypeOperator(t) = renders else {
7084 panic!("expected TypeOperator, got {:?}", renders.kind())
7085 };
7086 assert_eq!(gc.ctx().atom_table.bytes(t.operator.get()), op);
7087 };
7088 check(b"component A() renders React.Node {}", b"renders");
7089 check(b"component B() renders? Bar {}", b"renders?");
7090 check(b"component C() renders* Baz {}", b"renders*");
7091 }
7092
7093 #[test]
7095 fn flow_component_async_and_generic_hook() {
7096 use hermes_ast::node::Node;
7097 let mut sm = hermes_support::manager::SourceErrorManager::new();
7098 let mut ctx = comp_ctx();
7099 let gc = ctx.lock();
7100 let stmt0 = comp_parse_stmt_at(
7101 &gc,
7102 &mut sm,
7103 b"async component App() renders null { return null; }\nhook useZ<T>(x: T): T { return x; }",
7104 0,
7105 );
7106 let Node::ComponentDeclaration(c) = stmt0 else {
7107 panic!("expected ComponentDeclaration, got {:?}", stmt0.kind())
7108 };
7109 assert!(c.r#async.get());
7110 assert!(c.renders_type.is_some());
7111
7112 let stmt1 = comp_parse_stmt_at(
7113 &gc,
7114 &mut sm,
7115 b"async component App() renders null { return null; }\nhook useZ<T>(x: T): T { return x; }",
7116 1,
7117 );
7118 let Node::HookDeclaration(h) = stmt1 else {
7119 panic!("expected HookDeclaration, got {:?}", stmt1.kind())
7120 };
7121 assert_eq!(ident_bytes(&gc, h.id), b"useZ");
7122 assert!(h.type_parameters.is_some());
7123 assert!(h.return_type.is_some());
7124 assert!(!h.r#async.get());
7125 }
7126
7127 #[test]
7130 fn flow_component_and_hook_type_annotations() {
7131 use hermes_ast::node::Node;
7132 let alias_right = |stmt: &hermes_ast::node::Node<'_>| -> hermes_ast::node::NodeKind {
7133 let Node::TypeAlias(a) = stmt else {
7134 panic!("expected TypeAlias, got {:?}", stmt.kind())
7135 };
7136 a.right.kind()
7137 };
7138
7139 {
7141 let mut sm = hermes_support::manager::SourceErrorManager::new();
7142 let mut ctx = comp_ctx();
7143 let gc = ctx.lock();
7144 let stmt = comp_parse_stmt_at(
7145 &gc,
7146 &mut sm,
7147 b"type C = component(foo: string, ...bar: number) renders Baz;",
7148 0,
7149 );
7150 let Node::TypeAlias(a) = stmt else {
7151 panic!("expected TypeAlias, got {:?}", stmt.kind())
7152 };
7153 let Node::ComponentTypeAnnotation(ct) = a.right else {
7154 panic!("expected ComponentTypeAnnotation, got {:?}", a.right.kind())
7155 };
7156 assert_eq!(ct.params.iter().count(), 1);
7157 assert!(ct.rest.is_some());
7158 assert!(ct.renders_type.is_some());
7159 }
7160
7161 {
7163 let mut sm = hermes_support::manager::SourceErrorManager::new();
7164 let mut ctx = comp_ctx();
7165 let gc = ctx.lock();
7166 let stmt = comp_parse_stmt_at(
7167 &gc,
7168 &mut sm,
7169 b"type H = hook(a: number, b: string) => void;",
7170 0,
7171 );
7172 assert_eq!(alias_right(stmt), hermes_ast::node::NodeKind::HookTypeAnnotation);
7173 let Node::TypeAlias(a) = stmt else { unreachable!() };
7174 let Node::HookTypeAnnotation(h) = a.right else {
7175 panic!("expected HookTypeAnnotation, got {:?}", a.right.kind())
7176 };
7177 assert_eq!(h.params.iter().count(), 2);
7178 assert!(h.rest.is_none());
7179 }
7180 }
7181
7182 #[test]
7184 fn flow_hook_type_rejects_this() {
7185 use hermes_ast::context::Context;
7186 use hermes_support::manager::SourceErrorManager;
7187 let src = b"type H = hook(this: number) => void;";
7188 let mut sm = SourceErrorManager::new();
7189 let buf_id = sm.add_buffer_bytes("input", src);
7190 let mut ctx = Context::new();
7191 ctx.set_parse_flow(true);
7192 ctx.set_parse_flow_component_syntax(true);
7193 let gc = ctx.lock();
7194 let atoms = &gc.ctx().atom_table;
7195 let lexer = crate::lexer::JSLexer::new(
7196 buf_id,
7197 &mut sm,
7198 atoms,
7199 crate::lexer::GrammarContext::AllowRegExp,
7200 );
7201 let mut parser = JSParserImpl::new(&gc, lexer);
7202 let _ = parser.parse();
7203 assert!(
7204 parser.error_count_pub() >= 1,
7205 "hook type 'this' constraint must error"
7206 );
7207 }
7208
7209 #[test]
7213 fn flow_component_syntax_gated_off() {
7214 assert_parse_has_errors_impl(
7219 b"component Foo() {}",
7220 "component needs component-syntax flag",
7221 true,
7222 );
7223 let mut sm = hermes_support::manager::SourceErrorManager::new();
7225 let mut ctx = hermes_ast::context::Context::new();
7226 ctx.set_parse_flow(true);
7227 let gc = ctx.lock();
7228 let stmt = parse_one_stmt(&gc, &mut sm, b"var component = 1;");
7229 assert!(matches!(stmt, hermes_ast::node::Node::VariableDeclaration(_)));
7230 }
7231
7232 #[test]
7236 fn flow_p54_no_leak() {
7237 assert_parse_has_errors(
7238 b"class C extends B<T> {}",
7239 "super type args need Flow",
7240 );
7241 assert_parse_has_errors(
7242 b"function f(): T { return 1; }",
7243 "return type needs Flow",
7244 );
7245 assert_parse_has_errors(b"var a: T;", "binding annotation needs Flow");
7246 assert_parse_has_errors(
7247 b"var o = { m<T>() {} };",
7248 "object-method type params need Flow",
7249 );
7250 }
7251
7252 fn rec_ctx() -> hermes_ast::context::Context<'static> {
7261 let mut ctx = hermes_ast::context::Context::new();
7262 ctx.set_parse_flow(true);
7263 ctx.set_parse_flow_ambiguous(true);
7264 ctx.set_parse_flow_records(true);
7265 ctx
7266 }
7267
7268 fn rec_parse_stmt_at<'gc>(
7272 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
7273 sm: &mut hermes_support::manager::SourceErrorManager,
7274 src: &[u8],
7275 idx: usize,
7276 ) -> &'gc hermes_ast::node::Node<'gc> {
7277 comp_parse_stmt_at(gc, sm, src, idx)
7278 }
7279
7280 #[test]
7282 fn flow_record_empty() {
7283 use hermes_ast::node::Node;
7284 let mut sm = hermes_support::manager::SourceErrorManager::new();
7285 let mut ctx = rec_ctx();
7286 let gc = ctx.lock();
7287 let stmt = rec_parse_stmt_at(&gc, &mut sm, b"record Foo {}", 0);
7288 let Node::RecordDeclaration(r) = stmt else {
7289 panic!("expected RecordDeclaration, got {:?}", stmt.kind())
7290 };
7291 assert_eq!(ident_bytes(&gc, r.id), b"Foo");
7292 assert!(r.type_parameters.is_none(), "no type params");
7293 assert_eq!(r.implements.iter().count(), 0, "no implements");
7294 let Node::RecordDeclarationBody(body) = r.body else {
7295 panic!("expected RecordDeclarationBody, got {:?}", r.body.kind())
7296 };
7297 assert_eq!(body.elements.iter().count(), 0, "empty body");
7298 }
7299
7300 #[test]
7304 fn flow_record_full() {
7305 use hermes_ast::node::Node;
7306 let mut sm = hermes_support::manager::SourceErrorManager::new();
7307 let mut ctx = rec_ctx();
7308 let gc = ctx.lock();
7309 let stmt = rec_parse_stmt_at(
7310 &gc,
7311 &mut sm,
7312 b"record Point<T> implements I, J<K> {\n\
7313 x: number, y: T,\n\
7314 static origin: Point = mk(),\n\
7315 dist(o: Point): number { return 0; }\n\
7316 async *gen<U>(): U {}\n\
7317 }",
7318 0,
7319 );
7320 let Node::RecordDeclaration(r) = stmt else {
7321 panic!("expected RecordDeclaration, got {:?}", stmt.kind())
7322 };
7323 assert_eq!(ident_bytes(&gc, r.id), b"Point");
7324 assert!(r.type_parameters.is_some(), "has type params");
7325
7326 let impls: Vec<_> = r.implements.iter().collect();
7328 assert_eq!(impls.len(), 2, "two implements entries");
7329 let Node::RecordDeclarationImplements(i0) = impls[0] else {
7330 panic!("expected RecordDeclarationImplements")
7331 };
7332 assert_eq!(ident_bytes(&gc, i0.id), b"I");
7333 assert!(i0.type_arguments.is_none(), "I has no type-args");
7334 let Node::RecordDeclarationImplements(i1) = impls[1] else {
7335 panic!("expected RecordDeclarationImplements")
7336 };
7337 assert_eq!(ident_bytes(&gc, i1.id), b"J");
7338 assert!(i1.type_arguments.is_some(), "J<K> has type-args");
7339
7340 let Node::RecordDeclarationBody(body) = r.body else {
7341 panic!("expected RecordDeclarationBody")
7342 };
7343 let elems: Vec<_> = body.elements.iter().collect();
7344 assert_eq!(elems.len(), 5, "x, y, static origin, dist, gen");
7345
7346 let Node::RecordDeclarationProperty(p_x) = elems[0] else {
7348 panic!("expected RecordDeclarationProperty, got {:?}", elems[0].kind())
7349 };
7350 assert_eq!(ident_bytes(&gc, p_x.key), b"x");
7351 assert!(p_x.default_value.is_none(), "x has no initializer");
7352
7353 let Node::RecordDeclarationStaticProperty(p_origin) = elems[2] else {
7355 panic!(
7356 "expected RecordDeclarationStaticProperty, got {:?}",
7357 elems[2].kind()
7358 )
7359 };
7360 assert_eq!(ident_bytes(&gc, p_origin.key), b"origin");
7361
7362 let Node::MethodDefinition(m_dist) = elems[3] else {
7364 panic!("expected MethodDefinition, got {:?}", elems[3].kind())
7365 };
7366 assert!(!m_dist.r#static.get(), "dist is not static");
7367 let Node::FunctionExpression(f_dist) = m_dist.value else {
7368 panic!("expected FunctionExpression")
7369 };
7370 assert!(!f_dist.generator.get() && !f_dist.r#async.get());
7371 assert!(f_dist.return_type.is_some(), "dist has a return type");
7372
7373 let Node::MethodDefinition(m_gen) = elems[4] else {
7375 panic!("expected MethodDefinition, got {:?}", elems[4].kind())
7376 };
7377 let Node::FunctionExpression(f_gen) = m_gen.value else {
7378 panic!("expected FunctionExpression")
7379 };
7380 assert!(f_gen.generator.get(), "gen is a generator");
7381 assert!(f_gen.r#async.get(), "gen is async");
7382 assert!(f_gen.type_parameters.is_some(), "gen has type params");
7383 }
7384
7385 #[test]
7387 fn flow_record_expr_ident() {
7388 use hermes_ast::node::Node;
7389 let mut sm = hermes_support::manager::SourceErrorManager::new();
7390 let mut ctx = rec_ctx();
7391 let gc = ctx.lock();
7392 let init = {
7393 let stmt =
7394 rec_parse_stmt_at(&gc, &mut sm, b"const p = Point { x: 1 };", 0);
7395 let Node::VariableDeclaration(vd) = stmt else {
7396 panic!("expected VariableDeclaration")
7397 };
7398 let Node::VariableDeclarator(d) =
7399 vd.declarations.iter().next().unwrap()
7400 else {
7401 panic!("expected VariableDeclarator")
7402 };
7403 d.init.expect("has init")
7404 };
7405 let Node::RecordExpression(re) = init else {
7406 panic!("expected RecordExpression, got {:?}", init.kind())
7407 };
7408 assert_eq!(ident_bytes(&gc, re.record_constructor), b"Point");
7409 assert!(re.type_arguments.is_none(), "no type-args");
7410 let Node::RecordExpressionProperties(props) = re.properties else {
7411 panic!("expected RecordExpressionProperties")
7412 };
7413 assert_eq!(props.properties.iter().count(), 1, "one property");
7414 }
7415
7416 #[test]
7419 fn flow_record_expr_member_typeargs() {
7420 use hermes_ast::node::Node;
7421 let mut sm = hermes_support::manager::SourceErrorManager::new();
7422 let mut ctx = rec_ctx();
7423 let gc = ctx.lock();
7424 let init = {
7425 let stmt = rec_parse_stmt_at(
7426 &gc,
7427 &mut sm,
7428 b"const q = ns.Maker<T> { a: 3 };",
7429 0,
7430 );
7431 let Node::VariableDeclaration(vd) = stmt else {
7432 panic!("expected VariableDeclaration")
7433 };
7434 let Node::VariableDeclarator(d) =
7435 vd.declarations.iter().next().unwrap()
7436 else {
7437 panic!("expected VariableDeclarator")
7438 };
7439 d.init.expect("has init")
7440 };
7441 let Node::RecordExpression(re) = init else {
7442 panic!("expected RecordExpression, got {:?}", init.kind())
7443 };
7444 assert!(
7445 matches!(re.record_constructor, Node::MemberExpression(_)),
7446 "MemberExpression constructor"
7447 );
7448 assert!(re.type_arguments.is_some(), "ns.Maker<T> has type-args");
7449 }
7450
7451 #[test]
7457 fn flow_record_expr_lowercase_rejected() {
7458 use hermes_ast::node::Node;
7459 let mut sm = hermes_support::manager::SourceErrorManager::new();
7460 let mut ctx = rec_ctx();
7461 let gc = ctx.lock();
7462 let stmt = rec_parse_stmt_at(&gc, &mut sm, b"point\n{ x }", 0);
7465 assert!(
7466 !matches!(stmt, Node::RecordExpression(_)),
7467 "lowercase ctor must not form a RecordExpression"
7468 );
7469 }
7470
7471 #[test]
7474 fn flow_record_disabled_is_not_record() {
7475 use hermes_ast::context::Context;
7476 let mut sm = hermes_support::manager::SourceErrorManager::new();
7477 let mut ctx = Context::new();
7478 ctx.set_parse_flow(true); let gc = ctx.lock();
7480 let buf_id = sm.add_buffer_bytes("input", b"record R {}");
7481 let atoms = &gc.ctx().atom_table;
7482 let lexer = crate::lexer::JSLexer::new(
7483 buf_id,
7484 &mut sm,
7485 atoms,
7486 crate::lexer::GrammarContext::AllowRegExp,
7487 );
7488 let mut parser = JSParserImpl::new(&gc, lexer);
7489 let _ = parser.parse();
7490 assert!(
7491 parser.error_count_pub() > 0,
7492 "record disabled: `record R {{}}` must report a syntax error"
7493 );
7494 }
7495
7496 fn match_ctx() -> hermes_ast::context::Context<'static> {
7502 use hermes_ast::context::Context;
7503 let mut ctx = Context::new();
7504 ctx.set_parse_flow(true);
7505 ctx.set_parse_flow_match(true);
7506 ctx
7507 }
7508
7509 fn match_parse_stmt_at<'gc>(
7512 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
7513 sm: &mut hermes_support::manager::SourceErrorManager,
7514 src: &[u8],
7515 idx: usize,
7516 ) -> &'gc hermes_ast::node::Node<'gc> {
7517 let buf_id = sm.add_buffer_bytes("input", src);
7518 let atoms = &gc.ctx().atom_table;
7519 let lexer = crate::lexer::JSLexer::new(
7520 buf_id,
7521 sm,
7522 atoms,
7523 crate::lexer::GrammarContext::AllowRegExp,
7524 );
7525 let mut parser = JSParserImpl::new(gc, lexer);
7526 let program = parser.parse().expect("parse succeeded");
7527 assert_eq!(parser.error_count_pub(), 0, "zero errors for {src:?}");
7528 if let hermes_ast::node::Node::Program(p) = program {
7529 return p.body.iter().nth(idx).expect("has enough statements");
7530 }
7531 panic!("expected Program");
7532 }
7533
7534 fn match_expr_from<'gc>(
7536 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
7537 sm: &mut hermes_support::manager::SourceErrorManager,
7538 src: &[u8],
7539 ) -> &'gc hermes_ast::node::Node<'gc> {
7540 use hermes_ast::node::Node;
7541 let stmt = match_parse_stmt_at(gc, sm, src, 0);
7542 let Node::VariableDeclaration(vd) = stmt else {
7543 panic!("expected VariableDeclaration, got {:?}", stmt.kind())
7544 };
7545 let decl = vd.declarations.iter().next().expect("one declarator");
7546 let Node::VariableDeclarator(d) = decl else {
7547 panic!("expected VariableDeclarator")
7548 };
7549 d.init.expect("has init")
7550 }
7551
7552 #[test]
7555 fn flow_match_expression_basic() {
7556 use hermes_ast::node::Node;
7557 let mut sm = hermes_support::manager::SourceErrorManager::new();
7558 let mut ctx = match_ctx();
7559 let gc = ctx.lock();
7560 let expr =
7561 match_expr_from(&gc, &mut sm, b"const r = match (x) { 1 => 'a', _ => 'c' };");
7562 let Node::MatchExpression(m) = expr else {
7563 panic!("expected MatchExpression, got {:?}", expr.kind())
7564 };
7565 assert!(matches!(m.argument, Node::Identifier(_)), "arg is `x`");
7566 let mut it = m.cases.iter();
7567 let Node::MatchExpressionCase(c0) = it.next().unwrap() else {
7568 panic!("expected MatchExpressionCase")
7569 };
7570 assert!(
7571 matches!(c0.pattern, Node::MatchLiteralPattern(_)),
7572 "first case is a literal pattern"
7573 );
7574 assert!(c0.guard.is_none(), "no guard");
7575 let Node::MatchExpressionCase(c1) = it.next().unwrap() else {
7576 panic!("expected MatchExpressionCase")
7577 };
7578 assert!(
7579 matches!(c1.pattern, Node::MatchWildcardPattern(_)),
7580 "second case is the wildcard `_`"
7581 );
7582 assert!(it.next().is_none(), "exactly two cases");
7583 }
7584
7585 #[test]
7587 fn flow_match_statement_basic() {
7588 use hermes_ast::node::Node;
7589 let mut sm = hermes_support::manager::SourceErrorManager::new();
7590 let mut ctx = match_ctx();
7591 let gc = ctx.lock();
7592 let stmt =
7593 match_parse_stmt_at(&gc, &mut sm, b"match (x) { 1 => { f(); } _ => { g(); } }", 0);
7594 let Node::MatchStatement(m) = stmt else {
7595 panic!("expected MatchStatement, got {:?}", stmt.kind())
7596 };
7597 let mut it = m.cases.iter();
7598 let Node::MatchStatementCase(c0) = it.next().unwrap() else {
7599 panic!("expected MatchStatementCase")
7600 };
7601 assert!(
7602 matches!(c0.body, Node::BlockStatement(_)),
7603 "statement case body is a block"
7604 );
7605 assert!(it.next().is_some(), "second case present");
7606 }
7607
7608 #[test]
7611 fn flow_match_call_not_match() {
7612 use hermes_ast::node::Node;
7613 let mut sm = hermes_support::manager::SourceErrorManager::new();
7614 let mut ctx = match_ctx();
7615 let gc = ctx.lock();
7616
7617 let stmt0 = match_parse_stmt_at(&gc, &mut sm, b"match(1, 2);\nmatch (foo)(bar);", 0);
7618 let Node::ExpressionStatement(es0) = stmt0 else {
7619 panic!("expected ExpressionStatement")
7620 };
7621 let Node::CallExpression(call) = es0.expression else {
7622 panic!("expected CallExpression, got {:?}", es0.expression.kind())
7623 };
7624 assert!(matches!(call.callee, Node::Identifier(_)), "callee is `match`");
7626
7627 let stmt1 = match_parse_stmt_at(&gc, &mut sm, b"match(1, 2);\nmatch (foo)(bar);", 1);
7628 let Node::ExpressionStatement(es1) = stmt1 else {
7629 panic!("expected ExpressionStatement")
7630 };
7631 let Node::CallExpression(outer) = es1.expression else {
7634 panic!("expected CallExpression")
7635 };
7636 assert!(
7637 matches!(outer.callee, Node::CallExpression(_)),
7638 "outer callee is `match(foo)`"
7639 );
7640 }
7641
7642 #[test]
7647 fn flow_match_newline_is_not_match() {
7648 let mut sm = hermes_support::manager::SourceErrorManager::new();
7649 let mut ctx = match_ctx();
7650 let gc = ctx.lock();
7651 let buf_id = sm.add_buffer_bytes("input", b"match\n(x) { _ => 1 }\n");
7652 let atoms = &gc.ctx().atom_table;
7653 let lexer = crate::lexer::JSLexer::new(
7654 buf_id,
7655 &mut sm,
7656 atoms,
7657 crate::lexer::GrammarContext::AllowRegExp,
7658 );
7659 let mut parser = JSParserImpl::new(&gc, lexer);
7660 let _ = parser.parse();
7661 assert!(
7662 parser.error_count_pub() > 0,
7663 "`match\\n(x) {{…}}` must error (newline blocks the match), not parse as a match"
7664 );
7665 }
7666
7667 #[test]
7671 fn flow_match_expr_vs_stmt() {
7672 use hermes_ast::node::Node;
7673 let mut sm = hermes_support::manager::SourceErrorManager::new();
7674 let mut ctx = match_ctx();
7675 let gc = ctx.lock();
7676 let e = match_expr_from(&gc, &mut sm, b"const r = match (x) { _ => 1 };");
7677 assert!(matches!(e, Node::MatchExpression(_)), "expr form");
7678 let s = match_parse_stmt_at(&gc, &mut sm, b"match (x) { _ => { y; } }", 0);
7679 assert!(matches!(s, Node::MatchStatement(_)), "stmt form");
7680 }
7681
7682 #[test]
7684 fn flow_match_object_array_patterns() {
7685 use hermes_ast::node::Node;
7686 let mut sm = hermes_support::manager::SourceErrorManager::new();
7687 let mut ctx = match_ctx();
7688 let gc = ctx.lock();
7689 let expr = match_expr_from(
7690 &gc,
7691 &mut sm,
7692 b"const r = match (x) { {a: 1, b: _} => 1, [1, 2, ...const rest] => 2, _ => 3 };",
7693 );
7694 let Node::MatchExpression(m) = expr else {
7695 panic!("expected MatchExpression")
7696 };
7697 let mut it = m.cases.iter();
7698 let Node::MatchExpressionCase(c0) = it.next().unwrap() else {
7699 panic!("case 0")
7700 };
7701 let Node::MatchObjectPattern(obj) = c0.pattern else {
7702 panic!("expected MatchObjectPattern, got {:?}", c0.pattern.kind())
7703 };
7704 assert_eq!(obj.properties.iter().count(), 2, "two object props");
7705 assert!(obj.rest.is_none(), "no object rest");
7706 let Node::MatchExpressionCase(c1) = it.next().unwrap() else {
7707 panic!("case 1")
7708 };
7709 let Node::MatchArrayPattern(arr) = c1.pattern else {
7710 panic!("expected MatchArrayPattern, got {:?}", c1.pattern.kind())
7711 };
7712 assert_eq!(arr.elements.iter().count(), 2, "two array elements");
7713 let rest = arr.rest.expect("array rest present");
7714 let Node::MatchRestPattern(rp) = rest else {
7715 panic!("expected MatchRestPattern")
7716 };
7717 assert!(rp.argument.is_some(), "rest binds `const rest`");
7718 }
7719
7720 #[test]
7722 fn flow_match_or_and_guard() {
7723 use hermes_ast::node::Node;
7724 let mut sm = hermes_support::manager::SourceErrorManager::new();
7725 let mut ctx = match_ctx();
7726 let gc = ctx.lock();
7727 let expr = match_expr_from(
7728 &gc,
7729 &mut sm,
7730 b"const r = match (x) { 1 | 2 | 3 => 'low', const y if (y > 0) => 'pos', _ => 'z' };",
7731 );
7732 let Node::MatchExpression(m) = expr else {
7733 panic!("expected MatchExpression")
7734 };
7735 let mut it = m.cases.iter();
7736 let Node::MatchExpressionCase(c0) = it.next().unwrap() else {
7737 panic!("case 0")
7738 };
7739 let Node::MatchOrPattern(or) = c0.pattern else {
7740 panic!("expected MatchOrPattern, got {:?}", c0.pattern.kind())
7741 };
7742 assert_eq!(or.patterns.iter().count(), 3, "three or-alternatives");
7743 let Node::MatchExpressionCase(c1) = it.next().unwrap() else {
7744 panic!("case 1")
7745 };
7746 assert!(
7747 matches!(c1.pattern, Node::MatchBindingPattern(_)),
7748 "second case is a `const y` binding"
7749 );
7750 assert!(c1.guard.is_some(), "second case has an `if` guard");
7751 }
7752
7753 #[test]
7756 fn flow_match_member_unary_instance() {
7757 use hermes_ast::node::Node;
7758 let mut sm = hermes_support::manager::SourceErrorManager::new();
7759 let mut ctx = match_ctx();
7760 let gc = ctx.lock();
7761 let expr = match_expr_from(
7762 &gc,
7763 &mut sm,
7764 b"const r = match (x) { Foo.Bar => 1, -2 => 2, Status{value: const v} => v, _ => 0 };",
7765 );
7766 let Node::MatchExpression(m) = expr else {
7767 panic!("expected MatchExpression")
7768 };
7769 let mut it = m.cases.iter();
7770 let Node::MatchExpressionCase(c0) = it.next().unwrap() else {
7771 panic!("case 0")
7772 };
7773 assert!(
7774 matches!(c0.pattern, Node::MatchMemberPattern(_)),
7775 "first case is a member pattern, got {:?}",
7776 c0.pattern.kind()
7777 );
7778 let Node::MatchExpressionCase(c1) = it.next().unwrap() else {
7779 panic!("case 1")
7780 };
7781 let Node::MatchUnaryPattern(u) = c1.pattern else {
7782 panic!("expected MatchUnaryPattern, got {:?}", c1.pattern.kind())
7783 };
7784 assert_eq!(
7785 gc.ctx().atom_table.bytes(u.operator.get()),
7786 b"-",
7787 "unary operator is `-`"
7788 );
7789 let Node::MatchExpressionCase(c2) = it.next().unwrap() else {
7790 panic!("case 2")
7791 };
7792 let Node::MatchInstancePattern(inst) = c2.pattern else {
7793 panic!("expected MatchInstancePattern, got {:?}", c2.pattern.kind())
7794 };
7795 assert!(
7796 matches!(inst.properties, Node::MatchInstanceObjectPattern(_)),
7797 "instance properties are a MatchInstanceObjectPattern"
7798 );
7799 }
7800
7801 #[test]
7803 fn flow_match_as_pattern() {
7804 use hermes_ast::node::Node;
7805 let mut sm = hermes_support::manager::SourceErrorManager::new();
7806 let mut ctx = match_ctx();
7807 let gc = ctx.lock();
7808 let expr =
7809 match_expr_from(&gc, &mut sm, b"const r = match (x) { (1 | 2) as const k => k, _ => 0 };");
7810 let Node::MatchExpression(m) = expr else {
7811 panic!("expected MatchExpression")
7812 };
7813 let c0 = m.cases.iter().next().unwrap();
7814 let Node::MatchExpressionCase(c0) = c0 else {
7815 panic!("case 0")
7816 };
7817 let Node::MatchAsPattern(asp) = c0.pattern else {
7818 panic!("expected MatchAsPattern, got {:?}", c0.pattern.kind())
7819 };
7820 assert!(
7823 matches!(asp.pattern, Node::MatchOrPattern(_)),
7824 "as-pattern wraps a group-elided or-pattern"
7825 );
7826 assert!(
7827 matches!(asp.target, Node::MatchBindingPattern(_)),
7828 "as-target is a `const k` binding"
7829 );
7830 }
7831
7832 #[test]
7835 fn flow_match_rest_needs_binding() {
7836 let mut sm = hermes_support::manager::SourceErrorManager::new();
7837 let mut ctx = match_ctx();
7838 let gc = ctx.lock();
7839 let buf_id =
7840 sm.add_buffer_bytes("input", b"const r = match (x) { [...rest] => 1, _ => 0 };");
7841 let atoms = &gc.ctx().atom_table;
7842 let lexer = crate::lexer::JSLexer::new(
7843 buf_id,
7844 &mut sm,
7845 atoms,
7846 crate::lexer::GrammarContext::AllowRegExp,
7847 );
7848 let mut parser = JSParserImpl::new(&gc, lexer);
7849 let _ = parser.parse();
7850 assert!(
7851 parser.error_count_pub() > 0,
7852 "`...rest` without a binding keyword must error"
7853 );
7854 }
7855
7856 #[test]
7859 fn flow_match_disabled_is_identifier() {
7860 use hermes_ast::context::Context;
7861 use hermes_ast::node::Node;
7862 let mut sm = hermes_support::manager::SourceErrorManager::new();
7863 let mut ctx = Context::new();
7865 ctx.set_parse_flow(true);
7866 let gc = ctx.lock();
7867 let buf_id = sm.add_buffer_bytes("input", b"const r = match;\nmatch(x);");
7868 let atoms = &gc.ctx().atom_table;
7869 let lexer = crate::lexer::JSLexer::new(
7870 buf_id,
7871 &mut sm,
7872 atoms,
7873 crate::lexer::GrammarContext::AllowRegExp,
7874 );
7875 let mut parser = JSParserImpl::new(&gc, lexer);
7876 let program = parser.parse().expect("parses");
7877 assert_eq!(parser.error_count_pub(), 0, "no errors when match is off");
7878 let Node::Program(p) = program else {
7879 panic!("expected Program")
7880 };
7881 let mut body = p.body.iter();
7883 let Node::VariableDeclaration(vd) = body.next().unwrap() else {
7884 panic!("expected VariableDeclaration")
7885 };
7886 let Node::VariableDeclarator(d) = vd.declarations.iter().next().unwrap() else {
7887 panic!("expected VariableDeclarator")
7888 };
7889 assert!(
7890 matches!(d.init, Some(Node::Identifier(_))),
7891 "`match` is a plain identifier reference when the flag is off"
7892 );
7893 }
7894
7895 fn flow_parse_body<'gc>(
7902 gc: &'gc hermes_ast::context::GCLock<'_, '_>,
7903 sm: &mut hermes_support::manager::SourceErrorManager,
7904 src: &[u8],
7905 components: bool,
7906 ) -> Vec<&'gc hermes_ast::node::Node<'gc>> {
7907 let _ = components; let buf_id = sm.add_buffer_bytes("input", src);
7909 let atoms = &gc.ctx().atom_table;
7910 let lexer = crate::lexer::JSLexer::new(
7911 buf_id,
7912 sm,
7913 atoms,
7914 crate::lexer::GrammarContext::AllowRegExp,
7915 );
7916 let mut parser = JSParserImpl::new(gc, lexer);
7917 let program = parser.parse().expect("parse succeeded");
7918 assert_eq!(
7919 parser.error_count_pub(),
7920 0,
7921 "zero errors for {:?}",
7922 String::from_utf8_lossy(src)
7923 );
7924 if let hermes_ast::node::Node::Program(p) = program {
7925 return p.body.iter().collect();
7926 }
7927 panic!("expected Program");
7928 }
7929
7930 #[test]
7932 fn flow_declare_forms() {
7933 use hermes_ast::context::Context;
7934 use hermes_ast::node::Node;
7935 use hermes_support::manager::SourceErrorManager;
7936
7937 let check = |src: &[u8], pred: fn(&Node) -> bool| {
7938 let mut sm = SourceErrorManager::new();
7939 let mut ctx = Context::new();
7940 ctx.set_parse_flow(true);
7941 let gc = ctx.lock();
7942 let stmt = flow_parse_stmt_at(&gc, &mut sm, src, 0);
7943 assert!(pred(stmt), "wrong node for {:?}: {:?}", String::from_utf8_lossy(src), stmt.kind());
7944 };
7945
7946 check(b"declare function foo(x: number): string;", |n| {
7947 matches!(n, Node::DeclareFunction(_))
7948 });
7949 check(b"declare var x: number;", |n| {
7950 matches!(n, Node::DeclareVariable(_))
7951 });
7952 check(b"declare type T = number;", |n| {
7953 matches!(n, Node::DeclareTypeAlias(_))
7954 });
7955 check(b"declare interface I { foo(): void }", |n| {
7956 matches!(n, Node::DeclareInterface(_))
7957 });
7958 check(
7959 b"declare class C<T> extends B mixins M implements I { x: number; }",
7960 |n| matches!(n, Node::DeclareClass(_)),
7961 );
7962 check(b"declare module 'x' { declare var y: number; }", |n| {
7963 matches!(n, Node::DeclareModule(_))
7964 });
7965 check(b"declare module.exports: { a: number };", |n| {
7966 matches!(n, Node::DeclareModuleExports(_))
7967 });
7968 check(b"declare namespace NS { declare var z: string; }", |n| {
7969 matches!(n, Node::DeclareNamespace(_))
7970 });
7971 check(b"declare opaque type O: number;", |n| {
7972 matches!(n, Node::DeclareOpaqueType(_))
7973 });
7974 check(b"declare enum E { A, B }", |n| {
7975 matches!(n, Node::DeclareEnum(_))
7976 });
7977 }
7978
7979 #[test]
7983 fn flow_declare_export_forms() {
7984 use hermes_ast::context::Context;
7985 use hermes_ast::node::Node;
7986 use hermes_support::manager::SourceErrorManager;
7987
7988 let decl_of = |src: &[u8]| -> bool {
7989 let mut sm = SourceErrorManager::new();
7991 let mut ctx = Context::new();
7992 ctx.set_parse_flow(true);
7993 let gc = ctx.lock();
7994 let stmt = flow_parse_stmt_at(&gc, &mut sm, src, 0);
7995 let Node::DeclareExportDeclaration(d) = stmt else {
7996 panic!("expected DeclareExportDeclaration for {:?}, got {:?}",
7997 String::from_utf8_lossy(src), stmt.kind())
7998 };
7999 d.default.get()
8000 };
8001
8002 assert!(!decl_of(b"declare export function f(): void;"));
8003 assert!(decl_of(b"declare export default number;"));
8004 assert!(!decl_of(b"declare export opaque type T2: number;"));
8005
8006 {
8009 let mut sm = SourceErrorManager::new();
8010 let mut ctx = Context::new();
8011 ctx.set_parse_flow(true);
8012 let gc = ctx.lock();
8013 let stmt = flow_parse_stmt_at(
8014 &gc,
8015 &mut sm,
8016 b"declare export interface I2 { a: number }",
8017 0,
8018 );
8019 let Node::DeclareExportDeclaration(d) = stmt else {
8020 panic!("expected DeclareExportDeclaration")
8021 };
8022 assert!(
8023 matches!(d.declaration, Some(Node::InterfaceDeclaration(_))),
8024 "declare export interface wraps an InterfaceDeclaration"
8025 );
8026 }
8027
8028 {
8030 let mut sm = SourceErrorManager::new();
8031 let mut ctx = Context::new();
8032 ctx.set_parse_flow(true);
8033 let gc = ctx.lock();
8034 let stmt2 = flow_parse_stmt_at(
8035 &gc,
8036 &mut sm,
8037 b"declare export * from 'mod';",
8038 0,
8039 );
8040 assert!(matches!(stmt2, Node::DeclareExportAllDeclaration(_)));
8041 }
8042 }
8043
8044 #[test]
8047 fn flow_import_type_kinds() {
8048 use hermes_ast::context::Context;
8049 use hermes_ast::node::Node;
8050 use hermes_support::manager::SourceErrorManager;
8051
8052 let import_kind = |src: &[u8]| -> Vec<u8> {
8053 let mut sm = SourceErrorManager::new();
8054 let mut ctx = Context::new();
8055 ctx.set_parse_flow(true);
8056 let gc = ctx.lock();
8057 let stmt = flow_parse_stmt_at(&gc, &mut sm, src, 0);
8058 let Node::ImportDeclaration(d) = stmt else {
8059 panic!("expected ImportDeclaration for {:?}, got {:?}",
8060 String::from_utf8_lossy(src), stmt.kind())
8061 };
8062 gc.ctx().atom_table.bytes(d.import_kind.get()).to_vec()
8063 };
8064
8065 assert_eq!(import_kind(b"import type {A} from 'x';"), b"type");
8066 assert_eq!(import_kind(b"import typeof B from 'x';"), b"typeof");
8067 assert_eq!(import_kind(b"import {A} from 'x';"), b"value");
8068
8069 let mut sm = SourceErrorManager::new();
8071 let mut ctx = Context::new();
8072 ctx.set_parse_flow(true);
8073 let gc = ctx.lock();
8074 let stmt = flow_parse_stmt_at(
8075 &gc,
8076 &mut sm,
8077 b"import {type A2, typeof C} from 'x';",
8078 0,
8079 );
8080 let Node::ImportDeclaration(d) = stmt else {
8081 panic!("expected ImportDeclaration")
8082 };
8083 assert_eq!(gc.ctx().atom_table.bytes(d.import_kind.get()), b"value");
8085 let kinds: Vec<Vec<u8>> = d
8086 .specifiers
8087 .iter()
8088 .map(|s| {
8089 let Node::ImportSpecifier(is) = s else {
8090 panic!("expected ImportSpecifier")
8091 };
8092 gc.ctx().atom_table.bytes(is.import_kind.get()).to_vec()
8093 })
8094 .collect();
8095 assert_eq!(kinds, vec![b"type".to_vec(), b"typeof".to_vec()]);
8096 }
8097
8098 #[test]
8102 fn flow_import_type_from_trap() {
8103 use hermes_ast::context::Context;
8104 use hermes_ast::node::Node;
8105 use hermes_support::manager::SourceErrorManager;
8106
8107 let mut sm = SourceErrorManager::new();
8108 let mut ctx = Context::new();
8109 ctx.set_parse_flow(true);
8110 let gc = ctx.lock();
8111 let stmt = flow_parse_stmt_at(&gc, &mut sm, b"import type from 'x';", 0);
8112 let Node::ImportDeclaration(d) = stmt else {
8113 panic!("expected ImportDeclaration")
8114 };
8115 assert_eq!(
8116 gc.ctx().atom_table.bytes(d.import_kind.get()),
8117 b"value",
8118 "the trap resets the kind to value"
8119 );
8120 let spec = d.specifiers.iter().next().expect("one specifier");
8121 let Node::ImportDefaultSpecifier(s) = spec else {
8122 panic!("expected ImportDefaultSpecifier, got {:?}", spec.kind())
8123 };
8124 let Node::Identifier(local) = s.local else {
8125 panic!("expected Identifier local")
8126 };
8127 assert_eq!(gc.ctx().atom_table.bytes(local.name.get()), b"type");
8128 }
8129
8130 #[test]
8133 fn flow_declare_module_body_recursion() {
8134 use hermes_ast::context::Context;
8135 use hermes_ast::node::Node;
8136 use hermes_support::manager::SourceErrorManager;
8137
8138 let mut sm = SourceErrorManager::new();
8139 let mut ctx = Context::new();
8140 ctx.set_parse_flow(true);
8141 let gc = ctx.lock();
8142 let stmt = flow_parse_stmt_at(
8143 &gc,
8144 &mut sm,
8145 b"declare module 'x' { declare export var y: number; }",
8146 0,
8147 );
8148 let Node::DeclareModule(m) = stmt else {
8149 panic!("expected DeclareModule")
8150 };
8151 let Node::BlockStatement(b) = m.body else {
8152 panic!("expected BlockStatement body")
8153 };
8154 let inner = b.body.iter().next().expect("one inner declaration");
8155 assert!(
8156 matches!(inner, Node::DeclareExportDeclaration(_)),
8157 "inner declare export var parses, got {:?}",
8158 inner.kind()
8159 );
8160 }
8161
8162 #[test]
8165 fn flow_declare_component_and_hook() {
8166 use hermes_ast::context::Context;
8167 use hermes_ast::node::Node;
8168 use hermes_support::manager::SourceErrorManager;
8169
8170 let mut sm = SourceErrorManager::new();
8171 let mut ctx = Context::new();
8172 ctx.set_parse_flow(true);
8173 ctx.set_parse_flow_component_syntax(true);
8174 let gc = ctx.lock();
8175 let body = flow_parse_body(
8176 &gc,
8177 &mut sm,
8178 b"declare component Foo(p: number) renders Bar;\n\
8179 declare hook useY(a: string): number;",
8180 true,
8181 );
8182 assert!(matches!(body[0], Node::DeclareComponent(_)));
8183 assert!(matches!(body[1], Node::DeclareHook(_)));
8184 }
8185
8186 #[test]
8189 fn flow_plain_import_export_unaffected() {
8190 use hermes_ast::context::Context;
8191 use hermes_ast::node::Node;
8192 use hermes_support::manager::SourceErrorManager;
8193
8194 let mut sm = SourceErrorManager::new();
8196 let mut ctx = Context::new();
8197 let gc = ctx.lock();
8198 let stmt =
8199 flow_parse_stmt_at(&gc, &mut sm, b"import {a as b} from 'm';", 0);
8200 let Node::ImportDeclaration(d) = stmt else {
8201 panic!("expected ImportDeclaration")
8202 };
8203 assert_eq!(gc.ctx().atom_table.bytes(d.import_kind.get()), b"value");
8204 let Node::ImportSpecifier(is) =
8205 d.specifiers.iter().next().unwrap()
8206 else {
8207 panic!("expected ImportSpecifier")
8208 };
8209 assert_eq!(gc.ctx().atom_table.bytes(is.import_kind.get()), b"value");
8210
8211 let stmt2 =
8213 flow_parse_stmt_at(&gc, &mut sm, b"export {a as b};", 0);
8214 assert!(matches!(stmt2, Node::ExportNamedDeclaration(_)));
8215 }
8216}