Do not make intersection when only single item in coeffect brackets
[hiphop-php.git] / hphp / hack / src / parser / lowerer / lowerer.rs
blobfdbe454ffdaa90605f31dd97539e1dc3162a63d9
1 // Copyright (c) 2019, Facebook, Inc.
2 // All rights reserved.
3 //
4 // This source code is licensed under the MIT license found in the
5 // LICENSE file in the "hack" directory of this source tree.
7 use crate::{desugar_expression_tree::desugar, modifier};
8 use bstr::{BStr, BString, ByteSlice, B};
9 use bumpalo::Bump;
10 use escaper::*;
11 use hh_autoimport_rust as hh_autoimport;
12 use itertools::Either;
13 use lint_rust::LintError;
14 use naming_special_names_rust::{
15     classes as special_classes, literal, members as special_members, rx, special_functions,
16     special_idents, typehints as special_typehints, user_attributes as special_attrs,
18 use ocamlrep::rc::RcOc;
19 use oxidized::{
20     aast,
21     aast_visitor::{AstParams, Node, Visitor},
22     ast,
23     ast::Expr_ as E_,
24     doc_comment::DocComment,
25     errors::{Error as HHError, Naming, NastCheck},
26     file_info,
27     global_options::GlobalOptions,
28     namespace_env::Env as NamespaceEnv,
29     pos::Pos,
30     s_map,
32 use parser_core_types::{
33     indexed_source_text::IndexedSourceText,
34     lexable_token::LexablePositionedToken,
35     source_text::SourceText,
36     syntax::{SyntaxValueType, SyntaxValueWithKind},
37     syntax_by_ref::{
38         positioned_token::{PositionedToken, TokenFactory as PositionedTokenFactory},
39         positioned_value::PositionedValue,
40         syntax::Syntax,
41         syntax_variant_generated::{SyntaxVariant::*, *},
42     },
43     syntax_error, syntax_kind,
44     syntax_trait::SyntaxTrait,
45     token_factory::TokenMutator,
46     token_kind::TokenKind as TK,
48 use regex::bytes::Regex;
49 use stack_limit::StackLimit;
50 use std::{
51     cell::{Ref, RefCell, RefMut},
52     collections::HashSet,
53     matches, mem,
54     rc::Rc,
55     slice::Iter,
58 fn unescape_single(s: &str) -> std::result::Result<BString, escaper::InvalidString> {
59     Ok(escaper::unescape_single(s)?.into())
62 fn unescape_nowdoc(s: &str) -> std::result::Result<BString, escaper::InvalidString> {
63     Ok(escaper::unescape_nowdoc(s)?.into())
66 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
67 pub enum LiftedAwaitKind {
68     LiftedFromStatement,
69     LiftedFromConcurrent,
72 type LiftedAwaitExprs = Vec<(Option<ast::Lid>, ast::Expr)>;
74 #[derive(Debug, Clone)]
75 pub struct LiftedAwaits {
76     pub awaits: LiftedAwaitExprs,
77     lift_kind: LiftedAwaitKind,
80 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
81 pub enum ExprLocation {
82     TopLevel,
83     MemberSelect,
84     InDoubleQuotedString,
85     AsStatement,
86     RightOfAssignment,
87     RightOfAssignmentInUsingStatement,
88     RightOfReturn,
89     UsingStatement,
92 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
93 pub enum SuspensionKind {
94     SKSync,
95     SKAsync,
98 #[derive(Copy, Clone, Eq, PartialEq)]
99 pub enum TokenOp {
100     Skip,
101     Noop,
102     LeftTrim(usize),
103     RightTrim(usize),
106 #[derive(Debug)]
107 pub struct FunHdr {
108     suspension_kind: SuspensionKind,
109     name: ast::Sid,
110     constrs: Vec<ast::WhereConstraintHint>,
111     type_parameters: Vec<ast::Tparam>,
112     parameters: Vec<ast::FunParam>,
113     capability: Option<ast::Hint>,
114     unsafe_capability: Option<ast::Hint>,
115     return_type: Option<ast::Hint>,
118 impl FunHdr {
119     fn make_empty<TF: Clone>(env: &Env<TF>) -> Self {
120         Self {
121             suspension_kind: SuspensionKind::SKSync,
122             name: ast::Id(env.mk_none_pos(), String::from("<ANONYMOUS>")),
123             constrs: vec![],
124             type_parameters: vec![],
125             parameters: vec![],
126             capability: None,
127             unsafe_capability: None,
128             return_type: None,
129         }
130     }
133 #[derive(Debug)]
134 pub struct State {
135     pub cls_reified_generics: HashSet<String>,
136     pub in_static_method: bool,
137     pub parent_maybe_reified: bool,
138     /// This provides a generic mechanism to delay raising parsing errors;
139     /// since we're moving FFP errors away from CST to a stage after lowering
140     /// _and_ want to prioritize errors before lowering, the lowering errors
141     /// must be merely stored when the lowerer runs (until check for FFP runs (on AST)
142     /// and raised _after_ FFP error checking (unless we run the lowerer twice,
143     /// which would be expensive).
144     pub lowpri_errors: Vec<(Pos, String)>,
145     /// hh_errors captures errors after parsing, naming, nast, etc.
146     pub hh_errors: Vec<HHError>,
147     pub lint_errors: Vec<LintError>,
148     pub doc_comments: Vec<Option<DocComment>>,
150     pub local_id_counter: isize,
152     // TODO(hrust): this check is to avoid crash in Ocaml.
153     // Remove it after all Ocaml callers are eliminated.
154     pub exp_recursion_depth: usize,
157 const EXP_RECUSION_LIMIT: usize = 30_000;
159 #[derive(Debug, Clone)]
160 pub struct Env<'a, TF> {
161     pub codegen: bool,
162     pub keep_errors: bool,
163     quick_mode: bool,
164     /// Show errors even in quick mode. Does not override keep_errors. Hotfix
165     /// until we can properly set up saved states to surface parse errors during
166     /// typechecking properly.
167     pub show_all_errors: bool,
168     fail_open: bool,
169     file_mode: file_info::Mode,
170     disable_lowering_parsing_error: bool,
171     pub top_level_statements: bool, /* Whether we are (still) considering TLSs*/
173     // Cache none pos, lazy_static doesn't allow Rc.
174     pos_none: Pos,
175     pub empty_ns_env: RcOc<NamespaceEnv>,
177     pub saw_yield: bool, /* Information flowing back up */
178     pub lifted_awaits: Option<LiftedAwaits>,
179     pub tmp_var_counter: isize,
181     pub indexed_source_text: &'a IndexedSourceText<'a>,
182     pub parser_options: &'a GlobalOptions,
183     pub stack_limit: Option<&'a StackLimit>,
185     pub token_factory: TF,
186     pub arena: &'a Bump,
188     state: Rc<RefCell<State>>,
191 impl<'a, TF: Clone> Env<'a, TF> {
192     pub fn make(
193         codegen: bool,
194         quick_mode: bool,
195         keep_errors: bool,
196         show_all_errors: bool,
197         fail_open: bool,
198         disable_lowering_parsing_error: bool,
199         mode: file_info::Mode,
200         indexed_source_text: &'a IndexedSourceText<'a>,
201         parser_options: &'a GlobalOptions,
202         use_default_namespace: bool,
203         stack_limit: Option<&'a StackLimit>,
204         token_factory: TF,
205         arena: &'a Bump,
206     ) -> Self {
207         // (hrust) Ported from namespace_env.ml
208         let empty_ns_env = if use_default_namespace {
209             let mut nsenv = NamespaceEnv::empty(vec![], false, false);
210             nsenv.is_codegen = codegen;
211             nsenv.disable_xhp_element_mangling = parser_options.po_disable_xhp_element_mangling;
212             nsenv
213         } else {
214             let mut ns_uses = hh_autoimport::NAMESPACES_MAP.clone();
215             parser_options
216                 .po_auto_namespace_map
217                 .iter()
218                 .for_each(|(k, v)| {
219                     &ns_uses.insert(k.into(), v.into());
220                 });
221             NamespaceEnv {
222                 ns_uses,
223                 class_uses: hh_autoimport::TYPES_MAP.clone(),
224                 fun_uses: hh_autoimport::FUNCS_MAP.clone(),
225                 const_uses: hh_autoimport::CONSTS_MAP.clone(),
226                 record_def_uses: s_map::SMap::new(),
227                 name: None,
228                 auto_ns_map: parser_options.po_auto_namespace_map.clone(),
229                 is_codegen: codegen,
230                 disable_xhp_element_mangling: parser_options.po_disable_xhp_element_mangling,
231             }
232         };
234         Env {
235             codegen,
236             keep_errors,
237             quick_mode,
238             show_all_errors,
239             fail_open,
240             disable_lowering_parsing_error,
241             file_mode: mode,
242             top_level_statements: true,
243             saw_yield: false,
244             lifted_awaits: None,
245             tmp_var_counter: 1,
246             indexed_source_text,
247             parser_options,
248             pos_none: Pos::make_none(),
249             empty_ns_env: RcOc::new(empty_ns_env),
250             stack_limit,
251             token_factory,
252             arena,
254             state: Rc::new(RefCell::new(State {
255                 cls_reified_generics: HashSet::new(),
256                 in_static_method: false,
257                 parent_maybe_reified: false,
258                 lowpri_errors: vec![],
259                 doc_comments: vec![],
260                 local_id_counter: 1,
261                 hh_errors: vec![],
262                 lint_errors: vec![],
263                 exp_recursion_depth: 0,
264             })),
265         }
266     }
268     fn file_mode(&self) -> file_info::Mode {
269         self.file_mode
270     }
272     fn should_surface_error(&self) -> bool {
273         (!self.quick_mode || self.show_all_errors) && self.keep_errors
274     }
276     fn is_typechecker(&self) -> bool {
277         !self.codegen
278     }
280     fn codegen(&self) -> bool {
281         self.codegen
282     }
284     fn source_text(&self) -> &SourceText<'a> {
285         self.indexed_source_text.source_text()
286     }
288     fn fail_open(&self) -> bool {
289         self.fail_open
290     }
292     fn cls_reified_generics(&mut self) -> RefMut<HashSet<String>> {
293         RefMut::map(self.state.borrow_mut(), |s| &mut s.cls_reified_generics)
294     }
296     fn in_static_method(&mut self) -> RefMut<bool> {
297         RefMut::map(self.state.borrow_mut(), |s| &mut s.in_static_method)
298     }
300     fn parent_maybe_reified(&mut self) -> RefMut<bool> {
301         RefMut::map(self.state.borrow_mut(), |s| &mut s.parent_maybe_reified)
302     }
304     pub fn lowpri_errors(&mut self) -> RefMut<Vec<(Pos, String)>> {
305         RefMut::map(self.state.borrow_mut(), |s| &mut s.lowpri_errors)
306     }
308     pub fn hh_errors(&mut self) -> RefMut<Vec<HHError>> {
309         RefMut::map(self.state.borrow_mut(), |s| &mut s.hh_errors)
310     }
312     pub fn lint_errors(&mut self) -> RefMut<Vec<LintError>> {
313         RefMut::map(self.state.borrow_mut(), |s| &mut s.lint_errors)
314     }
316     fn top_docblock(&self) -> Ref<Option<DocComment>> {
317         Ref::map(self.state.borrow(), |s| {
318             s.doc_comments.last().unwrap_or(&None)
319         })
320     }
322     fn exp_recursion_depth(&self) -> RefMut<usize> {
323         RefMut::map(self.state.borrow_mut(), |s| &mut s.exp_recursion_depth)
324     }
326     fn next_local_id(&self) -> isize {
327         let mut id = RefMut::map(self.state.borrow_mut(), |s| &mut s.local_id_counter);
328         *id = *id + 1;
329         *id
330     }
332     fn push_docblock(&mut self, doc_comment: Option<DocComment>) {
333         RefMut::map(self.state.borrow_mut(), |s| &mut s.doc_comments).push(doc_comment)
334     }
336     fn pop_docblock(&mut self) {
337         RefMut::map(self.state.borrow_mut(), |s| &mut s.doc_comments).pop();
338     }
340     fn make_tmp_var_name(&mut self) -> String {
341         let name = String::from(special_idents::TMP_VAR_PREFIX) + &self.tmp_var_counter.to_string();
342         self.tmp_var_counter += 1;
343         name
344     }
346     fn mk_none_pos(&self) -> Pos {
347         self.pos_none.clone()
348     }
350     fn clone_and_unset_toplevel_if_toplevel<'b, 'c>(
351         e: &'b mut Env<'c, TF>,
352     ) -> impl AsMut<Env<'c, TF>> + 'b {
353         if e.top_level_statements {
354             let mut cloned = e.clone();
355             cloned.top_level_statements = false;
356             Either::Left(cloned)
357         } else {
358             Either::Right(e)
359         }
360     }
362     fn check_stack_limit(&self) {
363         self.stack_limit
364             .as_ref()
365             .map(|limit| limit.panic_if_exceeded());
366     }
369 impl<'a, TF> AsMut<Env<'a, TF>> for Env<'a, TF> {
370     fn as_mut(&mut self) -> &mut Env<'a, TF> {
371         self
372     }
375 #[derive(Debug)]
376 pub enum Error {
377     MissingSyntax {
378         expecting: String,
379         pos: Pos,
380         node_name: String,
381         kind: syntax_kind::SyntaxKind,
382     },
383     Failwith(String),
386 type Result<T> = std::result::Result<T, Error>;
387 type S<'arena, T, V> = &'arena Syntax<'arena, T, V>;
389 trait Lowerer<'a, T, V, TF>
390 where
391     TF: TokenMutator<Token = T> + Clone + 'a,
392     T: 'a + LexablePositionedToken + Copy,
393     V: 'a + SyntaxValueWithKind + SyntaxValueType<T>,
394     Syntax<'a, T, V>: SyntaxTrait,
396     fn p_pos(node: S<'a, T, V>, env: &Env<TF>) -> Pos {
397         node.position_exclusive(env.indexed_source_text)
398             .unwrap_or_else(|| env.mk_none_pos())
399     }
401     fn raise_parsing_error(node: S<'a, T, V>, env: &mut Env<'a, TF>, msg: &str) {
402         Self::raise_parsing_error_(Either::Left(node), env, msg)
403     }
405     fn raise_parsing_error_pos(pos: &Pos, env: &mut Env<'a, TF>, msg: &str) {
406         Self::raise_parsing_error_(Either::Right(pos), env, msg)
407     }
409     fn raise_parsing_error_(
410         node_or_pos: Either<S<'a, T, V>, &Pos>,
411         env: &mut Env<'a, TF>,
412         msg: &str,
413     ) {
414         if env.should_surface_error() {
415             let pos = node_or_pos.either(|node| Self::p_pos(node, env), |pos| pos.clone());
416             env.lowpri_errors().push((pos, String::from(msg)))
417         } else if env.codegen() {
418             let pos = node_or_pos.either(
419                 |node| {
420                     node.position_exclusive(env.indexed_source_text)
421                         .unwrap_or_else(|| env.mk_none_pos())
422                 },
423                 |pos| pos.clone(),
424             );
425             env.lowpri_errors().push((pos, String::from(msg)))
426         }
427     }
429     fn raise_hh_error(env: &mut Env<'a, TF>, err: HHError) {
430         env.hh_errors().push(err);
431     }
433     fn raise_lint_error(env: &mut Env<'a, TF>, err: LintError) {
434         env.lint_errors().push(err);
435     }
437     fn failwith<N>(msg: impl Into<String>) -> Result<N> {
438         Err(Error::Failwith(msg.into()))
439     }
441     fn text(node: S<'a, T, V>, env: &Env<TF>) -> String {
442         String::from(node.text(env.source_text()))
443     }
445     fn text_str<'b>(node: S<'a, T, V>, env: &'b Env<TF>) -> &'b str {
446         node.text(env.source_text())
447     }
449     fn lowering_error(env: &mut Env<'a, TF>, pos: &Pos, text: &str, syntax_kind: &str) {
450         if env.is_typechecker()
451             && !env.disable_lowering_parsing_error
452             && env.lowpri_errors().is_empty()
453         {
454             Self::raise_parsing_error_pos(
455                 pos,
456                 env,
457                 &syntax_error::lowering_parsing_error(text, syntax_kind),
458             )
459         }
460     }
462     fn missing_syntax_<N>(
463         fallback: Option<N>,
464         expecting: &str,
465         node: S<'a, T, V>,
466         env: &mut Env<'a, TF>,
467     ) -> Result<N> {
468         let pos = Self::p_pos(node, env);
469         let text = Self::text(node, env);
470         Self::lowering_error(env, &pos, &text, expecting);
471         if let Some(x) = fallback {
472             if env.fail_open() {
473                 return Ok(x);
474             }
475         }
476         Err(Error::MissingSyntax {
477             expecting: String::from(expecting),
478             pos: Self::p_pos(node, env),
479             node_name: text,
480             kind: node.kind(),
481         })
482     }
484     fn missing_syntax<N>(expecting: &str, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<N> {
485         Self::missing_syntax_(None, expecting, node, env)
486     }
488     fn is_num_octal_lit(s: &str) -> bool {
489         !s.chars().any(|c| c == '8' || c == '9')
490     }
492     fn mp_optional<F, R>(p: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Option<R>>
493     where
494         F: FnOnce(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
495     {
496         match &node.children {
497             Missing => Ok(None),
498             _ => p(node, env).map(Some),
499         }
500     }
502     fn pos_qualified_name(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Sid> {
503         if let QualifiedName(c) = &node.children {
504             if let SyntaxList(l) = &c.parts.children {
505                 let p = Self::p_pos(node, env);
506                 let mut s = String::with_capacity(node.width());
507                 for i in l.iter() {
508                     match &i.children {
509                         ListItem(li) => {
510                             s += Self::text_str(&li.item, env);
511                             s += Self::text_str(&li.separator, env);
512                         }
513                         _ => s += Self::text_str(&i, env),
514                     }
515                 }
516                 return Ok(ast::Id(p, s));
517             }
518         }
519         Self::missing_syntax("qualified name", node, env)
520     }
522     fn pos_name(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Sid> {
523         Self::pos_name_(node, env, None)
524     }
526     fn lid_from_pos_name(pos: Pos, name: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Lid> {
527         let name = Self::pos_name(name, env)?;
528         Ok(ast::Lid::new(pos, name.1))
529     }
531     fn lid_from_name(name: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Lid> {
532         let name = Self::pos_name(name, env)?;
533         Ok(ast::Lid::new(name.0, name.1))
534     }
536     fn p_pstring(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Pstring> {
537         Self::p_pstring_(node, env, None)
538     }
540     fn p_pstring_(
541         node: S<'a, T, V>,
542         env: &mut Env<'a, TF>,
543         drop_prefix: Option<char>,
544     ) -> Result<ast::Pstring> {
545         let ast::Id(p, id) = Self::pos_name_(node, env, drop_prefix)?;
546         Ok((p, id))
547     }
549     fn drop_prefix(s: &str, prefix: char) -> &str {
550         if s.len() > 0 && s.chars().nth(0) == Some(prefix) {
551             &s[1..]
552         } else {
553             s
554         }
555     }
557     fn pos_name_(
558         node: S<'a, T, V>,
559         env: &mut Env<'a, TF>,
560         drop_prefix: Option<char>,
561     ) -> Result<ast::Sid> {
562         match &node.children {
563             QualifiedName(_) => Self::pos_qualified_name(node, env),
564             SimpleTypeSpecifier(c) => Self::pos_name_(&c.specifier, env, drop_prefix),
565             _ => {
566                 let mut name = node.text(env.indexed_source_text.source_text());
567                 if let Some(prefix) = drop_prefix {
568                     name = Self::drop_prefix(name, prefix);
569                 }
570                 let p = Self::p_pos(node, env);
571                 Ok(ast::Id(p, String::from(name)))
572             }
573         }
574     }
576     fn mk_str<F>(
577         node: S<'a, T, V>,
578         env: &mut Env<'a, TF>,
579         unescaper: F,
580         mut content: &str,
581     ) -> BString
582     where
583         F: Fn(&str) -> std::result::Result<BString, InvalidString>,
584     {
585         if let Some('b') = content.chars().nth(0) {
586             content = content.get(1..).unwrap();
587         }
589         let len = content.len();
590         let no_quotes_result = extract_unquoted_string(content, 0, len);
591         match no_quotes_result {
592             Ok(no_quotes) => {
593                 let result = unescaper(&no_quotes);
594                 match result {
595                     Ok(s) => s,
596                     Err(_) => {
597                         Self::raise_parsing_error(
598                             node,
599                             env,
600                             &format!("Malformed string literal <<{}>>", &no_quotes),
601                         );
602                         BString::from("")
603                     }
604                 }
605             }
606             Err(_) => {
607                 Self::raise_parsing_error(
608                     node,
609                     env,
610                     &format!("Malformed string literal <<{}>>", &content),
611                 );
612                 BString::from("")
613             }
614         }
615     }
617     fn unesc_dbl(s: &str) -> std::result::Result<BString, InvalidString> {
618         let unesc_s = unescape_double(s)?;
619         if unesc_s == B("''") || unesc_s == B("\"\"") {
620             Ok(BString::from(""))
621         } else {
622             Ok(unesc_s)
623         }
624     }
626     // TODO: return Cow<[u8]>
627     fn unesc_xhp(s: &[u8]) -> Vec<u8> {
628         lazy_static! {
629             static ref WHITESPACE: Regex = Regex::new("[\x20\t\n\r\x0c]+").unwrap();
630         }
631         WHITESPACE.replace_all(s, &b" "[..]).into_owned()
632     }
634     fn unesc_xhp_attr(s: &[u8]) -> Vec<u8> {
635         // TODO: change unesc_dbl to &[u8] -> BString
636         let r = Self::get_quoted_content(s);
637         let r = unsafe { std::str::from_utf8_unchecked(r) };
638         Self::unesc_dbl(r).unwrap().into()
639     }
641     fn get_quoted_content(s: &[u8]) -> &[u8] {
642         lazy_static! {
643             static ref QUOTED: Regex = Regex::new(r#"^[\x20\t\n\r\x0c]*"((?:.|\n)*)""#).unwrap();
644         }
645         QUOTED
646             .captures(s)
647             .map_or(None, |c| c.get(1))
648             .map_or(s, |m| m.as_bytes())
649     }
651     fn token_kind(node: S<'a, T, V>) -> Option<TK> {
652         match &node.children {
653             Token(t) => Some(t.kind()),
654             _ => None,
655         }
656     }
658     fn check_valid_reified_hint(env: &mut Env<'a, TF>, node: S<'a, T, V>, hint: &ast::Hint) {
659         struct Checker<F: FnMut(&String)>(F);
660         impl<'ast, F: FnMut(&String)> Visitor<'ast> for Checker<F> {
661             type P = AstParams<(), ()>;
663             fn object(&mut self) -> &mut dyn Visitor<'ast, P = Self::P> {
664                 self
665             }
667             fn visit_hint(&mut self, c: &mut (), h: &ast::Hint) -> std::result::Result<(), ()> {
668                 match h.1.as_ref() {
669                     ast::Hint_::Happly(id, _) => {
670                         self.0(&id.1);
671                     }
672                     ast::Hint_::Haccess(_, ids) => {
673                         ids.iter().for_each(|id| self.0(&id.1));
674                     }
675                     _ => {}
676                 }
677                 h.recurse(c, self)
678             }
679         }
681         if *env.in_static_method() {
682             let f = |id: &String| {
683                 Self::fail_if_invalid_reified_generic(node, env, id);
684             };
685             let mut visitor = Checker(f);
686             visitor.visit_hint(&mut (), hint).unwrap();
687         }
688     }
690     fn p_closure_parameter(
691         node: S<'a, T, V>,
692         env: &mut Env<'a, TF>,
693     ) -> Result<(ast::Hint, Option<ast::ParamKind>)> {
694         match &node.children {
695             ClosureParameterTypeSpecifier(c) => {
696                 let kind = Self::mp_optional(Self::p_param_kind, &c.call_convention, env)?;
697                 let hint = Self::p_hint(&c.type_, env)?;
698                 Ok((hint, kind))
699             }
700             _ => Self::missing_syntax("closure parameter", node, env),
701         }
702     }
704     fn mp_shape_expression_field<F, R>(
705         f: F,
706         node: S<'a, T, V>,
707         env: &mut Env<'a, TF>,
708     ) -> Result<(ast::ShapeFieldName, R)>
709     where
710         F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
711     {
712         match &node.children {
713             FieldInitializer(c) => {
714                 let name = Self::p_shape_field_name(&c.name, env)?;
715                 let value = f(&c.value, env)?;
716                 Ok((name, value))
717             }
718             _ => Self::missing_syntax("shape field", node, env),
719         }
720     }
722     fn p_shape_field_name(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::ShapeFieldName> {
723         use ast::ShapeFieldName::*;
724         let is_valid_shape_literal = |t: &T| {
725             let is_str = t.kind() == TK::SingleQuotedStringLiteral
726                 || t.kind() == TK::DoubleQuotedStringLiteral;
727             let text = t.text(env.source_text());
728             let is_empty = text == "\'\'" || text == "\"\"";
729             is_str && !is_empty
730         };
731         if let LiteralExpression(c) = &node.children {
732             if let Token(t) = &c.expression.children {
733                 if is_valid_shape_literal(t) {
734                     let ast::Id(p, n) = Self::pos_name(node, env)?;
735                     let unescp = if t.kind() == TK::SingleQuotedStringLiteral {
736                         unescape_single
737                     } else {
738                         Self::unesc_dbl
739                     };
740                     let str_ = Self::mk_str(node, env, unescp, &n);
741                     if let Some(_) = ocaml_helper::int_of_string_opt(&str_.as_bytes()) {
742                         Self::raise_parsing_error(
743                             node,
744                             env,
745                             &syntax_error::shape_field_int_like_string,
746                         )
747                     }
748                     return Ok(SFlitStr((p, str_)));
749                 }
750             }
751         }
752         match &node.children {
753             ScopeResolutionExpression(c) => Ok(SFclassConst(
754                 Self::pos_name(&c.qualifier, env)?,
755                 Self::p_pstring(&c.name, env)?,
756             )),
757             _ => {
758                 Self::raise_parsing_error(node, env, &syntax_error::invalid_shape_field_name);
759                 let ast::Id(p, n) = Self::pos_name(node, env)?;
760                 Ok(SFlitStr((p, Self::mk_str(node, env, Self::unesc_dbl, &n))))
761             }
762         }
763     }
765     fn p_shape_field(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::ShapeFieldInfo> {
766         match &node.children {
767             FieldSpecifier(c) => {
768                 let optional = !c.question.is_missing();
769                 let name = Self::p_shape_field_name(&c.name, env)?;
770                 let hint = Self::p_hint(&c.type_, env)?;
771                 Ok(ast::ShapeFieldInfo {
772                     optional,
773                     hint,
774                     name,
775                 })
776             }
777             _ => {
778                 let (name, hint) = Self::mp_shape_expression_field(Self::p_hint, node, env)?;
779                 Ok(ast::ShapeFieldInfo {
780                     optional: false,
781                     name,
782                     hint,
783                 })
784             }
785         }
786     }
788     fn p_targ(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Targ> {
789         Ok(ast::Targ((), Self::p_hint(node, env)?))
790     }
792     fn p_hint_(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Hint_> {
793         use ast::Hint_::*;
794         let unary = |kw, ty, env: &mut Env<'a, TF>| {
795             Ok(Happly(
796                 Self::pos_name(kw, env)?,
797                 Self::could_map(Self::p_hint, ty, env)?,
798             ))
799         };
800         let binary = |kw, key, ty, env: &mut Env<'a, TF>| {
801             let kw = Self::pos_name(kw, env)?;
802             let key = Self::p_hint(key, env)?;
803             Ok(Happly(
804                 kw,
805                 Self::map_flatten_(&Self::p_hint, ty, env, vec![key])?,
806             ))
807         };
809         match &node.children {
810             /* Dirty hack; CastExpression can have type represented by token */
811             Token(_) | SimpleTypeSpecifier(_) | QualifiedName(_) => {
812                 let ast::Id(pos, name) = Self::pos_name(node, env)?;
813                 let mut suggest = |name: &str, canonical: &str| {
814                     Self::raise_parsing_error(
815                         node,
816                         env,
817                         &syntax_error::invalid_typehint_alias(name, canonical),
818                     );
819                 };
820                 if "integer".eq_ignore_ascii_case(&name) {
821                     suggest(&name, special_typehints::INT);
822                 } else if "boolean".eq_ignore_ascii_case(&name) {
823                     suggest(&name, special_typehints::BOOL);
824                 } else if "double".eq_ignore_ascii_case(&name) {
825                     suggest(&name, special_typehints::FLOAT);
826                 } else if "real".eq_ignore_ascii_case(&name) {
827                     suggest(&name, special_typehints::FLOAT);
828                 }
829                 Ok(Happly(ast::Id(pos, name), vec![]))
830             }
831             ShapeTypeSpecifier(c) => {
832                 let allows_unknown_fields = !c.ellipsis.is_missing();
833                 /* if last element lacks a separator and ellipsis is present, error */
834                 if allows_unknown_fields {
835                     if let SyntaxList(items) = &c.fields.children {
836                         if let Some(ListItem(item)) = items.last().map(|i| &i.children) {
837                             if item.separator.is_missing() {
838                                 Self::raise_parsing_error(
839                                     node,
840                                     env,
841                                     &syntax_error::shape_type_ellipsis_without_trailing_comma,
842                                 )
843                             }
844                         }
845                     }
846                 }
848                 let field_map = Self::could_map(Self::p_shape_field, &c.fields, env)?;
849                 // TODO:(shiqicao) improve perf
850                 // 1. replace HashSet by fnv hash map or something faster,
851                 // 2. move `set` to Env to avoid allocation,
852                 let mut set: HashSet<&BStr> = HashSet::with_capacity(field_map.len());
853                 for f in field_map.iter() {
854                     if !set.insert(f.name.get_name()) {
855                         Self::raise_hh_error(
856                             env,
857                             Naming::fd_name_already_bound(f.name.get_pos().clone()),
858                         );
859                     }
860                 }
862                 Ok(Hshape(ast::NastShapeInfo {
863                     allows_unknown_fields,
864                     field_map,
865                 }))
866             }
867             TupleTypeSpecifier(c) => Ok(Htuple(Self::could_map(Self::p_hint, &c.types, env)?)),
868             UnionTypeSpecifier(c) => Ok(Hunion(Self::could_map(&Self::p_hint, &c.types, env)?)),
869             IntersectionTypeSpecifier(c) => Ok(Hintersection(Self::could_map(
870                 &Self::p_hint,
871                 &c.types,
872                 env,
873             )?)),
874             KeysetTypeSpecifier(c) => Ok(Happly(
875                 Self::pos_name(&c.keyword, env)?,
876                 Self::could_map(Self::p_hint, &c.type_, env)?,
877             )),
878             VectorTypeSpecifier(c) => unary(&c.keyword, &c.type_, env),
879             ClassnameTypeSpecifier(c) => unary(&c.keyword, &c.type_, env),
880             TupleTypeExplicitSpecifier(c) => unary(&c.keyword, &c.types, env),
881             VarrayTypeSpecifier(c) => unary(&c.keyword, &c.type_, env),
882             DarrayTypeSpecifier(c) => binary(&c.keyword, &c.key, &c.value, env),
883             DictionaryTypeSpecifier(c) => unary(&c.keyword, &c.members, env),
884             GenericTypeSpecifier(c) => {
885                 let name = Self::pos_name(&c.class_type, env)?;
886                 let args = &c.argument_list;
887                 let type_args = match &args.children {
888                     TypeArguments(c) => Self::could_map(Self::p_hint, &c.types, env)?,
889                     _ => Self::missing_syntax("generic type arguments", args, env)?,
890                 };
891                 if env.codegen() {
892                     let process = |name: ast::Sid, mut args: Vec<ast::Hint>| -> ast::Hint_ {
893                         if args.len() == 1 {
894                             let eq = |s| name.1.eq_ignore_ascii_case(s);
895                             if (args[0].1.is_hfun()
896                                 && (eq(rx::RX)
897                                     || eq(rx::RX_LOCAL)
898                                     || eq(rx::RX_SHALLOW)
899                                     || eq(rx::PURE)))
900                                 || (args[0].1.is_happly()
901                                     && (eq(rx::MUTABLE)
902                                         || eq(rx::MAYBE_MUTABLE)
903                                         || eq(rx::OWNED_MUTABLE)))
904                             {
905                                 return *args.pop().unwrap().1;
906                             }
907                         }
908                         Happly(name, args)
909                     };
910                     Ok(process(name, type_args))
911                 } else {
912                     Ok(Happly(name, type_args))
913                 }
914             }
915             NullableTypeSpecifier(c) => Ok(Hoption(Self::p_hint(&c.type_, env)?)),
916             LikeTypeSpecifier(c) => Ok(Hlike(Self::p_hint(&c.type_, env)?)),
917             SoftTypeSpecifier(c) => Ok(Hsoft(Self::p_hint(&c.type_, env)?)),
918             ClosureTypeSpecifier(c) => {
919                 let (param_list, variadic_hints): (Vec<S<'a, T, V>>, Vec<S<'a, T, V>>) = c
920                     .parameter_list
921                     .syntax_node_to_list_skip_separator()
922                     .partition(|n| match &n.children {
923                         VariadicParameter(_) => false,
924                         _ => true,
925                     });
926                 let (type_hints, kinds) = param_list
927                     .iter()
928                     .map(|p| Self::p_closure_parameter(p, env))
929                     .collect::<std::result::Result<Vec<_>, _>>()?
930                     .into_iter()
931                     .unzip();
932                 let variadic_hints = variadic_hints
933                     .iter()
934                     .map(|v| match &v.children {
935                         VariadicParameter(c) => {
936                             if c.type_.is_missing() {
937                                 Self::raise_parsing_error(
938                                     v,
939                                     env,
940                                     "Cannot use ... without a typehint",
941                                 );
942                             }
943                             Ok(Some(Self::p_hint(&c.type_, env)?))
944                         }
945                         _ => panic!("expect variadic parameter"),
946                     })
947                     .collect::<std::result::Result<Vec<_>, _>>()?;
948                 if variadic_hints.len() > 1 {
949                     return Self::failwith(format!(
950                         "{} variadic parameters found. There should be no more than one.",
951                         variadic_hints.len().to_string()
952                     ));
953                 }
954                 let (cap, _) = Self::p_capability(&c.capability, env)?;
955                 Ok(Hfun(ast::HintFun {
956                     reactive_kind: ast::FuncReactive::FNonreactive,
957                     param_tys: type_hints,
958                     param_kinds: kinds,
959                     param_mutability: vec![],
960                     variadic_ty: variadic_hints.into_iter().next().unwrap_or(None),
961                     cap,
962                     return_ty: Self::p_hint(&c.return_type, env)?,
963                     is_mutable_return: true,
964                 }))
965             }
966             AttributizedSpecifier(c) => {
967                 let attrs = Self::p_user_attribute(&c.attribute_spec, env)?;
968                 let hint = Self::p_hint(&c.type_, env)?;
969                 if attrs.iter().any(|attr| attr.name.1 != special_attrs::SOFT) {
970                     Self::raise_parsing_error(node, env, &syntax_error::only_soft_allowed);
971                 }
972                 Ok(*Self::soften_hint(&attrs, hint).1)
973             }
974             TypeConstant(c) => {
975                 let child = Self::pos_name(&c.right_type, env)?;
976                 match Self::p_hint_(&c.left_type, env)? {
977                     Haccess(root, mut cs) => {
978                         cs.push(child);
979                         Ok(Haccess(root, cs))
980                     }
981                     Happly(ty, param) => {
982                         if param.is_empty() {
983                             let root = ast::Hint::new(ty.0.clone(), Happly(ty, param));
984                             Ok(Haccess(root, vec![child]))
985                         } else {
986                             Self::missing_syntax("type constant base", node, env)
987                         }
988                     }
989                     _ => Self::missing_syntax("type constant base", node, env),
990                 }
991             }
992             ReifiedTypeArgument(_) => {
993                 Self::raise_parsing_error(node, env, &syntax_error::invalid_reified);
994                 Self::missing_syntax("refied type", node, env)
995             }
996             _ => Self::missing_syntax("type hint", node, env),
997         }
998     }
1000     fn p_hint(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Hint> {
1001         let hint_ = Self::p_hint_(node, env)?;
1002         let pos = Self::p_pos(node, env);
1003         let hint = ast::Hint::new(pos, hint_);
1004         Self::check_valid_reified_hint(env, node, &hint);
1005         Ok(hint)
1006     }
1008     fn p_simple_initializer(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Expr> {
1009         match &node.children {
1010             SimpleInitializer(c) => Self::p_expr(&c.value, env),
1011             _ => Self::missing_syntax("simple initializer", node, env),
1012         }
1013     }
1015     fn p_member(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<(ast::Expr, ast::Expr)> {
1016         match &node.children {
1017             ElementInitializer(c) => Ok((Self::p_expr(&c.key, env)?, Self::p_expr(&c.value, env)?)),
1018             _ => Self::missing_syntax("darray intrinsic expression element", node, env),
1019         }
1020     }
1022     fn expand_type_args(ty: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Vec<ast::Hint>> {
1023         match &ty.children {
1024             TypeArguments(c) => Self::could_map(Self::p_hint, &c.types, env),
1025             _ => Ok(vec![]),
1026         }
1027     }
1029     fn p_afield(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Afield> {
1030         match &node.children {
1031             ElementInitializer(c) => Ok(ast::Afield::AFkvalue(
1032                 Self::p_expr(&c.key, env)?,
1033                 Self::p_expr(&c.value, env)?,
1034             )),
1035             _ => Ok(ast::Afield::AFvalue(Self::p_expr(node, env)?)),
1036         }
1037     }
1039     fn check_intrinsic_type_arg_varity(
1040         node: S<'a, T, V>,
1041         env: &mut Env<'a, TF>,
1042         tys: Vec<ast::Hint>,
1043     ) -> Option<ast::CollectionTarg> {
1044         let count = tys.len();
1045         let mut tys = tys.into_iter();
1046         match count {
1047             2 => Some(ast::CollectionTarg::CollectionTKV(
1048                 ast::Targ((), tys.next().unwrap()),
1049                 ast::Targ((), tys.next().unwrap()),
1050             )),
1051             1 => Some(ast::CollectionTarg::CollectionTV(ast::Targ(
1052                 (),
1053                 tys.next().unwrap(),
1054             ))),
1055             0 => None,
1056             _ => {
1057                 Self::raise_parsing_error(
1058                     node,
1059                     env,
1060                     &syntax_error::collection_intrinsic_many_typeargs,
1061                 );
1062                 None
1063             }
1064         }
1065     }
1067     fn p_import_flavor(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::ImportFlavor> {
1068         use ast::ImportFlavor::*;
1069         match Self::token_kind(node) {
1070             Some(TK::Include) => Ok(Include),
1071             Some(TK::Require) => Ok(Require),
1072             Some(TK::Include_once) => Ok(IncludeOnce),
1073             Some(TK::Require_once) => Ok(RequireOnce),
1074             _ => Self::missing_syntax("import flavor", node, env),
1075         }
1076     }
1078     fn p_null_flavor(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::OgNullFlavor> {
1079         use ast::OgNullFlavor::*;
1080         match Self::token_kind(node) {
1081             Some(TK::QuestionMinusGreaterThan) => Ok(OGNullsafe),
1082             Some(TK::MinusGreaterThan) => Ok(OGNullthrows),
1083             _ => Self::missing_syntax("null flavor", node, env),
1084         }
1085     }
1087     fn wrap_unescaper<F>(unescaper: F, s: &str) -> Result<BString>
1088     where
1089         F: FnOnce(&str) -> std::result::Result<BString, InvalidString>,
1090     {
1091         unescaper(s).map_err(|e| Error::Failwith(e.msg))
1092     }
1094     fn fail_if_invalid_class_creation(
1095         node: S<'a, T, V>,
1096         env: &mut Env<'a, TF>,
1097         id: impl AsRef<str>,
1098     ) {
1099         let id = id.as_ref();
1100         let is_in_static_method = *env.in_static_method();
1101         if is_in_static_method
1102             && ((id == special_classes::SELF && !env.cls_reified_generics().is_empty())
1103                 || (id == special_classes::PARENT && *env.parent_maybe_reified()))
1104         {
1105             Self::raise_parsing_error(node, env, &syntax_error::static_method_reified_obj_creation);
1106         }
1107     }
1109     fn fail_if_invalid_reified_generic(
1110         node: S<'a, T, V>,
1111         env: &mut Env<'a, TF>,
1112         id: impl AsRef<str>,
1113     ) {
1114         let is_in_static_method = *env.in_static_method();
1115         if is_in_static_method && env.cls_reified_generics().contains(id.as_ref()) {
1116             Self::raise_parsing_error(
1117                 node,
1118                 env,
1119                 &syntax_error::cls_reified_generic_in_static_method,
1120             );
1121         }
1122     }
1124     fn rfind(s: &[u8], mut i: usize, c: u8) -> Result<usize> {
1125         if i >= s.len() {
1126             return Self::failwith("index out of range");
1127         }
1128         i += 1;
1129         while i > 0 {
1130             i -= 1;
1131             if s[i] == c {
1132                 return Ok(i);
1133             }
1134         }
1135         Self::failwith("char not found")
1136     }
1138     fn prep_string2(
1139         nodes: &'a [Syntax<'a, T, V>],
1140         env: &mut Env<'a, TF>,
1141     ) -> Result<(TokenOp, TokenOp)> {
1142         use TokenOp::*;
1143         let is_qoute = |c| c == b'\"' || c == b'`';
1144         let start_is_qoute = |s: &[u8]| {
1145             (s.len() > 0 && is_qoute(s[0])) || (s.len() > 1 && (s[0] == b'b' && s[1] == b'\"'))
1146         };
1147         let last_is_qoute = |s: &[u8]| s.len() > 0 && is_qoute(s[s.len() - 1]);
1148         let is_heredoc = |s: &[u8]| (s.len() > 3 && &s[0..3] == b"<<<");
1149         let mut nodes = nodes.iter();
1150         let first = nodes.next();
1151         match first.map(|n| &n.children) {
1152             Some(Token(t)) => {
1153                 let raise = |env| {
1154                     Self::raise_parsing_error(first.unwrap(), env, "Malformed String2 SyntaxList");
1155                 };
1156                 let text = t.text_raw(env.source_text());
1157                 if start_is_qoute(text) {
1158                     let first_token_op = match text[0] {
1159                         b'b' if text.len() > 2 => LeftTrim(2),
1160                         _ if is_qoute(text[0]) && text.len() > 1 => LeftTrim(1),
1161                         _ => Skip,
1162                     };
1163                     if let Some(Token(t)) = nodes.last().map(|n| &n.children) {
1164                         let last_text = t.text_raw(env.source_text());
1165                         if last_is_qoute(last_text) {
1166                             let last_taken_op = match last_text.len() {
1167                                 n if n > 1 => RightTrim(1),
1168                                 _ => Skip,
1169                             };
1170                             return Ok((first_token_op, last_taken_op));
1171                         }
1172                     }
1173                     raise(env);
1174                     Ok((first_token_op, Noop))
1175                 } else if is_heredoc(text) {
1176                     let trim_size = text
1177                         .iter()
1178                         .position(|c| *c == b'\n')
1179                         .ok_or_else(|| Error::Failwith(String::from("newline not found")))?
1180                         + 1;
1181                     let first_token_op = match trim_size {
1182                         _ if trim_size == text.len() => Skip,
1183                         _ => LeftTrim(trim_size),
1184                     };
1185                     if let Some(Token(t)) = nodes.last().map(|n| &n.children) {
1186                         let text = t.text_raw(env.source_text());
1187                         let len = text.len();
1188                         if len != 0 {
1189                             let n = Self::rfind(text, len - 2, b'\n')?;
1190                             let last_token_op = match n {
1191                                 0 => Skip,
1192                                 _ => RightTrim(len - n),
1193                             };
1194                             return Ok((first_token_op, last_token_op));
1195                         }
1196                     }
1197                     raise(env);
1198                     Ok((first_token_op, Noop))
1199                 } else {
1200                     Ok((Noop, Noop))
1201                 }
1202             }
1203             _ => Ok((Noop, Noop)),
1204         }
1205     }
1207     fn process_token_op(
1208         env: &mut Env<'a, TF>,
1209         op: TokenOp,
1210         node: S<'a, T, V>,
1211     ) -> Result<Option<S<'a, T, V>>> {
1212         use TokenOp::*;
1213         match op {
1214             LeftTrim(n) => match &node.children {
1215                 Token(t) => {
1216                     let token = env.token_factory.trim_left(t, n);
1217                     let node = env.arena.alloc(<Syntax<'a, T, V>>::make_token(token));
1218                     Ok(Some(node))
1219                 }
1220                 _ => Self::failwith("Token expected"),
1221             },
1222             RightTrim(n) => match &node.children {
1223                 Token(t) => {
1224                     let token = env.token_factory.trim_right(t, n);
1225                     let node = env.arena.alloc(<Syntax<'a, T, V>>::make_token(token));
1226                     Ok(Some(node))
1227                 }
1228                 _ => Self::failwith("Token expected"),
1229             },
1230             _ => Ok(None),
1231         }
1232     }
1234     fn p_string2(nodes: &'a [Syntax<'a, T, V>], env: &mut Env<'a, TF>) -> Result<Vec<ast::Expr>> {
1235         use TokenOp::*;
1236         let (head_op, tail_op) = Self::prep_string2(nodes, env)?;
1237         let mut result = Vec::with_capacity(nodes.len());
1238         let mut i = 0;
1239         let last = nodes.len() - 1;
1240         while i <= last {
1241             let op = match i {
1242                 0 => head_op,
1243                 _ if i == last => tail_op,
1244                 _ => Noop,
1245             };
1247             if op == Skip {
1248                 i += 1;
1249                 continue;
1250             }
1252             let node = Self::process_token_op(env, op, &nodes[i])?;
1253             let node = node.unwrap_or(&nodes[i]);
1255             if Self::token_kind(node) == Some(TK::Dollar) && i < last {
1256                 if let EmbeddedBracedExpression(_) = &nodes[i + 1].children {
1257                     Self::raise_parsing_error(
1258                         &nodes[i + 1],
1259                         env,
1260                         &syntax_error::outside_dollar_str_interp,
1261                     );
1263                     result.push(Self::p_expr_with_loc(
1264                         ExprLocation::InDoubleQuotedString,
1265                         &nodes[i + 1],
1266                         env,
1267                     )?);
1268                     i += 2;
1269                     continue;
1270                 }
1271             }
1273             result.push(Self::p_expr_with_loc(
1274                 ExprLocation::InDoubleQuotedString,
1275                 node,
1276                 env,
1277             )?);
1278             i += 1;
1279         }
1280         Ok(result)
1281     }
1283     fn p_expr_l(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Vec<ast::Expr>> {
1284         let p_expr = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::Expr> {
1285             Self::p_expr_with_loc(ExprLocation::TopLevel, n, e)
1286         };
1287         Self::could_map(p_expr, node, env)
1288     }
1290     fn p_expr(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Expr> {
1291         Self::p_expr_with_loc(ExprLocation::TopLevel, node, env)
1292     }
1294     fn p_expr_with_loc(
1295         location: ExprLocation,
1296         node: S<'a, T, V>,
1297         env: &mut Env<'a, TF>,
1298     ) -> Result<ast::Expr> {
1299         Self::p_expr_impl(location, node, env, None)
1300     }
1302     fn p_expr_impl(
1303         location: ExprLocation,
1304         node: S<'a, T, V>,
1305         env: &mut Env<'a, TF>,
1306         parent_pos: Option<Pos>,
1307     ) -> Result<ast::Expr> {
1308         match &node.children {
1309             BracedExpression(c) => {
1310                 // Either a dynamic method lookup on a dynamic value:
1311                 //   $foo->{$meth_name}();
1312                 // or an XHP splice.
1313                 //   <p id={$id}>hello</p>;
1314                 // In both cases, unwrap, consistent with parentheses.
1315                 Self::p_expr_impl(location, &c.expression, env, parent_pos)
1316             }
1317             ParenthesizedExpression(c) => {
1318                 Self::p_expr_impl(location, &c.expression, env, parent_pos)
1319             }
1320             _ => {
1321                 let pos = Self::p_pos(node, env);
1322                 let expr_ = Self::p_expr_impl_(location, node, env, parent_pos)?;
1323                 Ok(ast::Expr::new(pos, expr_))
1324             }
1325         }
1326     }
1328     fn p_expr_lit(
1329         location: ExprLocation,
1330         parent: S<'a, T, V>,
1331         expr: S<'a, T, V>,
1332         env: &mut Env<'a, TF>,
1333     ) -> Result<ast::Expr_> {
1334         match &expr.children {
1335             Token(_) => {
1336                 let s = expr.text(env.indexed_source_text.source_text());
1337                 let check_lint_err = |e: &mut Env<'a, TF>, s: &str, expected: &str| {
1338                     if !e.codegen() && s != expected {
1339                         Self::raise_lint_error(
1340                             e,
1341                             LintError::lowercase_constant(Self::p_pos(expr, e), s),
1342                         );
1343                     }
1344                 };
1345                 match (location, Self::token_kind(expr)) {
1346                     (ExprLocation::InDoubleQuotedString, _) if env.codegen() => {
1347                         Ok(E_::String(Self::mk_str(expr, env, Self::unesc_dbl, s)))
1348                     }
1349                     (_, Some(TK::OctalLiteral))
1350                         if env.is_typechecker() && !Self::is_num_octal_lit(s) =>
1351                     {
1352                         Self::raise_parsing_error(
1353                             parent,
1354                             env,
1355                             &syntax_error::invalid_octal_integer,
1356                         );
1357                         Self::missing_syntax("octal", expr, env)
1358                     }
1359                     (_, Some(TK::DecimalLiteral))
1360                     | (_, Some(TK::OctalLiteral))
1361                     | (_, Some(TK::HexadecimalLiteral))
1362                     | (_, Some(TK::BinaryLiteral)) => Ok(E_::Int(s.replace("_", ""))),
1363                     (_, Some(TK::FloatingLiteral)) => Ok(E_::Float(String::from(s))),
1364                     (_, Some(TK::SingleQuotedStringLiteral)) => {
1365                         Ok(E_::String(Self::mk_str(expr, env, unescape_single, s)))
1366                     }
1367                     (_, Some(TK::DoubleQuotedStringLiteral)) => {
1368                         Ok(E_::String(Self::mk_str(expr, env, unescape_double, s)))
1369                     }
1370                     (_, Some(TK::HeredocStringLiteral)) => {
1371                         Ok(E_::String(Self::mk_str(expr, env, unescape_heredoc, s)))
1372                     }
1373                     (_, Some(TK::NowdocStringLiteral)) => {
1374                         Ok(E_::String(Self::mk_str(expr, env, unescape_nowdoc, s)))
1375                     }
1376                     (_, Some(TK::NullLiteral)) => {
1377                         check_lint_err(env, s, literal::NULL);
1378                         Ok(E_::Null)
1379                     }
1380                     (_, Some(TK::BooleanLiteral)) => {
1381                         if s.eq_ignore_ascii_case(literal::FALSE) {
1382                             check_lint_err(env, s, literal::FALSE);
1383                             Ok(E_::False)
1384                         } else if s.eq_ignore_ascii_case(literal::TRUE) {
1385                             check_lint_err(env, s, literal::TRUE);
1386                             Ok(E_::True)
1387                         } else {
1388                             Self::missing_syntax(&format!("boolean (not: {})", s), expr, env)
1389                         }
1390                     }
1391                     _ => Self::missing_syntax("literal", expr, env),
1392                 }
1393             }
1394             SyntaxList(ts) => Ok(E_::String2(Self::p_string2(ts, env)?)),
1395             _ => Self::missing_syntax("literal expressoin", expr, env),
1396         }
1397     }
1399     fn p_expr_with_loc_(
1400         location: ExprLocation,
1401         node: S<'a, T, V>,
1402         env: &mut Env<'a, TF>,
1403     ) -> Result<ast::Expr_> {
1404         Self::p_expr_impl_(location, node, env, None)
1405     }
1407     fn p_expr_impl_(
1408         location: ExprLocation,
1409         node: S<'a, T, V>,
1410         env: &mut Env<'a, TF>,
1411         parent_pos: Option<Pos>,
1412     ) -> Result<ast::Expr_> {
1413         if *env.exp_recursion_depth() >= EXP_RECUSION_LIMIT {
1414             Err(Error::Failwith("Expression recursion limit reached".into()))
1415         } else {
1416             *env.exp_recursion_depth() += 1;
1417             let r = Self::p_expr_impl__(location, node, env, parent_pos);
1418             *env.exp_recursion_depth() -= 1;
1419             r
1420         }
1421     }
1423     fn p_expr_impl__(
1424         location: ExprLocation,
1425         node: S<'a, T, V>,
1426         env: &mut Env<'a, TF>,
1427         parent_pos: Option<Pos>,
1428     ) -> Result<ast::Expr_> {
1429         env.check_stack_limit();
1430         use ast::Expr as E;
1431         let split_args_vararg = |
1432             arg_list_node: S<'a, T, V>,
1433             e: &mut Env<'a, TF>,
1434         | -> Result<(Vec<ast::Expr>, Option<ast::Expr>)> {
1435             let mut arg_list: Vec<_> = arg_list_node.syntax_node_to_list_skip_separator().collect();
1436             if let Some(last_arg) = arg_list.last() {
1437                 if let DecoratedExpression(c) = &last_arg.children {
1438                     if Self::token_kind(&c.decorator) == Some(TK::DotDotDot) {
1439                         let _ = arg_list.pop();
1440                         let args: std::result::Result<Vec<_>, _> =
1441                             arg_list.iter().map(|a| Self::p_expr(a, e)).collect();
1442                         let args = args?;
1443                         let vararg = Self::p_expr(&c.expression, e)?;
1444                         return Ok((args, Some(vararg)));
1445                     }
1446                 }
1447             }
1448             Ok((Self::could_map(Self::p_expr, arg_list_node, e)?, None))
1449         };
1450         let mk_lid = |p: Pos, s: String| ast::Lid(p, (0, s));
1451         let mk_name_lid = |name: S<'a, T, V>, env: &mut Env<'a, TF>| {
1452             let name = Self::pos_name(name, env)?;
1453             Ok(mk_lid(name.0, name.1))
1454         };
1455         let mk_lvar =
1456             |name: S<'a, T, V>, env: &mut Env<'a, TF>| Ok(E_::mk_lvar(mk_name_lid(name, env)?));
1457         let mk_id_expr = |name: ast::Sid| E::new(name.0.clone(), E_::mk_id(name));
1458         let p_intri_expr = |kw, ty, v, e: &mut Env<'a, TF>| {
1459             let hints = Self::expand_type_args(ty, e)?;
1460             let hints = Self::check_intrinsic_type_arg_varity(node, e, hints);
1461             Ok(E_::mk_collection(
1462                 Self::pos_name(kw, e)?,
1463                 hints,
1464                 Self::could_map(Self::p_afield, v, e)?,
1465             ))
1466         };
1467         let p_special_call =
1468             |recv: S<'a, T, V>, args: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::Expr_> {
1469                 let pos_if_has_parens = match &recv.children {
1470                     ParenthesizedExpression(_) => Some(Self::p_pos(recv, e)),
1471                     _ => None,
1472                 };
1473                 let recv = Self::p_expr(recv, e)?;
1474                 let recv = match (&recv.1, pos_if_has_parens) {
1475                     (E_::ObjGet(t), Some(ref _p)) => {
1476                         let (a, b, c, _false) = &**t;
1477                         E::new(
1478                             recv.0.clone(),
1479                             E_::mk_obj_get(a.clone(), b.clone(), c.clone(), true),
1480                         )
1481                     }
1482                     (E_::ClassGet(c), Some(ref _p)) => {
1483                         let (a, b, _false) = &**c;
1484                         E::new(recv.0.clone(), E_::mk_class_get(a.clone(), b.clone(), true))
1485                     }
1486                     _ => recv,
1487                 };
1488                 let (args, varargs) = split_args_vararg(args, e)?;
1489                 Ok(E_::mk_call(recv, vec![], args, varargs))
1490             };
1491         let p_obj_get = |
1492             recv: S<'a, T, V>,
1493             op: S<'a, T, V>,
1494             name: S<'a, T, V>,
1495             e: &mut Env<'a, TF>,
1496         | -> Result<ast::Expr_> {
1497             if recv.is_object_creation_expression() && !e.codegen() {
1498                 Self::raise_parsing_error(recv, e, &syntax_error::invalid_constructor_method_call);
1499             }
1500             let recv = Self::p_expr(recv, e)?;
1501             let name = Self::p_expr_with_loc(ExprLocation::MemberSelect, name, e)?;
1502             let op = Self::p_null_flavor(op, e)?;
1503             Ok(E_::mk_obj_get(recv, name, op, false))
1504         };
1505         let pos = match parent_pos {
1506             None => Self::p_pos(node, env),
1507             Some(p) => p,
1508         };
1509         match &node.children {
1510             LambdaExpression(c) => {
1511                 let suspension_kind = Self::mk_suspension_kind(&c.async_);
1512                 let (params, (capability, unsafe_capability), ret) = match &c.signature.children {
1513                     LambdaSignature(c) => (
1514                         Self::could_map(Self::p_fun_param, &c.parameters, env)?,
1515                         Self::p_capability(&c.capability, env)?,
1516                         Self::mp_optional(Self::p_hint, &c.type_, env)?,
1517                     ),
1518                     Token(_) => {
1519                         let ast::Id(p, n) = Self::pos_name(&c.signature, env)?;
1520                         (
1521                             vec![ast::FunParam {
1522                                 annotation: p.clone(),
1523                                 type_hint: ast::TypeHint((), None),
1524                                 is_variadic: false,
1525                                 pos: p,
1526                                 name: n,
1527                                 expr: None,
1528                                 callconv: None,
1529                                 user_attributes: vec![],
1530                                 visibility: None,
1531                             }],
1532                             (None, None),
1533                             None,
1534                         )
1535                     }
1536                     _ => Self::missing_syntax("lambda signature", &c.signature, env)?,
1537                 };
1538                 let (body, yield_) = if !c.body.is_compound_statement() {
1539                     Self::mp_yielding(Self::p_function_body, &c.body, env)?
1540                 } else {
1541                     let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
1542                     Self::mp_yielding(&Self::p_function_body, &c.body, env1.as_mut())?
1543                 };
1544                 let external = c.body.is_external();
1545                 let fun = ast::Fun_ {
1546                     span: pos.clone(),
1547                     annotation: (),
1548                     mode: env.file_mode(),
1549                     ret: ast::TypeHint((), ret),
1550                     name: ast::Id(pos, String::from(";anonymous")),
1551                     tparams: vec![],
1552                     where_constraints: vec![],
1553                     body: ast::FuncBody {
1554                         ast: body,
1555                         annotation: (),
1556                     },
1557                     fun_kind: Self::mk_fun_kind(suspension_kind, yield_),
1558                     variadic: Self::determine_variadicity(&params),
1559                     params,
1560                     cap: ast::TypeHint((), capability),
1561                     unsafe_cap: ast::TypeHint((), unsafe_capability),
1562                     user_attributes: Self::p_user_attributes(&c.attribute_spec, env)?,
1563                     file_attributes: vec![],
1564                     external,
1565                     namespace: Self::mk_empty_ns_env(env),
1566                     doc_comment: None,
1567                     static_: false,
1568                 };
1569                 Ok(E_::mk_lfun(fun, vec![]))
1570             }
1571             BracedExpression(c) => Self::p_expr_with_loc_(location, &c.expression, env),
1572             EmbeddedBracedExpression(c) => {
1573                 Self::p_expr_impl_(location, &c.expression, env, Some(pos))
1574             }
1575             ParenthesizedExpression(c) => Self::p_expr_with_loc_(location, &c.expression, env),
1576             DictionaryIntrinsicExpression(c) => {
1577                 p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env)
1578             }
1579             KeysetIntrinsicExpression(c) => {
1580                 p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env)
1581             }
1582             VectorIntrinsicExpression(c) => {
1583                 p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env)
1584             }
1585             CollectionLiteralExpression(c) => {
1586                 let (collection_name, hints) = match &c.name.children {
1587                     SimpleTypeSpecifier(c) => (Self::pos_name(&c.specifier, env)?, None),
1588                     GenericTypeSpecifier(c) => {
1589                         let hints = Self::expand_type_args(&c.argument_list, env)?;
1590                         let hints = Self::check_intrinsic_type_arg_varity(node, env, hints);
1591                         (Self::pos_name(&c.class_type, env)?, hints)
1592                     }
1593                     _ => (Self::pos_name(&c.name, env)?, None),
1594                 };
1595                 Ok(E_::mk_collection(
1596                     collection_name,
1597                     hints,
1598                     Self::could_map(Self::p_afield, &c.initializers, env)?,
1599                 ))
1600             }
1601             VarrayIntrinsicExpression(c) => {
1602                 let hints = Self::expand_type_args(&c.explicit_type, env)?;
1603                 let hints = Self::check_intrinsic_type_arg_varity(node, env, hints);
1604                 let targ = match hints {
1605                     Some(ast::CollectionTarg::CollectionTV(ty)) => Some(ty),
1606                     None => None,
1607                     _ => Self::missing_syntax("VarrayIntrinsicExpression type args", node, env)?,
1608                 };
1609                 Ok(E_::mk_varray(
1610                     targ,
1611                     Self::could_map(Self::p_expr, &c.members, env)?,
1612                 ))
1613             }
1614             DarrayIntrinsicExpression(c) => {
1615                 let hints = Self::expand_type_args(&c.explicit_type, env)?;
1616                 let hints = Self::check_intrinsic_type_arg_varity(node, env, hints);
1617                 match hints {
1618                     Some(ast::CollectionTarg::CollectionTKV(tk, tv)) => Ok(E_::mk_darray(
1619                         Some((tk, tv)),
1620                         Self::could_map(Self::p_member, &c.members, env)?,
1621                     )),
1622                     None => Ok(E_::mk_darray(
1623                         None,
1624                         Self::could_map(Self::p_member, &c.members, env)?,
1625                     )),
1626                     _ => Self::missing_syntax("DarrayIntrinsicExpression type args", node, env),
1627                 }
1628             }
1629             ListExpression(c) => {
1630                 /* TODO: Or tie in with other intrinsics and post-process to List */
1631                 let p_binder_or_ignore =
1632                     |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::Expr> {
1633                         match &n.children {
1634                             Missing => Ok(E::new(e.mk_none_pos(), E_::Omitted)),
1635                             _ => Self::p_expr(n, e),
1636                         }
1637                     };
1638                 Ok(E_::List(Self::could_map(
1639                     &p_binder_or_ignore,
1640                     &c.members,
1641                     env,
1642                 )?))
1643             }
1644             EvalExpression(c) => p_special_call(&c.keyword, &c.argument, env),
1645             IssetExpression(c) => p_special_call(&c.keyword, &c.argument_list, env),
1646             TupleExpression(c) => p_special_call(&c.keyword, &c.items, env),
1647             FunctionCallExpression(c) => {
1648                 let recv = &c.receiver;
1649                 let args = &c.argument_list;
1650                 let get_hhas_adata = || {
1651                     if Self::text_str(recv, env) == "__hhas_adata" {
1652                         if let SyntaxList(l) = &args.children {
1653                             if let Some(li) = l.first() {
1654                                 if let ListItem(i) = &li.children {
1655                                     if let LiteralExpression(le) = &i.item.children {
1656                                         let expr = &le.expression;
1657                                         if Self::token_kind(expr) == Some(TK::NowdocStringLiteral) {
1658                                             return Some(expr);
1659                                         }
1660                                     }
1661                                 }
1662                             }
1663                         }
1664                     }
1665                     None
1666                 };
1667                 match get_hhas_adata() {
1668                     Some(expr) => {
1669                         let literal_expression_pos = Self::p_pos(expr, env);
1670                         let s = extract_unquoted_string(Self::text_str(expr, env), 0, expr.width())
1671                             .map_err(|e| Error::Failwith(e.msg))?;
1672                         Ok(E_::mk_call(
1673                             Self::p_expr(recv, env)?,
1674                             vec![],
1675                             vec![E::new(literal_expression_pos, E_::String(s.into()))],
1676                             None,
1677                         ))
1678                     }
1679                     None => {
1680                         let targs = match (&recv.children, &c.type_args.children) {
1681                             (_, TypeArguments(c)) => Self::could_map(Self::p_targ, &c.types, env)?,
1682                             /* TODO might not be needed */
1683                             (GenericTypeSpecifier(c), _) => match &c.argument_list.children {
1684                                 TypeArguments(c) => Self::could_map(Self::p_targ, &c.types, env)?,
1685                                 _ => vec![],
1686                             },
1687                             _ => vec![],
1688                         };
1690                         /* preserve parens on receiver of call expression
1691                         to allow distinguishing between
1692                         ($a->b)() // invoke on callable property
1693                         $a->b()   // method call */
1694                         let pos_if_has_parens = match &recv.children {
1695                             ParenthesizedExpression(_) => Some(Self::p_pos(recv, env)),
1696                             _ => None,
1697                         };
1698                         let is_splice = Self::text_str(recv, env) == special_functions::SPLICE;
1699                         let recv = Self::p_expr(recv, env)?;
1700                         let recv = match (&recv.1, pos_if_has_parens) {
1701                             (E_::ObjGet(t), Some(ref _p)) => {
1702                                 let (a, b, c, _false) = &**t;
1703                                 E::new(
1704                                     recv.0.clone(),
1705                                     E_::mk_obj_get(a.clone(), b.clone(), c.clone(), true),
1706                                 )
1707                             }
1708                             (E_::ClassGet(c), Some(ref _p)) => {
1709                                 let (a, b, _false) = &**c;
1710                                 E::new(recv.0.clone(), E_::mk_class_get(a.clone(), b.clone(), true))
1711                             }
1712                             _ => recv,
1713                         };
1714                         let (args, varargs) = split_args_vararg(args, env)?;
1715                         if is_splice {
1716                             if args.len() == 1 && targs.len() == 0 && varargs == None {
1717                                 if let Some(e) = args.first() {
1718                                     return Ok(E_::mk_etsplice(e.to_owned()));
1719                                 }
1720                             }
1721                         }
1722                         Ok(E_::mk_call(recv, targs, args, varargs))
1723                     }
1724                 }
1725             }
1726             FunctionPointerExpression(c) => {
1727                 let targs = match &c.type_args.children {
1728                     TypeArguments(c) => Self::could_map(Self::p_targ, &c.types, env)?,
1729                     _ => vec![],
1730                 };
1732                 let recv = Self::p_expr(&c.receiver, env)?;
1734                 match &recv.1 {
1735                     aast::Expr_::Id(id) => Ok(E_::mk_function_pointer(
1736                         aast::FunctionPtrId::FPId(*(id.to_owned())),
1737                         targs,
1738                     )),
1739                     aast::Expr_::ClassConst(c) => {
1740                         if let aast::ClassId_::CIexpr(aast::Expr(_, aast::Expr_::Id(_))) = (c.0).1 {
1741                             Ok(E_::mk_function_pointer(
1742                                 aast::FunctionPtrId::FPClassConst(c.0.to_owned(), c.1.to_owned()),
1743                                 targs,
1744                             ))
1745                         } else {
1746                             Self::raise_parsing_error(
1747                                 node,
1748                                 env,
1749                                 &syntax_error::function_pointer_bad_recv,
1750                             );
1751                             Self::missing_syntax("function or static method", node, env)
1752                         }
1753                     }
1754                     _ => {
1755                         Self::raise_parsing_error(
1756                             node,
1757                             env,
1758                             &syntax_error::function_pointer_bad_recv,
1759                         );
1760                         Self::missing_syntax("function or static method", node, env)
1761                     }
1762                 }
1763             }
1764             QualifiedName(_) => match location {
1765                 ExprLocation::InDoubleQuotedString => {
1766                     let ast::Id(_, n) = Self::pos_qualified_name(node, env)?;
1767                     Ok(E_::String(n.into()))
1768                 }
1769                 _ => Ok(E_::mk_id(Self::pos_qualified_name(node, env)?)),
1770             },
1771             VariableExpression(c) => Ok(E_::mk_lvar(Self::lid_from_pos_name(
1772                 pos,
1773                 &c.expression,
1774                 env,
1775             )?)),
1776             PipeVariableExpression(_) => Ok(E_::mk_lvar(mk_lid(
1777                 pos,
1778                 special_idents::DOLLAR_DOLLAR.into(),
1779             ))),
1780             InclusionExpression(c) => Ok(E_::mk_import(
1781                 Self::p_import_flavor(&c.require, env)?,
1782                 Self::p_expr(&c.filename, env)?,
1783             )),
1784             MemberSelectionExpression(c) => p_obj_get(&c.object, &c.operator, &c.name, env),
1785             SafeMemberSelectionExpression(c) => p_obj_get(&c.object, &c.operator, &c.name, env),
1786             EmbeddedMemberSelectionExpression(c) => p_obj_get(&c.object, &c.operator, &c.name, env),
1787             PrefixUnaryExpression(_) | PostfixUnaryExpression(_) | DecoratedExpression(_) => {
1788                 let (operand, op, postfix) = match &node.children {
1789                     PrefixUnaryExpression(c) => (&c.operand, &c.operator, false),
1790                     PostfixUnaryExpression(c) => (&c.operand, &c.operator, true),
1791                     DecoratedExpression(c) => (&c.expression, &c.decorator, false),
1792                     _ => Self::missing_syntax("unary exppr", node, env)?,
1793                 };
1795                 /**
1796                  * FFP does not destinguish between ++$i and $i++ on the level of token
1797                  * kind annotation. Prevent duplication by switching on `postfix` for
1798                  * the two operatores for which AST /does/ differentiate between
1799                  * fixities.
1800                  */
1801                 use ast::Uop::*;
1802                 let mk_unop = |op, e| Ok(E_::mk_unop(op, e));
1803                 let op_kind = Self::token_kind(op);
1804                 if let Some(TK::At) = op_kind {
1805                     if env.parser_options.po_disallow_silence {
1806                         Self::raise_parsing_error(op, env, &syntax_error::no_silence);
1807                     }
1808                     if env.codegen() {
1809                         let expr = Self::p_expr(operand, env)?;
1810                         mk_unop(Usilence, expr)
1811                     } else {
1812                         let expr =
1813                             Self::p_expr_impl(ExprLocation::TopLevel, operand, env, Some(pos))?;
1814                         Ok(expr.1)
1815                     }
1816                 } else {
1817                     let expr = Self::p_expr(operand, env)?;
1818                     match op_kind {
1819                         Some(TK::PlusPlus) if postfix => mk_unop(Upincr, expr),
1820                         Some(TK::MinusMinus) if postfix => mk_unop(Updecr, expr),
1821                         Some(TK::PlusPlus) => mk_unop(Uincr, expr),
1822                         Some(TK::MinusMinus) => mk_unop(Udecr, expr),
1823                         Some(TK::Exclamation) => mk_unop(Unot, expr),
1824                         Some(TK::Tilde) => mk_unop(Utild, expr),
1825                         Some(TK::Plus) => mk_unop(Uplus, expr),
1826                         Some(TK::Minus) => mk_unop(Uminus, expr),
1827                         Some(TK::Inout) => Ok(E_::mk_callconv(ast::ParamKind::Pinout, expr)),
1828                         Some(TK::Await) => Self::lift_await(pos, expr, env, location),
1829                         Some(TK::Clone) => Ok(E_::mk_clone(expr)),
1830                         Some(TK::Print) => Ok(E_::mk_call(
1831                             E::new(
1832                                 pos.clone(),
1833                                 E_::mk_id(ast::Id(pos, special_functions::ECHO.into())),
1834                             ),
1835                             vec![],
1836                             vec![expr],
1837                             None,
1838                         )),
1839                         Some(TK::Dollar) => {
1840                             Self::raise_parsing_error(
1841                                 op,
1842                                 env,
1843                                 &syntax_error::invalid_variable_name,
1844                             );
1845                             Ok(E_::Omitted)
1846                         }
1847                         _ => Self::missing_syntax("unary operator", node, env),
1848                     }
1849                 }
1850             }
1851             BinaryExpression(c) => {
1852                 use ExprLocation::*;
1853                 let rlocation = if Self::token_kind(&c.operator) == Some(TK::Equal) {
1854                     match location {
1855                         AsStatement => RightOfAssignment,
1856                         UsingStatement => RightOfAssignmentInUsingStatement,
1857                         _ => TopLevel,
1858                     }
1859                 } else {
1860                     TopLevel
1861                 };
1862                 let bop_ast_node = Self::p_bop(
1863                     pos,
1864                     &c.operator,
1865                     Self::p_expr(&c.left_operand, env)?,
1866                     Self::p_expr_with_loc(rlocation, &c.right_operand, env)?,
1867                     env,
1868                 )?;
1869                 if let Some((ast::Bop::Eq(_), lhs, _)) = bop_ast_node.as_binop() {
1870                     Self::check_lvalue(lhs, env);
1871                 }
1872                 Ok(bop_ast_node)
1873             }
1874             Token(t) => {
1875                 use ExprLocation::*;
1876                 match (location, t.kind()) {
1877                     (MemberSelect, TK::Variable) => mk_lvar(node, env),
1878                     (InDoubleQuotedString, TK::HeredocStringLiteral)
1879                     | (InDoubleQuotedString, TK::HeredocStringLiteralHead)
1880                     | (InDoubleQuotedString, TK::HeredocStringLiteralTail) => Ok(E_::String(
1881                         Self::wrap_unescaper(unescape_heredoc, Self::text_str(node, env))?,
1882                     )),
1883                     (InDoubleQuotedString, _) => Ok(E_::String(Self::wrap_unescaper(
1884                         Self::unesc_dbl,
1885                         Self::text_str(node, env),
1886                     )?)),
1887                     (MemberSelect, _)
1888                     | (TopLevel, _)
1889                     | (AsStatement, _)
1890                     | (UsingStatement, _)
1891                     | (RightOfAssignment, _)
1892                     | (RightOfAssignmentInUsingStatement, _)
1893                     | (RightOfReturn, _) => Ok(E_::mk_id(Self::pos_name(node, env)?)),
1894                 }
1895             }
1896             YieldExpression(c) => {
1897                 use ExprLocation::*;
1898                 env.saw_yield = true;
1899                 if location != AsStatement
1900                     && location != RightOfAssignment
1901                     && location != RightOfAssignmentInUsingStatement
1902                 {
1903                     Self::raise_parsing_error(node, env, &syntax_error::invalid_yield);
1904                 }
1905                 if Self::text_str(&c.operand, env) == "break" {
1906                     Ok(E_::YieldBreak)
1907                 } else if c.operand.is_missing() {
1908                     Ok(E_::mk_yield(ast::Afield::AFvalue(E::new(pos, E_::Null))))
1909                 } else {
1910                     Ok(E_::mk_yield(Self::p_afield(&c.operand, env)?))
1911                 }
1912             }
1913             DefineExpression(c) => {
1914                 let name = Self::pos_name(&c.keyword, env)?;
1915                 Ok(E_::mk_call(
1916                     mk_id_expr(name),
1917                     vec![],
1918                     c.argument_list
1919                         .syntax_node_to_list_skip_separator()
1920                         .map(|x| Self::p_expr(x, env))
1921                         .collect::<std::result::Result<Vec<_>, _>>()?,
1922                     None,
1923                 ))
1924             }
1925             ScopeResolutionExpression(c) => {
1926                 let qual = Self::p_expr(&c.qualifier, env)?;
1927                 if let E_::Id(id) = &qual.1 {
1928                     Self::fail_if_invalid_reified_generic(node, env, &id.1);
1929                 }
1930                 match &c.name.children {
1931                     Token(token) if token.kind() == TK::Variable => {
1932                         let ast::Id(p, name) = Self::pos_name(&c.name, env)?;
1933                         Ok(E_::mk_class_get(
1934                             ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
1935                             ast::ClassGetExpr::CGstring((p, name)),
1936                             false,
1937                         ))
1938                     }
1939                     _ => {
1940                         let E(p, expr_) = Self::p_expr(&c.name, env)?;
1941                         match expr_ {
1942                             E_::String(id) => Ok(E_::mk_class_const(
1943                                 ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
1944                                 (
1945                                     p,
1946                                     String::from_utf8(id.into())
1947                                         .map_err(|e| Error::Failwith(e.to_string()))?,
1948                                 ),
1949                             )),
1950                             E_::Id(id) => {
1951                                 let ast::Id(p, n) = *id;
1952                                 Ok(E_::mk_class_const(
1953                                     ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
1954                                     (p, n),
1955                                 ))
1956                             }
1957                             E_::Lvar(id) => {
1958                                 let ast::Lid(p, (_, n)) = *id;
1959                                 Ok(E_::mk_class_get(
1960                                     ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
1961                                     ast::ClassGetExpr::CGstring((p, n)),
1962                                     false,
1963                                 ))
1964                             }
1965                             _ => Ok(E_::mk_class_get(
1966                                 ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
1967                                 ast::ClassGetExpr::CGexpr(E(p, expr_)),
1968                                 false,
1969                             )),
1970                         }
1971                     }
1972                 }
1973             }
1974             CastExpression(c) => Ok(E_::mk_cast(
1975                 Self::p_hint(&c.type_, env)?,
1976                 Self::p_expr(&c.operand, env)?,
1977             )),
1978             PrefixedCodeExpression(c) => {
1979                 let src_expr = Self::p_expr(&c.expression, env)?;
1980                 let hint = Self::p_hint(&c.prefix, env)?;
1981                 let desugared_expr = desugar(&hint, &src_expr, env);
1982                 Ok(E_::mk_expression_tree(ast::ExpressionTree {
1983                     hint,
1984                     src_expr,
1985                     desugared_expr,
1986                 }))
1987             }
1988             ConditionalExpression(c) => {
1989                 let alter = Self::p_expr(&c.alternative, env)?;
1990                 let consequence = Self::mp_optional(Self::p_expr, &c.consequence, env)?;
1991                 let condition = Self::p_expr(&c.test, env)?;
1992                 Ok(E_::mk_eif(condition, consequence, alter))
1993             }
1994             SubscriptExpression(c) => Ok(E_::mk_array_get(
1995                 Self::p_expr(&c.receiver, env)?,
1996                 Self::mp_optional(Self::p_expr, &c.index, env)?,
1997             )),
1998             EmbeddedSubscriptExpression(c) => Ok(E_::mk_array_get(
1999                 Self::p_expr(&c.receiver, env)?,
2000                 Self::mp_optional(|n, e| Self::p_expr_with_loc(location, n, e), &c.index, env)?,
2001             )),
2002             ShapeExpression(c) => Ok(E_::Shape(Self::could_map(
2003                 |n: S<'a, T, V>, e: &mut Env<'a, TF>| {
2004                     Self::mp_shape_expression_field(&Self::p_expr, n, e)
2005                 },
2006                 &c.fields,
2007                 env,
2008             )?)),
2009             ObjectCreationExpression(c) => Self::p_expr_impl_(location, &c.object, env, Some(pos)),
2010             ConstructorCall(c) => {
2011                 let (args, varargs) = split_args_vararg(&c.argument_list, env)?;
2012                 let (e, hl) = match &c.type_.children {
2013                     GenericTypeSpecifier(c) => {
2014                         let name = Self::pos_name(&c.class_type, env)?;
2015                         let hints = match &c.argument_list.children {
2016                             TypeArguments(c) => Self::could_map(Self::p_targ, &c.types, env)?,
2017                             _ => Self::missing_syntax(
2018                                 "generic type arguments",
2019                                 &c.argument_list,
2020                                 env,
2021                             )?,
2022                         };
2023                         (mk_id_expr(name), hints)
2024                     }
2025                     SimpleTypeSpecifier(_) => {
2026                         let name = Self::pos_name(&c.type_, env)?;
2027                         (mk_id_expr(name), vec![])
2028                     }
2029                     _ => (Self::p_expr(&c.type_, env)?, vec![]),
2030                 };
2031                 if let E_::Id(name) = &e.1 {
2032                     Self::fail_if_invalid_reified_generic(node, env, &name.1);
2033                     Self::fail_if_invalid_class_creation(node, env, &name.1);
2034                 }
2035                 Ok(E_::mk_new(
2036                     ast::ClassId(pos.clone(), ast::ClassId_::CIexpr(e)),
2037                     hl,
2038                     args,
2039                     varargs,
2040                     pos,
2041                 ))
2042             }
2043             GenericTypeSpecifier(c) => {
2044                 if !c.argument_list.is_missing() {
2045                     Self::raise_parsing_error(
2046                         &c.argument_list,
2047                         env,
2048                         &syntax_error::targs_not_allowed,
2049                     )
2050                 }
2051                 Ok(E_::mk_id(Self::pos_name(&c.class_type, env)?))
2052             }
2053             RecordCreationExpression(c) => {
2054                 let id = Self::pos_name(&c.type_, env)?;
2055                 Ok(E_::mk_record(
2056                     id,
2057                     Self::could_map(Self::p_member, &c.members, env)?,
2058                 ))
2059             }
2060             LiteralExpression(c) => Self::p_expr_lit(location, node, &c.expression, env),
2061             PrefixedStringExpression(c) => {
2062                 /* Temporarily allow only`re`- prefixed strings */
2063                 let name_text = Self::text(&c.name, env);
2064                 if name_text != "re" {
2065                     Self::raise_parsing_error(node, env, &syntax_error::non_re_prefix);
2066                 }
2067                 Ok(E_::mk_prefixed_string(
2068                     name_text,
2069                     Self::p_expr(&c.str, env)?,
2070                 ))
2071             }
2072             IsExpression(c) => Ok(E_::mk_is(
2073                 Self::p_expr(&c.left_operand, env)?,
2074                 Self::p_hint(&c.right_operand, env)?,
2075             )),
2076             AsExpression(c) => Ok(E_::mk_as(
2077                 Self::p_expr(&c.left_operand, env)?,
2078                 Self::p_hint(&c.right_operand, env)?,
2079                 false,
2080             )),
2081             NullableAsExpression(c) => Ok(E_::mk_as(
2082                 Self::p_expr(&c.left_operand, env)?,
2083                 Self::p_hint(&c.right_operand, env)?,
2084                 true,
2085             )),
2086             AnonymousFunction(c) => {
2087                 if env.parser_options.po_disable_static_closures
2088                     && Self::token_kind(&c.static_keyword) == Some(TK::Static)
2089                 {
2090                     Self::raise_parsing_error(
2091                         node,
2092                         env,
2093                         &syntax_error::static_closures_are_disabled,
2094                     );
2095                 }
2096                 let p_arg = |n: S<'a, T, V>, e: &mut Env<'a, TF>| match &n.children {
2097                     Token(_) => mk_name_lid(n, e),
2098                     _ => Self::missing_syntax("use variable", n, e),
2099                 };
2100                 let p_use = |n: S<'a, T, V>, e: &mut Env<'a, TF>| match &n.children {
2101                     AnonymousFunctionUseClause(c) => Self::could_map(p_arg, &c.variables, e),
2102                     _ => Ok(vec![]),
2103                 };
2104                 let suspension_kind = Self::mk_suspension_kind(&c.async_keyword);
2105                 let (body, yield_) = {
2106                     let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
2107                     Self::mp_yielding(&Self::p_function_body, &c.body, env1.as_mut())?
2108                 };
2109                 let doc_comment =
2110                     Self::extract_docblock(node, env).or_else(|| env.top_docblock().clone());
2111                 let user_attributes = Self::p_user_attributes(&c.attribute_spec, env)?;
2112                 let external = c.body.is_external();
2113                 let params = Self::could_map(Self::p_fun_param, &c.parameters, env)?;
2114                 let name_pos = Self::p_fun_pos(node, env);
2115                 let fun = ast::Fun_ {
2116                     span: Self::p_pos(node, env),
2117                     annotation: (),
2118                     mode: env.file_mode(),
2119                     ret: ast::TypeHint((), Self::mp_optional(Self::p_hint, &c.type_, env)?),
2120                     name: ast::Id(name_pos, String::from(";anonymous")),
2121                     tparams: vec![],
2122                     where_constraints: vec![],
2123                     body: ast::FuncBody {
2124                         ast: body,
2125                         annotation: (),
2126                     },
2127                     fun_kind: Self::mk_fun_kind(suspension_kind, yield_),
2128                     variadic: Self::determine_variadicity(&params),
2129                     params,
2130                     cap: ast::TypeHint((), None), // TODO(T70095684)
2131                     unsafe_cap: ast::TypeHint((), None), // TODO(T70095684)
2132                     user_attributes,
2133                     file_attributes: vec![],
2134                     external,
2135                     namespace: Self::mk_empty_ns_env(env),
2136                     doc_comment,
2137                     static_: !c.static_keyword.is_missing(),
2138                 };
2139                 let uses = p_use(&c.use_, env).unwrap_or_else(|_| vec![]);
2140                 Ok(E_::mk_efun(fun, uses))
2141             }
2142             AwaitableCreationExpression(c) => {
2143                 let suspension_kind = Self::mk_suspension_kind(&c.async_);
2144                 let (blk, yld) =
2145                     Self::mp_yielding(&Self::p_function_body, &c.compound_statement, env)?;
2146                 let user_attributes = Self::p_user_attributes(&c.attribute_spec, env)?;
2147                 let external = c.compound_statement.is_external();
2148                 let name_pos = Self::p_fun_pos(node, env);
2149                 let body = ast::Fun_ {
2150                     span: pos.clone(),
2151                     annotation: (),
2152                     mode: env.file_mode(),
2153                     ret: ast::TypeHint((), None),
2154                     name: ast::Id(name_pos, String::from(";anonymous")),
2155                     tparams: vec![],
2156                     where_constraints: vec![],
2157                     body: ast::FuncBody {
2158                         ast: if blk.len() == 0 {
2159                             let pos = Self::p_pos(&c.compound_statement, env);
2160                             vec![ast::Stmt::noop(pos)]
2161                         } else {
2162                             blk
2163                         },
2164                         annotation: (),
2165                     },
2166                     fun_kind: Self::mk_fun_kind(suspension_kind, yld),
2167                     variadic: Self::determine_variadicity(&[]),
2168                     params: vec![],
2169                     cap: ast::TypeHint((), None), // TODO(T70095684)
2170                     unsafe_cap: ast::TypeHint((), None), // TODO(T70095684)
2171                     user_attributes,
2172                     file_attributes: vec![],
2173                     external,
2174                     namespace: Self::mk_empty_ns_env(env),
2175                     doc_comment: None,
2176                     static_: false,
2177                 };
2178                 Ok(E_::mk_call(
2179                     E::new(pos, E_::mk_lfun(body, vec![])),
2180                     vec![],
2181                     vec![],
2182                     None,
2183                 ))
2184             }
2185             XHPExpression(c) if c.open.is_xhp_open() => {
2186                 if let XHPOpen(c1) = &c.open.children {
2187                     let name = Self::pos_name(&c1.name, env)?;
2188                     let attrs = Self::could_map(Self::p_xhp_attr, &c1.attributes, env)?;
2189                     let exprs = Self::aggregate_xhp_tokens(env, &c.body)?
2190                         .iter()
2191                         .map(|n| Self::p_xhp_embedded(Self::unesc_xhp, n, env))
2192                         .collect::<std::result::Result<Vec<_>, _>>()?;
2194                     let id = if env.empty_ns_env.disable_xhp_element_mangling {
2195                         ast::Id(name.0, name.1)
2196                     } else {
2197                         ast::Id(name.0, String::from(":") + &name.1)
2198                     };
2200                     Ok(E_::mk_xml(
2201                         // TODO: update pos_name to support prefix
2202                         id, attrs, exprs,
2203                     ))
2204                 } else {
2205                     Self::failwith("expect xhp open")
2206                 }
2207             }
2208             EnumAtomExpression(c) => Ok(E_::EnumAtom(Self::pos_name(&c.expression, env)?.1)),
2209             _ => Self::missing_syntax_(Some(E_::Null), "expression", node, env),
2210         }
2211     }
2213     fn check_lvalue(ast::Expr(p, expr_): &ast::Expr, env: &mut Env<'a, TF>) {
2214         use aast::Expr_::*;
2215         let mut raise = |s| Self::raise_parsing_error_pos(p, env, s);
2216         match expr_ {
2217             ObjGet(og) => {
2218                 if og.as_ref().3 {
2219                     raise("Invalid lvalue")
2220                 } else {
2221                     match og.as_ref() {
2222                         (_, ast::Expr(_, Id(_)), ast::OgNullFlavor::OGNullsafe, _) => {
2223                             raise("?-> syntax is not supported for lvalues")
2224                         }
2225                         (_, ast::Expr(_, Id(sid)), _, _) if sid.1.as_bytes()[0] == b':' => {
2226                             raise("->: syntax is not supported for lvalues")
2227                         }
2228                         _ => {}
2229                     }
2230                 }
2231             }
2232             ArrayGet(ag) => {
2233                 if let ClassConst(_) = (ag.0).1 {
2234                     raise("Array-like class consts are not valid lvalues");
2235                 }
2236             }
2237             Call(c) => match &(c.0).1 {
2238                 Id(sid) if sid.1 == "tuple" => {
2239                     raise("Tuple cannot be used as an lvalue. Maybe you meant list?")
2240                 }
2241                 _ => raise("Invalid lvalue"),
2242             },
2243             List(l) => {
2244                 for i in l.iter() {
2245                     Self::check_lvalue(i, env);
2246                 }
2247             }
2248             Darray(_) | Varray(_) | Shape(_) | Collection(_) | Record(_) | Null | True | False
2249             | Id(_) | Clone(_) | ClassConst(_) | Int(_) | Float(_) | PrefixedString(_)
2250             | String(_) | String2(_) | Yield(_) | YieldBreak | Await(_) | Cast(_) | Unop(_)
2251             | Binop(_) | Eif(_) | New(_) | Efun(_) | Lfun(_) | Xml(_) | Import(_) | Pipe(_)
2252             | Callconv(_) | Is(_) | As(_) => raise("Invalid lvalue"),
2253             _ => {}
2254         }
2255     }
2257     fn p_xhp_embedded<F>(escaper: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Expr>
2258     where
2259         F: FnOnce(&[u8]) -> Vec<u8>,
2260     {
2261         if let Some(kind) = Self::token_kind(node) {
2262             if env.codegen() && TK::XHPStringLiteral == kind {
2263                 let p = Self::p_pos(node, env);
2264                 /* for XHP string literals (attribute values) just extract
2265                 value from quotes and decode HTML entities  */
2266                 let text = html_entities::decode(&Self::get_quoted_content(
2267                     node.full_text(env.source_text()),
2268                 ));
2269                 Ok(ast::Expr::new(p, E_::make_string(text)))
2270             } else if env.codegen() && TK::XHPBody == kind {
2271                 let p = Self::p_pos(node, env);
2272                 /* for XHP body - only decode HTML entities */
2273                 let text =
2274                     html_entities::decode(&Self::unesc_xhp(node.full_text(env.source_text())));
2275                 Ok(ast::Expr::new(p, E_::make_string(text)))
2276             } else {
2277                 let p = Self::p_pos(node, env);
2278                 let s = escaper(node.full_text(env.source_text()));
2279                 Ok(ast::Expr::new(p, E_::make_string(s)))
2280             }
2281         } else {
2282             Self::p_expr(node, env)
2283         }
2284     }
2287     fn p_xhp_attr(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::XhpAttribute> {
2288         match &node.children {
2289             XHPSimpleAttribute(c) => {
2290                 let attr_expr = &c.expression;
2291                 let name = Self::p_pstring(&c.name, env)?;
2292                 let expr = if attr_expr.is_braced_expression()
2293                     && env.file_mode() == file_info::Mode::Mdecl
2294                     && !env.codegen()
2295                 {
2296                     ast::Expr::new(env.mk_none_pos(), E_::Null)
2297                 } else {
2298                     Self::p_xhp_embedded(Self::unesc_xhp_attr, attr_expr, env)?
2299                 };
2300                 Ok(ast::XhpAttribute::XhpSimple(name, expr))
2301             }
2302             XHPSpreadAttribute(c) => {
2303                 let expr = Self::p_xhp_embedded(Self::unesc_xhp, &c.expression, env)?;
2304                 Ok(ast::XhpAttribute::XhpSpread(expr))
2305             }
2306             _ => Self::missing_syntax("XHP attribute", node, env),
2307         }
2308     }
2310     fn aggregate_xhp_tokens(env: &mut Env<'a, TF>, nodes: S<'a, T, V>) -> Result<Vec<S<'a, T, V>>> {
2311         let nodes = nodes.syntax_node_to_list_skip_separator();
2312         let mut state = (None, None, vec![]); // (start, end, result)
2313         let mut combine =
2314             |state: &mut (Option<S<'a, T, V>>, Option<S<'a, T, V>>, Vec<S<'a, T, V>>)| {
2315                 match (state.0, state.1) {
2316                     (Some(s), None) => state.2.push(s),
2317                     (Some(s), Some(e)) => {
2318                         let token = env
2319                             .token_factory
2320                             .concatenate(s.get_token().unwrap(), e.get_token().unwrap());
2321                         let node = env.arena.alloc(<Syntax<T, V>>::make_token(token));
2322                         state.2.push(node)
2323                     }
2324                     _ => {}
2325                 }
2326                 state.0 = None;
2327                 state.1 = None;
2328                 Ok(())
2329             };
2330         for n in nodes {
2331             match &n.children {
2332                 Token(t) if t.kind() == TK::XHPComment => {
2333                     if state.0.is_some() {
2334                         combine(&mut state)?;
2335                     }
2336                 }
2337                 Token(_) => {
2338                     if state.0.is_none() {
2339                         state.0 = Some(n)
2340                     } else {
2341                         state.1 = Some(n)
2342                     }
2343                 }
2344                 _ => {
2345                     combine(&mut state)?;
2346                     state.2.push(n);
2347                 }
2348             }
2349         }
2350         combine(&mut state)?;
2351         Ok(state.2)
2352     }
2354     fn p_bop(
2355         pos: Pos,
2356         node: S<'a, T, V>,
2357         lhs: ast::Expr,
2358         rhs: ast::Expr,
2359         env: &mut Env<'a, TF>,
2360     ) -> Result<ast::Expr_> {
2361         use ast::Bop::*;
2362         let mk = |op, l, r| Ok(E_::mk_binop(op, l, r));
2363         let mk_eq = |op, l, r| Ok(E_::mk_binop(Eq(Some(Box::new(op))), l, r));
2364         match Self::token_kind(node) {
2365             Some(TK::Equal) => mk(Eq(None), lhs, rhs),
2366             Some(TK::Bar) => mk(Bar, lhs, rhs),
2367             Some(TK::Ampersand) => mk(Amp, lhs, rhs),
2368             Some(TK::Plus) => mk(Plus, lhs, rhs),
2369             Some(TK::Minus) => mk(Minus, lhs, rhs),
2370             Some(TK::Star) => mk(Star, lhs, rhs),
2371             Some(TK::Carat) => mk(Xor, lhs, rhs),
2372             Some(TK::Slash) => mk(Slash, lhs, rhs),
2373             Some(TK::Dot) => mk(Dot, lhs, rhs),
2374             Some(TK::Percent) => mk(Percent, lhs, rhs),
2375             Some(TK::LessThan) => mk(Lt, lhs, rhs),
2376             Some(TK::GreaterThan) => mk(Gt, lhs, rhs),
2377             Some(TK::EqualEqual) => mk(Eqeq, lhs, rhs),
2378             Some(TK::LessThanEqual) => mk(Lte, lhs, rhs),
2379             Some(TK::GreaterThanEqual) => mk(Gte, lhs, rhs),
2380             Some(TK::StarStar) => mk(Starstar, lhs, rhs),
2381             Some(TK::ExclamationEqual) => mk(Diff, lhs, rhs),
2382             Some(TK::BarEqual) => mk_eq(Bar, lhs, rhs),
2383             Some(TK::PlusEqual) => mk_eq(Plus, lhs, rhs),
2384             Some(TK::MinusEqual) => mk_eq(Minus, lhs, rhs),
2385             Some(TK::StarEqual) => mk_eq(Star, lhs, rhs),
2386             Some(TK::StarStarEqual) => mk_eq(Starstar, lhs, rhs),
2387             Some(TK::SlashEqual) => mk_eq(Slash, lhs, rhs),
2388             Some(TK::DotEqual) => mk_eq(Dot, lhs, rhs),
2389             Some(TK::PercentEqual) => mk_eq(Percent, lhs, rhs),
2390             Some(TK::CaratEqual) => mk_eq(Xor, lhs, rhs),
2391             Some(TK::AmpersandEqual) => mk_eq(Amp, lhs, rhs),
2392             Some(TK::BarBar) => mk(Barbar, lhs, rhs),
2393             Some(TK::AmpersandAmpersand) => mk(Ampamp, lhs, rhs),
2394             Some(TK::LessThanLessThan) => mk(Ltlt, lhs, rhs),
2395             Some(TK::GreaterThanGreaterThan) => mk(Gtgt, lhs, rhs),
2396             Some(TK::EqualEqualEqual) => mk(Eqeqeq, lhs, rhs),
2397             Some(TK::LessThanLessThanEqual) => mk_eq(Ltlt, lhs, rhs),
2398             Some(TK::GreaterThanGreaterThanEqual) => mk_eq(Gtgt, lhs, rhs),
2399             Some(TK::ExclamationEqualEqual) => mk(Diff2, lhs, rhs),
2400             Some(TK::LessThanEqualGreaterThan) => mk(Cmp, lhs, rhs),
2401             Some(TK::QuestionQuestion) => mk(QuestionQuestion, lhs, rhs),
2402             Some(TK::QuestionQuestionEqual) => mk_eq(QuestionQuestion, lhs, rhs),
2403             /* The ugly duckling; In the FFP, `|>` is parsed as a
2404              * `BinaryOperator`, whereas the typed AST has separate constructors for
2405              * Pipe and Binop. This is why we don't just project onto a
2406              * `bop`, but a `expr -> expr -> expr_`.
2407              */
2408             Some(TK::BarGreaterThan) => {
2409                 let lid =
2410                     ast::Lid::from_counter(pos, env.next_local_id(), special_idents::DOLLAR_DOLLAR);
2411                 Ok(E_::mk_pipe(lid, lhs, rhs))
2412             }
2413             Some(TK::QuestionColon) => Ok(E_::mk_eif(lhs, None, rhs)),
2414             _ => Self::missing_syntax("binary operator", node, env),
2415         }
2416     }
2418     fn p_exprs_with_loc(n: S<'a, T, V>, e: &mut Env<'a, TF>) -> Result<(Pos, Vec<ast::Expr>)> {
2419         let loc = Self::p_pos(&n, e);
2420         let p_expr = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::Expr> {
2421             Self::p_expr_with_loc(ExprLocation::UsingStatement, n, e)
2422         };
2423         Ok((loc, Self::could_map(p_expr, n, e)?))
2424     }
2426     fn p_stmt_list_(
2427         pos: &Pos,
2428         mut nodes: Iter<S<'a, T, V>>,
2429         env: &mut Env<'a, TF>,
2430     ) -> Result<Vec<ast::Stmt>> {
2431         let mut r = vec![];
2432         loop {
2433             match nodes.next() {
2434                 Some(n) => match &n.children {
2435                     UsingStatementFunctionScoped(c) => {
2436                         let body = Self::p_stmt_list_(pos, nodes, env)?;
2437                         let f = |e: &mut Env<'a, TF>| {
2438                             Ok(ast::Stmt::new(
2439                                 pos.clone(),
2440                                 ast::Stmt_::mk_using(ast::UsingStmt {
2441                                     is_block_scoped: false,
2442                                     has_await: !c.await_keyword.is_missing(),
2443                                     exprs: Self::p_exprs_with_loc(&c.expression, e)?,
2444                                     block: body,
2445                                 }),
2446                             ))
2447                         };
2448                         let using = Self::lift_awaits_in_statement_(f, Either::Right(pos), env)?;
2449                         r.push(using);
2450                         break Ok(r);
2451                     }
2452                     _ => {
2453                         r.push(Self::p_stmt(n, env)?);
2454                     }
2455                 },
2456                 _ => break Ok(r),
2457             }
2458         }
2459     }
2461     fn handle_loop_body(pos: Pos, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Stmt> {
2462         let list: Vec<_> = node.syntax_node_to_list_skip_separator().collect();
2463         let blk: Vec<_> = Self::p_stmt_list_(&pos, list.iter(), env)?
2464             .into_iter()
2465             .filter(|stmt| !stmt.1.is_noop())
2466             .collect();
2467         let body = if blk.len() == 0 {
2468             vec![Self::mk_noop(env)]
2469         } else {
2470             blk
2471         };
2472         Ok(ast::Stmt::new(pos, ast::Stmt_::mk_block(body)))
2473     }
2475     fn is_simple_assignment_await_expression(node: S<'a, T, V>) -> bool {
2476         match &node.children {
2477             BinaryExpression(c) => {
2478                 Self::token_kind(&c.operator) == Some(TK::Equal)
2479                     && Self::is_simple_await_expression(&c.right_operand)
2480             }
2481             _ => false,
2482         }
2483     }
2485     fn is_simple_await_expression(node: S<'a, T, V>) -> bool {
2486         match &node.children {
2487             PrefixUnaryExpression(c) => Self::token_kind(&c.operator) == Some(TK::Await),
2488             _ => false,
2489         }
2490     }
2492     fn with_new_nonconcurrent_scope<F, R>(f: F, env: &mut Env<'a, TF>) -> R
2493     where
2494         F: FnOnce(&mut Env<'a, TF>) -> R,
2495     {
2496         let saved_lifted_awaits = env.lifted_awaits.take();
2497         let result = f(env);
2498         env.lifted_awaits = saved_lifted_awaits;
2499         result
2500     }
2502     fn with_new_concurrent_scope<F, R>(f: F, env: &mut Env<'a, TF>) -> Result<(LiftedAwaitExprs, R)>
2503     where
2504         F: FnOnce(&mut Env<'a, TF>) -> Result<R>,
2505     {
2506         let saved_lifted_awaits = env.lifted_awaits.replace(LiftedAwaits {
2507             awaits: vec![],
2508             lift_kind: LiftedAwaitKind::LiftedFromConcurrent,
2509         });
2510         let result = f(env);
2511         let lifted_awaits = mem::replace(&mut env.lifted_awaits, saved_lifted_awaits);
2512         let result = result?;
2513         let awaits = match lifted_awaits {
2514             Some(la) => Self::process_lifted_awaits(la)?,
2515             None => Self::failwith("lifted awaits should not be None")?,
2516         };
2517         Ok((awaits, result))
2518     }
2520     fn process_lifted_awaits(mut awaits: LiftedAwaits) -> Result<LiftedAwaitExprs> {
2521         for await_ in awaits.awaits.iter() {
2522             if (await_.1).0.is_none() {
2523                 return Self::failwith("none pos in lifted awaits");
2524             }
2525         }
2526         awaits
2527             .awaits
2528             .sort_unstable_by(|a1, a2| Pos::cmp(&(a1.1).0, &(a2.1).0));
2529         Ok(awaits.awaits)
2530     }
2532     fn clear_statement_scope<F, R>(f: F, env: &mut Env<'a, TF>) -> R
2533     where
2534         F: FnOnce(&mut Env<'a, TF>) -> R,
2535     {
2536         use LiftedAwaitKind::*;
2537         match &env.lifted_awaits {
2538             Some(LiftedAwaits { lift_kind, .. }) if *lift_kind == LiftedFromStatement => {
2539                 let saved_lifted_awaits = env.lifted_awaits.take();
2540                 let result = f(env);
2541                 env.lifted_awaits = saved_lifted_awaits;
2542                 result
2543             }
2544             _ => f(env),
2545         }
2546     }
2548     fn lift_awaits_in_statement<F>(
2549         f: F,
2550         node: S<'a, T, V>,
2551         env: &mut Env<'a, TF>,
2552     ) -> Result<ast::Stmt>
2553     where
2554         F: FnOnce(&mut Env<'a, TF>) -> Result<ast::Stmt>,
2555     {
2556         Self::lift_awaits_in_statement_(f, Either::Left(node), env)
2557     }
2559     fn lift_awaits_in_statement_<F>(
2560         f: F,
2561         pos: Either<S<'a, T, V>, &Pos>,
2562         env: &mut Env<'a, TF>,
2563     ) -> Result<ast::Stmt>
2564     where
2565         F: FnOnce(&mut Env<'a, TF>) -> Result<ast::Stmt>,
2566     {
2567         use LiftedAwaitKind::*;
2568         let (lifted_awaits, result) = match env.lifted_awaits {
2569             Some(LiftedAwaits { lift_kind, .. }) if lift_kind == LiftedFromConcurrent => {
2570                 (None, f(env)?)
2571             }
2572             _ => {
2573                 let saved = env.lifted_awaits.replace(LiftedAwaits {
2574                     awaits: vec![],
2575                     lift_kind: LiftedFromStatement,
2576                 });
2577                 let result = f(env);
2578                 let lifted_awaits = mem::replace(&mut env.lifted_awaits, saved);
2579                 let result = result?;
2580                 (lifted_awaits, result)
2581             }
2582         };
2583         if let Some(lifted_awaits) = lifted_awaits {
2584             if !lifted_awaits.awaits.is_empty() {
2585                 let awaits = Self::process_lifted_awaits(lifted_awaits)?;
2586                 let pos = match pos {
2587                     Either::Left(n) => Self::p_pos(n, env),
2588                     Either::Right(p) => p.clone(),
2589                 };
2590                 return Ok(ast::Stmt::new(
2591                     pos,
2592                     ast::Stmt_::mk_awaitall(awaits, vec![result]),
2593                 ));
2594             }
2595         }
2596         Ok(result)
2597     }
2599     fn lift_await(
2600         parent_pos: Pos,
2601         expr: ast::Expr,
2602         env: &mut Env<'a, TF>,
2603         location: ExprLocation,
2604     ) -> Result<ast::Expr_> {
2605         use ExprLocation::*;
2606         match (&env.lifted_awaits, location) {
2607             (_, UsingStatement) | (_, RightOfAssignmentInUsingStatement) | (None, _) => {
2608                 Ok(E_::mk_await(expr))
2609             }
2610             (Some(_), _) => {
2611                 if location != AsStatement {
2612                     let name = env.make_tmp_var_name();
2613                     let lid = ast::Lid::new(parent_pos, name.clone());
2614                     let await_lid = ast::Lid::new(expr.0.clone(), name);
2615                     let await_ = (Some(await_lid), expr);
2616                     env.lifted_awaits.as_mut().map(|aw| aw.awaits.push(await_));
2617                     Ok(E_::mk_lvar(lid))
2618                 } else {
2619                     env.lifted_awaits
2620                         .as_mut()
2621                         .map(|aw| aw.awaits.push((None, expr)));
2622                     Ok(E_::Null)
2623                 }
2624             }
2625         }
2626     }
2628     fn p_stmt(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Stmt> {
2629         Self::clear_statement_scope(
2630             |e: &mut Env<'a, TF>| {
2631                 let docblock = Self::extract_docblock(node, e);
2632                 e.push_docblock(docblock);
2633                 let result = Self::p_stmt_(node, e);
2634                 e.pop_docblock();
2635                 result
2636             },
2637             env,
2638         )
2639     }
2641     fn p_stmt_(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Stmt> {
2642         let pos = Self::p_pos(node, env);
2643         use ast::{Stmt, Stmt_ as S_};
2644         let new = Stmt::new;
2645         match &node.children {
2646             SwitchStatement(c) => {
2647                 let p_label = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::Case> {
2648                     match &n.children {
2649                         CaseLabel(c) => {
2650                             Ok(ast::Case::Case(Self::p_expr(&c.expression, e)?, vec![]))
2651                         }
2652                         DefaultLabel(_) => Ok(ast::Case::Default(Self::p_pos(n, e), vec![])),
2653                         _ => Self::missing_syntax("switch label", n, e),
2654                     }
2655                 };
2656                 let p_section = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<Vec<ast::Case>> {
2657                     match &n.children {
2658                         SwitchSection(c) => {
2659                             let mut blk = Self::could_map(Self::p_stmt, &c.statements, e)?;
2660                             if !c.fallthrough.is_missing() {
2661                                 blk.push(new(e.mk_none_pos(), S_::Fallthrough));
2662                             }
2663                             let mut labels = Self::could_map(p_label, &c.labels, e)?;
2664                             match labels.last_mut() {
2665                                 Some(ast::Case::Default(_, b)) => *b = blk,
2666                                 Some(ast::Case::Case(_, b)) => *b = blk,
2667                                 _ => Self::raise_parsing_error(n, e, "Malformed block result"),
2668                             }
2669                             Ok(labels)
2670                         }
2671                         _ => Self::missing_syntax("switch section", n, e),
2672                     }
2673                 };
2674                 let f = |env: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2675                     Ok(new(
2676                         pos,
2677                         S_::mk_switch(
2678                             Self::p_expr(&c.expression, env)?,
2679                             itertools::concat(Self::could_map(p_section, &c.sections, env)?),
2680                         ),
2681                     ))
2682                 };
2683                 Self::lift_awaits_in_statement(f, node, env)
2684             }
2685             IfStatement(c) => {
2686                 let p_else_if =
2687                     |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<(ast::Expr, ast::Block)> {
2688                         match &n.children {
2689                             ElseifClause(c) => Ok((
2690                                 Self::p_expr(&c.condition, e)?,
2691                                 Self::p_block(true, &c.statement, e)?,
2692                             )),
2693                             _ => Self::missing_syntax("elseif clause", n, e),
2694                         }
2695                     };
2696                 let f = |env: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2697                     let condition = Self::p_expr(&c.condition, env)?;
2698                     let statement = Self::p_block(true /* remove noop */, &c.statement, env)?;
2699                     let else_ = match &c.else_clause.children {
2700                         ElseClause(c) => Self::p_block(true, &c.statement, env)?,
2701                         Missing => vec![Self::mk_noop(env)],
2702                         _ => Self::missing_syntax("else clause", &c.else_clause, env)?,
2703                     };
2704                     let else_ifs = Self::could_map(p_else_if, &c.elseif_clauses, env)?;
2705                     let else_if = else_ifs
2706                         .into_iter()
2707                         .rev()
2708                         .fold(else_, |child, (cond, stmts)| {
2709                             vec![new(pos.clone(), S_::mk_if(cond, stmts, child))]
2710                         });
2711                     Ok(new(pos, S_::mk_if(condition, statement, else_if)))
2712                 };
2713                 Self::lift_awaits_in_statement(f, node, env)
2714             }
2715             ExpressionStatement(c) => {
2716                 let expr = &c.expression;
2717                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2718                     if expr.is_missing() {
2719                         Ok(new(pos, S_::Noop))
2720                     } else {
2721                         Ok(new(
2722                             pos,
2723                             S_::mk_expr(Self::p_expr_with_loc(ExprLocation::AsStatement, expr, e)?),
2724                         ))
2725                     }
2726                 };
2727                 if Self::is_simple_assignment_await_expression(expr)
2728                     || Self::is_simple_await_expression(expr)
2729                 {
2730                     f(env)
2731                 } else {
2732                     Self::lift_awaits_in_statement(f, node, env)
2733                 }
2734             }
2735             CompoundStatement(c) => Self::handle_loop_body(pos, &c.statements, env),
2736             SyntaxList(_) => Self::handle_loop_body(pos, node, env),
2737             ThrowStatement(c) => Self::lift_awaits_in_statement(
2738                 |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2739                     Ok(new(pos, S_::mk_throw(Self::p_expr(&c.expression, e)?)))
2740                 },
2741                 node,
2742                 env,
2743             ),
2744             DoStatement(c) => Ok(new(
2745                 pos,
2746                 S_::mk_do(
2747                     Self::p_block(false /* remove noop */, &c.body, env)?,
2748                     Self::p_expr(&c.condition, env)?,
2749                 ),
2750             )),
2751             WhileStatement(c) => Ok(new(
2752                 pos,
2753                 S_::mk_while(
2754                     Self::p_expr(&c.condition, env)?,
2755                     Self::p_block(true, &c.body, env)?,
2756                 ),
2757             )),
2758             UsingStatementBlockScoped(c) => {
2759                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2760                     Ok(new(
2761                         pos,
2762                         S_::mk_using(ast::UsingStmt {
2763                             is_block_scoped: true,
2764                             has_await: !&c.await_keyword.is_missing(),
2765                             exprs: Self::p_exprs_with_loc(&c.expressions, e)?,
2766                             block: Self::p_block(false, &c.body, e)?,
2767                         }),
2768                     ))
2769                 };
2770                 Self::lift_awaits_in_statement(f, node, env)
2771             }
2772             UsingStatementFunctionScoped(c) => {
2773                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2774                     Ok(new(
2775                         pos,
2776                         S_::mk_using(ast::UsingStmt {
2777                             is_block_scoped: false,
2778                             has_await: !&c.await_keyword.is_missing(),
2779                             exprs: Self::p_exprs_with_loc(&c.expression, e)?,
2780                             block: vec![Self::mk_noop(e)],
2781                         }),
2782                     ))
2783                 };
2784                 Self::lift_awaits_in_statement(f, node, env)
2785             }
2786             ForStatement(c) => {
2787                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2788                     let ini = Self::p_expr_l(&c.initializer, e)?;
2789                     let ctr = Self::mp_optional(Self::p_expr, &c.control, e)?;
2790                     let eol = Self::p_expr_l(&c.end_of_loop, e)?;
2791                     let blk = Self::p_block(true, &c.body, e)?;
2792                     Ok(Stmt::new(pos, S_::mk_for(ini, ctr, eol, blk)))
2793                 };
2794                 Self::lift_awaits_in_statement(f, node, env)
2795             }
2796             ForeachStatement(c) => {
2797                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2798                     let col = Self::p_expr(&c.collection, e)?;
2799                     let akw = match Self::token_kind(&c.await_keyword) {
2800                         Some(TK::Await) => Some(Self::p_pos(&c.await_keyword, e)),
2801                         _ => None,
2802                     };
2803                     let value = Self::p_expr(&c.value, e)?;
2804                     let akv = match (akw, &c.key.children) {
2805                         (Some(p), Missing) => ast::AsExpr::AwaitAsV(p, value),
2806                         (None, Missing) => ast::AsExpr::AsV(value),
2807                         (Some(p), _) => ast::AsExpr::AwaitAsKv(p, Self::p_expr(&c.key, e)?, value),
2808                         (None, _) => ast::AsExpr::AsKv(Self::p_expr(&c.key, e)?, value),
2809                     };
2810                     let blk = Self::p_block(true, &c.body, e)?;
2811                     Ok(new(pos, S_::mk_foreach(col, akv, blk)))
2812                 };
2813                 Self::lift_awaits_in_statement(f, node, env)
2814             }
2815             TryStatement(c) => Ok(new(
2816                 pos,
2817                 S_::mk_try(
2818                     Self::p_block(false, &c.compound_statement, env)?,
2819                     Self::could_map(
2820                         |n: S<'a, T, V>, e| match &n.children {
2821                             CatchClause(c) => Ok(ast::Catch(
2822                                 Self::pos_name(&c.type_, e)?,
2823                                 Self::lid_from_name(&c.variable, e)?,
2824                                 Self::p_block(true, &c.body, e)?,
2825                             )),
2826                             _ => Self::missing_syntax("catch clause", n, e),
2827                         },
2828                         &c.catch_clauses,
2829                         env,
2830                     )?,
2831                     match &c.finally_clause.children {
2832                         FinallyClause(c) => Self::p_block(false, &c.body, env)?,
2833                         _ => vec![],
2834                     },
2835                 ),
2836             )),
2837             ReturnStatement(c) => {
2838                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2839                     let expr = match &c.expression.children {
2840                         Missing => None,
2841                         _ => Some(Self::p_expr_with_loc(
2842                             ExprLocation::RightOfReturn,
2843                             &c.expression,
2844                             e,
2845                         )?),
2846                     };
2847                     Ok(ast::Stmt::new(pos, ast::Stmt_::mk_return(expr)))
2848                 };
2849                 if Self::is_simple_await_expression(&c.expression) {
2850                     f(env)
2851                 } else {
2852                     Self::lift_awaits_in_statement(f, node, env)
2853                 }
2854             }
2855             EchoStatement(c) => {
2856                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2857                     let echo = match &c.keyword.children {
2858                         QualifiedName(_) | SimpleTypeSpecifier(_) | Token(_) => {
2859                             let name = Self::pos_name(&c.keyword, e)?;
2860                             ast::Expr::new(name.0.clone(), E_::mk_id(name))
2861                         }
2862                         _ => Self::missing_syntax("id", &c.keyword, e)?,
2863                     };
2864                     let args = Self::could_map(Self::p_expr, &c.expressions, e)?;
2865                     Ok(new(
2866                         pos.clone(),
2867                         S_::mk_expr(ast::Expr::new(pos, E_::mk_call(echo, vec![], args, None))),
2868                     ))
2869                 };
2870                 Self::lift_awaits_in_statement(f, node, env)
2871             }
2872             UnsetStatement(c) => {
2873                 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2874                     let args = Self::could_map(Self::p_expr, &c.variables, e)?;
2875                     if e.parser_options.po_disable_unset_class_const {
2876                         args.iter()
2877                             .for_each(|arg| Self::check_mutate_class_const(arg, node, e))
2878                     }
2879                     let unset = match &c.keyword.children {
2880                         QualifiedName(_) | SimpleTypeSpecifier(_) | Token(_) => {
2881                             let name = Self::pos_name(&c.keyword, e)?;
2882                             ast::Expr::new(name.0.clone(), E_::mk_id(name))
2883                         }
2884                         _ => Self::missing_syntax("id", &c.keyword, e)?,
2885                     };
2886                     Ok(new(
2887                         pos.clone(),
2888                         S_::mk_expr(ast::Expr::new(pos, E_::mk_call(unset, vec![], args, None))),
2889                     ))
2890                 };
2891                 Self::lift_awaits_in_statement(f, node, env)
2892             }
2893             BreakStatement(_) => Ok(new(pos, S_::Break)),
2894             ContinueStatement(_) => Ok(new(pos, S_::Continue)),
2895             ConcurrentStatement(c) => {
2896                 let keyword_pos = Self::p_pos(&c.keyword, env);
2897                 let (lifted_awaits, Stmt(stmt_pos, stmt)) = Self::with_new_concurrent_scope(
2898                     |e: &mut Env<'a, TF>| Self::p_stmt(&c.statement, e),
2899                     env,
2900                 )?;
2901                 let stmt = match stmt {
2902                     S_::Block(stmts) => {
2903                         use ast::Bop::Eq;
2904                         use ast::Expr as E;
2905                         /* Reuse tmp vars from lifted_awaits, this is safe because there will
2906                          * always be more awaits with tmp vars than statements with assignments */
2907                         let mut tmp_vars = lifted_awaits
2908                             .iter()
2909                             .filter_map(|lifted_await| lifted_await.0.as_ref().map(|x| &x.1));
2910                         let mut body_stmts = vec![];
2911                         let mut assign_stmts = vec![];
2912                         for n in stmts.into_iter() {
2913                             if !n.is_assign_expr() {
2914                                 body_stmts.push(n);
2915                                 continue;
2916                             }
2918                             if let Some(tv) = tmp_vars.next() {
2919                                 if let Stmt(p1, S_::Expr(expr)) = n {
2920                                     if let E(p2, E_::Binop(bop)) = *expr {
2921                                         if let (Eq(op), e1, e2) = *bop {
2922                                             let tmp_n = E::mk_lvar(&e2.0, &(tv.1));
2923                                             if tmp_n.lvar_name() != e2.lvar_name() {
2924                                                 let new_n = new(
2925                                                     p1.clone(),
2926                                                     S_::mk_expr(E::new(
2927                                                         p2.clone(),
2928                                                         E_::mk_binop(
2929                                                             Eq(None),
2930                                                             tmp_n.clone(),
2931                                                             e2.clone(),
2932                                                         ),
2933                                                     )),
2934                                                 );
2935                                                 body_stmts.push(new_n);
2936                                             }
2937                                             let assign_stmt = new(
2938                                                 p1,
2939                                                 S_::mk_expr(E::new(
2940                                                     p2,
2941                                                     E_::mk_binop(Eq(op), e1, tmp_n),
2942                                                 )),
2943                                             );
2944                                             assign_stmts.push(assign_stmt);
2945                                             continue;
2946                                         }
2947                                     }
2948                                 }
2950                                 Self::failwith("Expect assignment stmt")?;
2951                             } else {
2952                                 Self::raise_parsing_error_pos(
2953                                     &stmt_pos,
2954                                     env,
2955                                     &syntax_error::statement_without_await_in_concurrent_block,
2956                                 );
2957                                 body_stmts.push(n)
2958                             }
2959                         }
2960                         body_stmts.append(&mut assign_stmts);
2961                         new(stmt_pos, S_::mk_block(body_stmts))
2962                     }
2963                     _ => Self::failwith("Unexpected concurrent stmt structure")?,
2964                 };
2965                 Ok(new(keyword_pos, S_::mk_awaitall(lifted_awaits, vec![stmt])))
2966             }
2967             MarkupSection(_) => Self::p_markup(node, env),
2968             _ => Self::missing_syntax_(
2969                 Some(new(env.mk_none_pos(), S_::Noop)),
2970                 "statement",
2971                 node,
2972                 env,
2973             ),
2974         }
2975     }
2976     fn check_mutate_class_const(e: &ast::Expr, node: S<'a, T, V>, env: &mut Env<'a, TF>) {
2977         match &e.1 {
2978             E_::ArrayGet(c) if c.1.is_some() => Self::check_mutate_class_const(&c.0, node, env),
2979             E_::ClassConst(_) => {
2980                 Self::raise_parsing_error(node, env, &syntax_error::const_mutation)
2981             }
2982             _ => {}
2983         }
2984     }
2986     fn is_hashbang(node: S<'a, T, V>, env: &Env<TF>) -> bool {
2987         let text = Self::text_str(node, env);
2988         lazy_static! {
2989             static ref RE: regex::Regex = regex::Regex::new("^#!.*\n").unwrap();
2990         }
2991         text.lines().nth(1).is_none() && // only one line
2992         RE.is_match(text)
2993     }
2995     fn p_markup(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Stmt> {
2996         match &node.children {
2997             MarkupSection(c) => {
2998                 let markup_hashbang = &c.hashbang;
2999                 let pos = Self::p_pos(node, env);
3000                 let f = pos.filename();
3001                 if (f.has_extension("hack") || f.has_extension("hackpartial"))
3002                     && !(&c.suffix.is_missing())
3003                 {
3004                     let ext = f.path().extension().unwrap(); // has_extension ensures this is a Some
3005                     Self::raise_parsing_error(
3006                         node,
3007                         env,
3008                         &syntax_error::error1060(&ext.to_str().unwrap()),
3009                     );
3010                 } else if markup_hashbang.width() > 0 && !Self::is_hashbang(markup_hashbang, env) {
3011                     Self::raise_parsing_error(node, env, &syntax_error::error1001);
3012                 }
3013                 let stmt_ = ast::Stmt_::mk_markup((pos.clone(), Self::text(markup_hashbang, env)));
3014                 Ok(ast::Stmt::new(pos, stmt_))
3015             }
3016             _ => Self::failwith("invalid node"),
3017         }
3018     }
3020     fn p_modifiers<F: Fn(R, modifier::Kind) -> R, R>(
3021         on_kind: F,
3022         mut init: R,
3023         node: S<'a, T, V>,
3024         env: &mut Env<'a, TF>,
3025     ) -> Result<(modifier::KindSet, R)> {
3026         let mut kind_set = modifier::KindSet::new();
3027         for n in node.syntax_node_to_list_skip_separator() {
3028             let token_kind = Self::token_kind(n).map_or(None, modifier::from_token_kind);
3029             match token_kind {
3030                 Some(kind) => {
3031                     kind_set.add(kind);
3032                     init = on_kind(init, kind);
3033                 }
3034                 _ => Self::missing_syntax("kind", n, env)?,
3035             }
3036         }
3037         Ok((kind_set, init))
3038     }
3040     fn p_kinds(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<modifier::KindSet> {
3041         Self::p_modifiers(|_, _| {}, (), node, env).map(|r| r.0)
3042     }
3044     fn could_map<R, F>(f: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Vec<R>>
3045     where
3046         F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
3047     {
3048         Self::map_flatten_(f, node, env, vec![])
3049     }
3051     fn map_flatten_<R, F>(
3052         f: F,
3053         node: S<'a, T, V>,
3054         env: &mut Env<'a, TF>,
3055         acc: Vec<R>,
3056     ) -> Result<Vec<R>>
3057     where
3058         F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
3059     {
3060         let op = |mut v: Vec<R>, a| {
3061             v.push(a);
3062             v
3063         };
3064         Self::map_fold(&f, &op, node, env, acc)
3065     }
3067     fn could_map_filter<R, F>(
3068         f: F,
3069         node: S<'a, T, V>,
3070         env: &mut Env<'a, TF>,
3071     ) -> Result<(Vec<R>, bool)>
3072     where
3073         F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<Option<R>>,
3074     {
3075         Self::map_flatten_filter_(f, node, env, (vec![], false))
3076     }
3078     #[inline]
3079     fn map_flatten_filter_<R, F>(
3080         f: F,
3081         node: S<'a, T, V>,
3082         env: &mut Env<'a, TF>,
3083         acc: (Vec<R>, bool),
3084     ) -> Result<(Vec<R>, bool)>
3085     where
3086         F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<Option<R>>,
3087     {
3088         let op = |mut v: (Vec<R>, bool), a| -> (Vec<R>, bool) {
3089             match a {
3090                 Option::None => (v.0, true),
3091                 Option::Some(a) => {
3092                     v.0.push(a);
3093                     v
3094                 }
3095             }
3096         };
3097         Self::map_fold(&f, &op, node, env, acc)
3098     }
3100     fn map_fold<A, R, F, O>(
3101         f: &F,
3102         op: &O,
3103         node: S<'a, T, V>,
3104         env: &mut Env<'a, TF>,
3105         mut acc: A,
3106     ) -> Result<A>
3107     where
3108         F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
3109         O: Fn(A, R) -> A,
3110     {
3111         for n in node.syntax_node_to_list_skip_separator() {
3112             acc = op(acc, f(n, env)?);
3113         }
3114         Ok(acc)
3115     }
3117     fn p_visibility(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Option<ast::Visibility>> {
3118         let first_vis =
3119             |r: Option<ast::Visibility>, kind| r.or_else(|| modifier::to_visibility(kind));
3120         Self::p_modifiers(first_vis, None, node, env).map(|r| r.1)
3121     }
3123     fn p_visibility_or(
3124         node: S<'a, T, V>,
3125         env: &mut Env<'a, TF>,
3126         default: ast::Visibility,
3127     ) -> Result<ast::Visibility> {
3128         Self::p_visibility(node, env).map(|v| v.unwrap_or(default))
3129     }
3131     fn p_visibility_last_win(
3132         node: S<'a, T, V>,
3133         env: &mut Env<'a, TF>,
3134     ) -> Result<Option<ast::Visibility>> {
3135         let last_vis = |r, kind| modifier::to_visibility(kind).or(r);
3136         Self::p_modifiers(last_vis, None, node, env).map(|r| r.1)
3137     }
3139     fn p_visibility_last_win_or(
3140         node: S<'a, T, V>,
3141         env: &mut Env<'a, TF>,
3142         default: ast::Visibility,
3143     ) -> Result<ast::Visibility> {
3144         Self::p_visibility_last_win(node, env).map(|v| v.unwrap_or(default))
3145     }
3147     fn has_soft(attrs: &[ast::UserAttribute]) -> bool {
3148         attrs.iter().any(|attr| attr.name.1 == special_attrs::SOFT)
3149     }
3151     fn soften_hint(attrs: &[ast::UserAttribute], hint: ast::Hint) -> ast::Hint {
3152         if Self::has_soft(attrs) {
3153             ast::Hint::new(hint.0.clone(), ast::Hint_::Hsoft(hint))
3154         } else {
3155             hint
3156         }
3157     }
3159     fn p_fun_param_default_value(
3160         node: S<'a, T, V>,
3161         env: &mut Env<'a, TF>,
3162     ) -> Result<Option<ast::Expr>> {
3163         match &node.children {
3164             SimpleInitializer(c) => Self::mp_optional(Self::p_expr, &c.value, env),
3165             _ => Ok(None),
3166         }
3167     }
3169     fn p_param_kind(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::ParamKind> {
3170         match Self::token_kind(node) {
3171             Some(TK::Inout) => Ok(ast::ParamKind::Pinout),
3172             _ => Self::missing_syntax("param kind", node, env),
3173         }
3174     }
3176     fn param_template(node: S<'a, T, V>, env: &Env<TF>) -> ast::FunParam {
3177         let pos = Self::p_pos(node, env);
3178         ast::FunParam {
3179             annotation: pos.clone(),
3180             type_hint: ast::TypeHint((), None),
3181             is_variadic: false,
3182             pos,
3183             name: Self::text(node, env),
3184             expr: None,
3185             callconv: None,
3186             user_attributes: vec![],
3187             visibility: None,
3188         }
3189     }
3191     fn p_fun_param(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::FunParam> {
3192         match &node.children {
3193             ParameterDeclaration(ParameterDeclarationChildren {
3194                 attribute,
3195                 visibility,
3196                 call_convention,
3197                 type_,
3198                 name,
3199                 default_value,
3200             }) => {
3201                 let (is_variadic, name) = match &name.children {
3202                     DecoratedExpression(DecoratedExpressionChildren {
3203                         decorator,
3204                         expression,
3205                     }) => {
3206                         let decorator = Self::text_str(decorator, env);
3207                         match &expression.children {
3208                             DecoratedExpression(c) => {
3209                                 let nested_expression = &c.expression;
3210                                 let nested_decorator = Self::text_str(&c.decorator, env);
3211                                 (
3212                                     decorator == "..." || nested_decorator == "...",
3213                                     nested_expression,
3214                                 )
3215                             }
3216                             _ => (decorator == "...", expression),
3217                         }
3218                     }
3219                     _ => (false, name),
3220                 };
3221                 let user_attributes = Self::p_user_attributes(attribute, env)?;
3222                 let hint = Self::mp_optional(Self::p_hint, type_, env)?
3223                     .map(|h| Self::soften_hint(&user_attributes, h));
3224                 if is_variadic && !user_attributes.is_empty() {
3225                     Self::raise_parsing_error(
3226                         node,
3227                         env,
3228                         &syntax_error::no_attributes_on_variadic_parameter,
3229                     );
3230                 }
3231                 let pos = Self::p_pos(name, env);
3232                 Ok(ast::FunParam {
3233                     annotation: pos.clone(),
3234                     type_hint: ast::TypeHint((), hint),
3235                     user_attributes,
3236                     is_variadic,
3237                     pos,
3238                     name: Self::text(name, env),
3239                     expr: Self::p_fun_param_default_value(default_value, env)?,
3240                     callconv: Self::mp_optional(Self::p_param_kind, call_convention, env)?,
3241                     /* implicit field via constructor parameter.
3242                      * This is always None except for constructors and the modifier
3243                      * can be only Public or Protected or Private.
3244                      */
3245                     visibility: Self::p_visibility(visibility, env)?,
3246                 })
3247             }
3248             VariadicParameter(_) => {
3249                 let mut param = Self::param_template(node, env);
3250                 param.is_variadic = true;
3251                 Ok(param)
3252             }
3253             Token(_) if Self::text_str(node, env) == "..." => {
3254                 let mut param = Self::param_template(node, env);
3255                 param.is_variadic = true;
3256                 Ok(param)
3257             }
3258             _ => Self::missing_syntax("function parameter", node, env),
3259         }
3260     }
3262     fn p_tconstraint_ty(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Hint> {
3263         match &node.children {
3264             TypeConstraint(c) => Self::p_hint(&c.type_, env),
3265             _ => Self::missing_syntax("type constraint", node, env),
3266         }
3267     }
3269     fn p_tconstraint(
3270         node: S<'a, T, V>,
3271         env: &mut Env<'a, TF>,
3272     ) -> Result<(ast::ConstraintKind, ast::Hint)> {
3273         match &node.children {
3274             TypeConstraint(c) => Ok((
3275                 match Self::token_kind(&c.keyword) {
3276                     Some(TK::As) => ast::ConstraintKind::ConstraintAs,
3277                     Some(TK::Super) => ast::ConstraintKind::ConstraintSuper,
3278                     Some(TK::Equal) => ast::ConstraintKind::ConstraintEq,
3279                     _ => Self::missing_syntax("constraint operator", &c.keyword, env)?,
3280                 },
3281                 Self::p_hint(&c.type_, env)?,
3282             )),
3283             _ => Self::missing_syntax("type constraint", node, env),
3284         }
3285     }
3287     fn p_tparam(is_class: bool, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Tparam> {
3288         match &node.children {
3289             TypeParameter(TypeParameterChildren {
3290                 attribute_spec,
3291                 reified,
3292                 variance,
3293                 name,
3294                 param_params,
3295                 constraints,
3296             }) => {
3297                 let user_attributes = Self::p_user_attributes(attribute_spec, env)?;
3298                 let is_reified = !reified.is_missing();
3299                 if is_class && is_reified {
3300                     let type_name = Self::text(name, env);
3301                     env.cls_reified_generics().insert(type_name);
3302                 }
3303                 let variance = match Self::token_kind(variance) {
3304                     Some(TK::Plus) => ast::Variance::Covariant,
3305                     Some(TK::Minus) => ast::Variance::Contravariant,
3306                     _ => ast::Variance::Invariant,
3307                 };
3308                 if is_reified && variance != ast::Variance::Invariant {
3309                     Self::raise_parsing_error(
3310                         node,
3311                         env,
3312                         &syntax_error::non_invariant_reified_generic,
3313                     );
3314                 }
3315                 let reified = match (is_reified, Self::has_soft(&user_attributes)) {
3316                     (true, true) => ast::ReifyKind::SoftReified,
3317                     (true, false) => ast::ReifyKind::Reified,
3318                     _ => ast::ReifyKind::Erased,
3319                 };
3320                 let parameters = Self::p_tparam_l(is_class, param_params, env)?;
3321                 Ok(ast::Tparam {
3322                     variance,
3323                     name: Self::pos_name(name, env)?,
3324                     parameters,
3325                     constraints: Self::could_map(Self::p_tconstraint, constraints, env)?,
3326                     reified,
3327                     user_attributes,
3328                 })
3329             }
3330             _ => Self::missing_syntax("type parameter", node, env),
3331         }
3332     }
3334     fn p_tparam_l(
3335         is_class: bool,
3336         node: S<'a, T, V>,
3337         env: &mut Env<'a, TF>,
3338     ) -> Result<Vec<ast::Tparam>> {
3339         match &node.children {
3340             Missing => Ok(vec![]),
3341             TypeParameters(c) => {
3342                 Self::could_map(|n, e| Self::p_tparam(is_class, n, e), &c.parameters, env)
3343             }
3344             _ => Self::missing_syntax("type parameter", node, env),
3345         }
3346     }
3348     fn p_capability(
3349         node: S<'a, T, V>,
3350         env: &mut Env<'a, TF>,
3351     ) -> Result<(Option<ast::Hint>, Option<ast::Hint>)> {
3352         match &node.children {
3353             Missing => Ok((None, None)),
3354             Capability(c) => {
3355                 let mut hints = Self::could_map(&Self::p_hint, &c.types, env)?;
3356                 let hint_ = if hints.len() == 1 {
3357                     *hints.pop().unwrap().1
3358                 } else {
3359                     /* Could make [] into Hmixed, but it just turns into empty intersection anyway */
3360                     ast::Hint_::Hintersection(hints)
3361                 };
3362                 let pos = Self::p_pos(node, env);
3363                 let hint = ast::Hint::new(pos, hint_);
3364                 let unsafe_hint = hint.clone();
3365                 Ok((Some(hint), Some(unsafe_hint)))
3366             }
3367             _ => Self::missing_syntax("capability", node, env),
3368         }
3369     }
3371     fn p_capability_provisional(
3372         node: S<'a, T, V>,
3373         env: &mut Env<'a, TF>,
3374     ) -> Result<(Option<ast::Hint>, Option<ast::Hint>)> {
3375         match &node.children {
3376             Missing => Ok((None, None)),
3377             CapabilityProvisional(c) => {
3378                 let cap = Self::p_hint(&c.type_, env)?;
3379                 let unsafe_cap = Self::mp_optional(Self::p_hint, &c.unsafe_type, env)?;
3380                 Ok((Some(cap), unsafe_cap))
3381             }
3382             _ => Self::missing_syntax("capability_provisional", node, env),
3383         }
3384     }
3386     /* Just temporary to handle both syntaxes. This will be removed when p_capability_provisional is removed */
3387     fn p_cap(
3388         capability: S<'a, T, V>,
3389         capability_provisional: S<'a, T, V>,
3390         env: &mut Env<'a, TF>,
3391     ) -> Result<(Option<ast::Hint>, Option<ast::Hint>)> {
3392         if !capability.is_missing() && !capability_provisional.is_missing() {
3393             Self::raise_parsing_error(
3394                 capability_provisional,
3395                 env,
3396                 "Cannot use both the [ and @{ syntax for coeffects",
3397             );
3398             /* Not exactly missing, but this is the standard function used to get an Err result in the lowerer */
3399             Self::missing_syntax("capability", capability, env)
3400         } else if !capability.is_missing() {
3401             Self::p_capability(capability, env)
3402         } else {
3403             Self::p_capability_provisional(capability_provisional, env)
3404         }
3405     }
3407     fn p_fun_hdr(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<FunHdr> {
3408         match &node.children {
3409             FunctionDeclarationHeader(FunctionDeclarationHeaderChildren {
3410                 modifiers,
3411                 name,
3412                 where_clause,
3413                 type_parameter_list,
3414                 parameter_list,
3415                 type_,
3416                 capability,
3417                 capability_provisional,
3418                 ..
3419             }) => {
3420                 if name.value.is_missing() {
3421                     Self::raise_parsing_error(name, env, &syntax_error::empty_method_name);
3422                 }
3423                 let kinds = Self::p_kinds(modifiers, env)?;
3424                 let has_async = kinds.has(modifier::ASYNC);
3425                 let parameters = Self::could_map(Self::p_fun_param, parameter_list, env)?;
3426                 let (capability, unsafe_capability) =
3427                     Self::p_cap(capability, capability_provisional, env)?;
3428                 let return_type = Self::mp_optional(Self::p_hint, type_, env)?;
3429                 let suspension_kind = Self::mk_suspension_kind_(has_async);
3430                 let name = Self::pos_name(name, env)?;
3431                 let constrs = Self::p_where_constraint(false, node, where_clause, env)?;
3432                 let type_parameters = Self::p_tparam_l(false, type_parameter_list, env)?;
3433                 Ok(FunHdr {
3434                     suspension_kind,
3435                     name,
3436                     constrs,
3437                     type_parameters,
3438                     parameters,
3439                     capability,
3440                     unsafe_capability,
3441                     return_type,
3442                 })
3443             }
3444             LambdaSignature(LambdaSignatureChildren {
3445                 parameters,
3446                 capability,
3447                 type_,
3448                 ..
3449             }) => {
3450                 let mut header = FunHdr::make_empty(env);
3451                 header.parameters = Self::could_map(Self::p_fun_param, parameters, env)?;
3452                 let (capability, unsafe_capability) = Self::p_capability(capability, env)?;
3453                 header.capability = capability;
3454                 header.unsafe_capability = unsafe_capability;
3455                 header.return_type = Self::mp_optional(Self::p_hint, type_, env)?;
3456                 Ok(header)
3457             }
3458             Token(_) => Ok(FunHdr::make_empty(env)),
3459             _ => Self::missing_syntax("function header", node, env),
3460         }
3461     }
3463     fn determine_variadicity(params: &[ast::FunParam]) -> ast::FunVariadicity {
3464         use aast::FunVariadicity::*;
3465         if let Some(x) = params.last() {
3466             match (x.is_variadic, &x.name) {
3467                 (false, _) => FVnonVariadic,
3468                 (true, name) if name == "..." => FVellipsis(x.pos.clone()),
3469                 (true, _) => FVvariadicArg(x.clone()),
3470             }
3471         } else {
3472             FVnonVariadic
3473         }
3474     }
3476     fn p_fun_pos(node: S<'a, T, V>, env: &Env<TF>) -> Pos {
3477         let get_pos = |n: S<'a, T, V>, p: Pos| -> Pos {
3478             if let FunctionDeclarationHeader(c1) = &n.children {
3479                 if !c1.keyword.is_missing() {
3480                     return Pos::btw_nocheck(Self::p_pos(&c1.keyword, env), p);
3481                 }
3482             }
3483             p
3484         };
3485         let p = Self::p_pos(node, env);
3486         match &node.children {
3487             FunctionDeclaration(c) if env.codegen() => get_pos(&c.declaration_header, p),
3488             MethodishDeclaration(c) if env.codegen() => get_pos(&c.function_decl_header, p),
3489             _ => p,
3490         }
3491     }
3493     fn p_block(remove_noop: bool, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Block> {
3494         let ast::Stmt(p, stmt_) = Self::p_stmt(node, env)?;
3495         if let ast::Stmt_::Block(blk) = stmt_ {
3496             if remove_noop && blk.len() == 1 && blk[0].1.is_noop() {
3497                 return Ok(vec![]);
3498             }
3499             return Ok(blk);
3500         } else {
3501             Ok(vec![ast::Stmt(p, stmt_)])
3502         }
3503     }
3505     fn mk_noop(env: &Env<TF>) -> ast::Stmt {
3506         ast::Stmt::noop(env.mk_none_pos())
3507     }
3509     fn p_function_body(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Block> {
3510         let mk_noop_result = |e: &Env<TF>| Ok(vec![Self::mk_noop(e)]);
3511         let f = |e: &mut Env<'a, TF>| -> Result<ast::Block> {
3512             match &node.children {
3513                 Missing => Ok(vec![]),
3514                 CompoundStatement(c) => {
3515                     let compound_statements = &c.statements.children;
3516                     let compound_right_brace = &c.right_brace.children;
3517                     match (compound_statements, compound_right_brace) {
3518                         (Missing, Token(_)) => mk_noop_result(e),
3519                         (SyntaxList(t), _) if t.len() == 1 && t[0].is_yield() => {
3520                             e.saw_yield = true;
3521                             mk_noop_result(e)
3522                         }
3523                         _ => {
3524                             if !e.top_level_statements
3525                                 && ((e.file_mode() == file_info::Mode::Mdecl && !e.codegen())
3526                                     || e.quick_mode)
3527                             {
3528                                 mk_noop_result(e)
3529                             } else {
3530                                 Self::p_block(false /*remove noop*/, node, e)
3531                             }
3532                         }
3533                     }
3534                 }
3535                 _ => {
3536                     let f = |e: &mut Env<'a, TF>| {
3537                         let expr = Self::p_expr(node, e)?;
3538                         Ok(ast::Stmt::new(
3539                             expr.0.clone(),
3540                             ast::Stmt_::mk_return(Some(expr)),
3541                         ))
3542                     };
3543                     if Self::is_simple_await_expression(node) {
3544                         Ok(vec![f(e)?])
3545                     } else {
3546                         Ok(vec![Self::lift_awaits_in_statement(f, node, e)?])
3547                     }
3548                 }
3549             }
3550         };
3551         Self::with_new_nonconcurrent_scope(f, env)
3552     }
3554     fn mk_suspension_kind(async_keyword: S<'a, T, V>) -> SuspensionKind {
3555         Self::mk_suspension_kind_(!async_keyword.is_missing())
3556     }
3558     fn mk_suspension_kind_(has_async: bool) -> SuspensionKind {
3559         if has_async {
3560             SuspensionKind::SKAsync
3561         } else {
3562             SuspensionKind::SKSync
3563         }
3564     }
3566     fn mk_fun_kind(suspension_kind: SuspensionKind, yield_: bool) -> ast::FunKind {
3567         use ast::FunKind::*;
3568         use SuspensionKind::*;
3569         match (suspension_kind, yield_) {
3570             (SKSync, true) => FGenerator,
3571             (SKAsync, true) => FAsyncGenerator,
3572             (SKSync, false) => FSync,
3573             (SKAsync, false) => FAsync,
3574         }
3575     }
3577     fn process_attribute_constructor_call(
3578         node: S<'a, T, V>,
3579         constructor_call_argument_list: S<'a, T, V>,
3580         constructor_call_type: S<'a, T, V>,
3581         env: &mut Env<'a, TF>,
3582     ) -> Result<ast::UserAttribute> {
3583         let name = Self::pos_name(constructor_call_type, env)?;
3584         if name.1.eq_ignore_ascii_case("__reified")
3585             || name.1.eq_ignore_ascii_case("__hasreifiedparent")
3586         {
3587             Self::raise_parsing_error(node, env, &syntax_error::reified_attribute);
3588         } else if name.1.eq_ignore_ascii_case(special_attrs::SOFT)
3589             && constructor_call_argument_list
3590                 .syntax_node_to_list_skip_separator()
3591                 .count()
3592                 > 0
3593         {
3594             Self::raise_parsing_error(node, env, &syntax_error::soft_no_arguments);
3595         }
3596         let params = Self::could_map(
3597             |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::Expr> {
3598                 Self::is_valid_attribute_arg(n, e);
3599                 Self::p_expr(n, e)
3600             },
3601             constructor_call_argument_list,
3602             env,
3603         )?;
3604         Ok(ast::UserAttribute { name, params })
3605     }
3607     // Arguments to attributes must be literals (int, string, etc), collections
3608     // (eg vec, dict, keyset, etc), Foo::class strings, shapes, string
3609     // concatenations, or tuples.
3610     fn is_valid_attribute_arg(node: S<'a, T, V>, env: &mut Env<'a, TF>) {
3611         let mut is_valid_list = |nodes: S<'a, T, V>| {
3612             let _ = Self::could_map(
3613                 |n, e| {
3614                     Self::is_valid_attribute_arg(n, e);
3615                     Ok(())
3616                 },
3617                 nodes,
3618                 env,
3619             );
3620             ()
3621         };
3622         match &node.children {
3623             ParenthesizedExpression(c) => Self::is_valid_attribute_arg(&c.expression, env),
3624             // Normal literals (string, int, etc)
3625             LiteralExpression(_) => {}
3626             // ::class strings
3627             ScopeResolutionExpression(c) => {
3628                 if let Some(TK::Class) = Self::token_kind(&c.name) {
3629                 } else {
3630                     Self::raise_parsing_error(
3631                         node,
3632                         env,
3633                         &syntax_error::expression_as_attribute_arguments,
3634                     );
3635                 }
3636             }
3637             // Negations
3638             PrefixUnaryExpression(c) => {
3639                 Self::is_valid_attribute_arg(&c.operand, env);
3640                 match Self::token_kind(&c.operator) {
3641                     Some(TK::Minus) => {}
3642                     Some(TK::Plus) => {}
3643                     _ => Self::raise_parsing_error(
3644                         node,
3645                         env,
3646                         &syntax_error::expression_as_attribute_arguments,
3647                     ),
3648                 }
3649             }
3650             // String concatenation
3651             BinaryExpression(c) => {
3652                 if let Some(TK::Dot) = Self::token_kind(&c.operator) {
3653                     Self::is_valid_attribute_arg(&c.left_operand, env);
3654                     Self::is_valid_attribute_arg(&c.right_operand, env);
3655                 } else {
3656                     Self::raise_parsing_error(
3657                         node,
3658                         env,
3659                         &syntax_error::expression_as_attribute_arguments,
3660                     );
3661                 }
3662             }
3663             // Top-level Collections
3664             DarrayIntrinsicExpression(c) => is_valid_list(&c.members),
3665             DictionaryIntrinsicExpression(c) => is_valid_list(&c.members),
3666             KeysetIntrinsicExpression(c) => is_valid_list(&c.members),
3667             VarrayIntrinsicExpression(c) => is_valid_list(&c.members),
3668             VectorIntrinsicExpression(c) => is_valid_list(&c.members),
3669             ShapeExpression(c) => is_valid_list(&c.fields),
3670             TupleExpression(c) => is_valid_list(&c.items),
3671             // Collection Internals
3672             FieldInitializer(c) => {
3673                 Self::is_valid_attribute_arg(&c.name, env);
3674                 Self::is_valid_attribute_arg(&c.value, env);
3675             }
3676             ElementInitializer(c) => {
3677                 Self::is_valid_attribute_arg(&c.key, env);
3678                 Self::is_valid_attribute_arg(&c.value, env);
3679             }
3680             // Everything else is not allowed
3681             _ => Self::raise_parsing_error(
3682                 node,
3683                 env,
3684                 &syntax_error::expression_as_attribute_arguments,
3685             ),
3686         }
3687     }
3689     fn p_user_attribute(
3690         node: S<'a, T, V>,
3691         env: &mut Env<'a, TF>,
3692     ) -> Result<Vec<ast::UserAttribute>> {
3693         let p_attr = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::UserAttribute> {
3694             match &n.children {
3695                 ConstructorCall(c) => {
3696                     Self::process_attribute_constructor_call(node, &c.argument_list, &c.type_, e)
3697                 }
3698                 _ => Self::missing_syntax("attribute", node, e),
3699             }
3700         };
3701         match &node.children {
3702             FileAttributeSpecification(c) => Self::could_map(p_attr, &c.attributes, env),
3703             OldAttributeSpecification(c) => Self::could_map(p_attr, &c.attributes, env),
3704             AttributeSpecification(c) => Self::could_map(
3705                 |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::UserAttribute> {
3706                     match &n.children {
3707                         Attribute(c) => p_attr(&c.attribute_name, e),
3708                         _ => Self::missing_syntax("attribute", node, e),
3709                     }
3710                 },
3711                 &c.attributes,
3712                 env,
3713             ),
3714             _ => Self::missing_syntax("attribute specification", node, env),
3715         }
3716     }
3718     fn p_user_attributes(
3719         node: S<'a, T, V>,
3720         env: &mut Env<'a, TF>,
3721     ) -> Result<Vec<ast::UserAttribute>> {
3722         Self::map_fold(
3723             &Self::p_user_attribute,
3724             &|mut acc: Vec<ast::UserAttribute>, mut x: Vec<ast::UserAttribute>| {
3725                 acc.append(&mut x);
3726                 acc
3727             },
3728             node,
3729             env,
3730             vec![],
3731         )
3732     }
3734     fn mp_yielding<F, R>(p: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<(R, bool)>
3735     where
3736         F: FnOnce(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
3737     {
3738         let outer_saw_yield = env.saw_yield;
3739         env.saw_yield = false;
3740         let r = p(node, env);
3741         let saw_yield = env.saw_yield;
3742         env.saw_yield = outer_saw_yield;
3743         Ok((r?, saw_yield))
3744     }
3746     fn mk_empty_ns_env(env: &Env<TF>) -> RcOc<NamespaceEnv> {
3747         RcOc::clone(&env.empty_ns_env)
3748     }
3750     fn extract_docblock(node: S<'a, T, V>, env: &Env<TF>) -> Option<DocComment> {
3751         #[derive(Copy, Clone, Eq, PartialEq)]
3752         enum ScanState {
3753             DocComment,
3754             EmbeddedCmt,
3755             EndDoc,
3756             EndEmbedded,
3757             Free,
3758             LineCmt,
3759             MaybeDoc,
3760             MaybeDoc2,
3761             SawSlash,
3762         }
3763         use ScanState::*;
3764         // `parse` mixes loop and recursion to use less stack space.
3765         fn parse(
3766             str: &str,
3767             start: usize,
3768             state: ScanState,
3769             idx: usize,
3770         ) -> Option<(usize, usize, String)> {
3771             let is_whitespace = |c| c == ' ' || c == '\t' || c == '\n' || c == '\r';
3772             let mut s = (start, state, idx);
3773             let chars = str.as_bytes();
3774             loop {
3775                 if s.2 == str.len() {
3776                     break None;
3777                 }
3779                 let next = s.2 + 1;
3780                 match (s.1, chars[s.2] as char) {
3781                     (LineCmt, '\n') => s = (next, Free, next),
3782                     (EndEmbedded, '/') => s = (next, Free, next),
3783                     (EndDoc, '/') => {
3784                         let r = parse(str, next, Free, next);
3785                         match r {
3786                             d @ Some(_) => break d,
3787                             None => break Some((s.0, s.2 + 1, String::from(&str[s.0..s.2 + 1]))),
3788                         }
3789                     }
3790                     /* PHP has line comments delimited by a # */
3791                     (Free, '#') => s = (next, LineCmt, next),
3792                     /* All other comment delimiters start with a / */
3793                     (Free, '/') => s = (s.2, SawSlash, next),
3794                     /* After a / in trivia, we must see either another / or a * */
3795                     (SawSlash, '/') => s = (next, LineCmt, next),
3796                     (SawSlash, '*') => s = (s.0, MaybeDoc, next),
3797                     (MaybeDoc, '*') => s = (s.0, MaybeDoc2, next),
3798                     (MaybeDoc, _) => s = (s.0, EmbeddedCmt, next),
3799                     (MaybeDoc2, '/') => s = (next, Free, next),
3800                     /* Doc comments have a space after the second star */
3801                     (MaybeDoc2, c) if is_whitespace(c) => s = (s.0, DocComment, s.2),
3802                     (MaybeDoc2, _) => s = (s.0, EmbeddedCmt, next),
3803                     (DocComment, '*') => s = (s.0, EndDoc, next),
3804                     (DocComment, _) => s = (s.0, DocComment, next),
3805                     (EndDoc, _) => s = (s.0, DocComment, next),
3806                     /* A * without a / does not end an embedded comment */
3807                     (EmbeddedCmt, '*') => s = (s.0, EndEmbedded, next),
3808                     (EndEmbedded, '*') => s = (s.0, EndEmbedded, next),
3809                     (EndEmbedded, _) => s = (s.0, EmbeddedCmt, next),
3810                     /* Whitespace skips everywhere else */
3811                     (_, c) if is_whitespace(c) => s = (s.0, s.1, next),
3812                     /* When scanning comments, anything else is accepted */
3813                     (LineCmt, _) => s = (s.0, s.1, next),
3814                     (EmbeddedCmt, _) => s = (s.0, s.1, next),
3815                     _ => break None,
3816                 }
3817             }
3818         }
3819         let str = node.leading_text(env.indexed_source_text.source_text());
3820         parse(str, 0, Free, 0).map(|(start, end, txt)| {
3821             let anchor = node.leading_start_offset();
3822             let pos = env
3823                 .indexed_source_text
3824                 .relative_pos(anchor + start, anchor + end);
3825             let ps = (pos, txt);
3826             oxidized::doc_comment::DocComment::new(ps)
3827         })
3828     }
3830     fn p_xhp_child(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::XhpChild> {
3831         use ast::XhpChild::*;
3832         use ast::XhpChildOp::*;
3833         match &node.children {
3834             Token(_) => Self::pos_name(node, env).map(ChildName),
3835             PostfixUnaryExpression(c) => {
3836                 let operand = Self::p_xhp_child(&c.operand, env)?;
3837                 let operator = match Self::token_kind(&c.operator) {
3838                     Some(TK::Question) => ChildQuestion,
3839                     Some(TK::Plus) => ChildPlus,
3840                     Some(TK::Star) => ChildStar,
3841                     _ => Self::missing_syntax("xhp children operator", node, env)?,
3842                 };
3843                 Ok(ChildUnary(Box::new(operand), operator))
3844             }
3845             BinaryExpression(c) => {
3846                 let left = Self::p_xhp_child(&c.left_operand, env)?;
3847                 let right = Self::p_xhp_child(&c.right_operand, env)?;
3848                 Ok(ChildBinary(Box::new(left), Box::new(right)))
3849             }
3850             XHPChildrenParenthesizedList(c) => {
3851                 let children: std::result::Result<Vec<_>, _> = c
3852                     .xhp_children
3853                     .syntax_node_to_list_skip_separator()
3854                     .map(|c| Self::p_xhp_child(c, env))
3855                     .collect();
3856                 Ok(ChildList(children?))
3857             }
3858             _ => Self::missing_syntax("xhp children", node, env),
3859         }
3860     }
3862     fn p_class_elt_(
3863         class: &mut ast::Class_,
3864         node: S<'a, T, V>,
3865         env: &mut Env<'a, TF>,
3866     ) -> Result<()> {
3867         use ast::Visibility;
3868         let doc_comment_opt = Self::extract_docblock(node, env);
3869         let has_fun_header = |m: &MethodishDeclarationChildren<T, V>| {
3870             matches!(
3871                 m.function_decl_header.children,
3872                 FunctionDeclarationHeader(_)
3873             )
3874         };
3875         let p_method_vis = |
3876             node: S<'a, T, V>,
3877             name_pos: &Pos,
3878             env: &mut Env<'a, TF>,
3879         | -> Result<Visibility> {
3880             match Self::p_visibility_last_win(node, env)? {
3881                 None => {
3882                     Self::raise_hh_error(env, Naming::method_needs_visibility(name_pos.clone()));
3883                     Ok(Visibility::Public)
3884                 }
3885                 Some(v) => Ok(v),
3886             }
3887         };
3888         match &node.children {
3889             ConstDeclaration(c) => {
3890                 // TODO: make wrap `type_` `doc_comment` by `Rc` in ClassConst to avoid clone
3891                 let type_ = Self::mp_optional(Self::p_hint, &c.type_specifier, env)?;
3892                 // using map_fold can save one Vec allocation, but ocaml's behavior is that
3893                 // if anything throw, it will discard all lowered elements. So adding to class
3894                 // must be at the last.
3895                 let mut class_consts = Self::could_map(
3896                     |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::ClassConst> {
3897                         match &n.children {
3898                             ConstantDeclarator(c) => {
3899                                 let id = Self::pos_name(&c.name, e)?;
3900                                 let expr = if n.is_abstract() {
3901                                     None
3902                                 } else {
3903                                     Self::mp_optional(
3904                                         Self::p_simple_initializer,
3905                                         &c.initializer,
3906                                         e,
3907                                     )?
3908                                 };
3909                                 Ok(ast::ClassConst {
3910                                     type_: type_.clone(),
3911                                     id,
3912                                     expr,
3913                                     doc_comment: doc_comment_opt.clone(),
3914                                 })
3915                             }
3916                             _ => Self::missing_syntax("constant declarator", n, e),
3917                         }
3918                     },
3919                     &c.declarators,
3920                     env,
3921                 )?;
3922                 Ok(class.consts.append(&mut class_consts))
3923             }
3924             TypeConstDeclaration(c) => {
3925                 if !c.type_parameters.is_missing() {
3926                     Self::raise_parsing_error(node, env, &syntax_error::tparams_in_tconst);
3927                 }
3928                 let user_attributes = Self::p_user_attributes(&c.attribute_spec, env)?;
3929                 let type__ = Self::mp_optional(Self::p_hint, &c.type_specifier, env)?
3930                     .map(|hint| Self::soften_hint(&user_attributes, hint));
3931                 let kinds = Self::p_kinds(&c.modifiers, env)?;
3932                 let name = Self::pos_name(&c.name, env)?;
3933                 let constraint =
3934                     Self::mp_optional(Self::p_tconstraint_ty, &c.type_constraint, env)?;
3935                 let span = Self::p_pos(node, env);
3936                 let has_abstract = kinds.has(modifier::ABSTRACT);
3937                 let (type_, abstract_kind) = match (has_abstract, &constraint, &type__) {
3938                     (false, _, None) => {
3939                         Self::raise_hh_error(
3940                             env,
3941                             NastCheck::not_abstract_without_typeconst(name.0.clone()),
3942                         );
3943                         (constraint.clone(), ast::TypeconstAbstractKind::TCConcrete)
3944                     }
3945                     (false, None, Some(_)) => (type__, ast::TypeconstAbstractKind::TCConcrete),
3946                     (false, Some(_), Some(_)) => {
3947                         (type__, ast::TypeconstAbstractKind::TCPartiallyAbstract)
3948                     }
3949                     (true, _, None) => (
3950                         type__.clone(),
3951                         ast::TypeconstAbstractKind::TCAbstract(type__),
3952                     ),
3953                     (true, _, Some(_)) => (None, ast::TypeconstAbstractKind::TCAbstract(type__)),
3954                 };
3955                 Ok(class.typeconsts.push(ast::ClassTypeconst {
3956                     abstract_: abstract_kind,
3957                     name,
3958                     constraint,
3959                     type_,
3960                     user_attributes,
3961                     span,
3962                     doc_comment: doc_comment_opt,
3963                 }))
3964             }
3965             PropertyDeclaration(c) => {
3966                 let user_attributes = Self::p_user_attributes(&c.attribute_spec, env)?;
3967                 let type_ = Self::mp_optional(Self::p_hint, &c.type_, env)?
3968                     .map(|t| Self::soften_hint(&user_attributes, t));
3969                 let kinds = Self::p_kinds(&c.modifiers, env)?;
3970                 let vis = Self::p_visibility_last_win_or(&c.modifiers, env, Visibility::Public)?;
3971                 let doc_comment = if env.quick_mode {
3972                     None
3973                 } else {
3974                     doc_comment_opt
3975                 };
3976                 let name_exprs = Self::could_map(
3977                     |n, e| -> Result<(Pos, ast::Sid, Option<ast::Expr>)> {
3978                         match &n.children {
3979                             PropertyDeclarator(c) => {
3980                                 let name = Self::pos_name_(&c.name, e, Some('$'))?;
3981                                 let pos = Self::p_pos(n, e);
3982                                 let expr = Self::mp_optional(
3983                                     Self::p_simple_initializer,
3984                                     &c.initializer,
3985                                     e,
3986                                 )?;
3987                                 Ok((pos, name, expr))
3988                             }
3989                             _ => Self::missing_syntax("property declarator", n, e),
3990                         }
3991                     },
3992                     &c.declarators,
3993                     env,
3994                 )?;
3996                 let mut i = 0;
3997                 for name_expr in name_exprs.into_iter() {
3998                     class.vars.push(ast::ClassVar {
3999                         final_: kinds.has(modifier::FINAL),
4000                         xhp_attr: None,
4001                         abstract_: kinds.has(modifier::ABSTRACT),
4002                         visibility: vis,
4003                         type_: ast::TypeHint((), type_.clone()),
4004                         id: name_expr.1,
4005                         expr: name_expr.2,
4006                         user_attributes: user_attributes.clone(),
4007                         doc_comment: if i == 0 { doc_comment.clone() } else { None },
4008                         is_promoted_variadic: false,
4009                         is_static: kinds.has(modifier::STATIC),
4010                         span: name_expr.0,
4011                     });
4012                     i += 1;
4013                 }
4014                 Ok(())
4015             }
4016             MethodishDeclaration(c) if has_fun_header(c) => {
4017                 let classvar_init = |param: &ast::FunParam| -> (ast::Stmt, ast::ClassVar) {
4018                     let cvname = Self::drop_prefix(&param.name, '$');
4019                     let p = &param.pos;
4020                     let span = match &param.expr {
4021                         Some(ast::Expr(pos_end, _)) => {
4022                             Pos::btw(p, pos_end).unwrap_or_else(|_| p.clone())
4023                         }
4024                         _ => p.clone(),
4025                     };
4026                     let e = |expr_: ast::Expr_| -> ast::Expr { ast::Expr::new(p.clone(), expr_) };
4027                     let lid = |s: &str| -> ast::Lid { ast::Lid(p.clone(), (0, s.to_string())) };
4028                     (
4029                         ast::Stmt::new(
4030                             p.clone(),
4031                             ast::Stmt_::mk_expr(e(E_::mk_binop(
4032                                 ast::Bop::Eq(None),
4033                                 e(E_::mk_obj_get(
4034                                     e(E_::mk_lvar(lid(special_idents::THIS))),
4035                                     e(E_::mk_id(ast::Id(p.clone(), cvname.to_string()))),
4036                                     ast::OgNullFlavor::OGNullthrows,
4037                                     false,
4038                                 )),
4039                                 e(E_::mk_lvar(lid(&param.name))),
4040                             ))),
4041                         ),
4042                         ast::ClassVar {
4043                             final_: false,
4044                             xhp_attr: None,
4045                             abstract_: false,
4046                             visibility: param.visibility.unwrap(),
4047                             type_: param.type_hint.clone(),
4048                             id: ast::Id(p.clone(), cvname.to_string()),
4049                             expr: None,
4050                             user_attributes: param.user_attributes.clone(),
4051                             doc_comment: None,
4052                             is_promoted_variadic: param.is_variadic,
4053                             is_static: false,
4054                             span,
4055                         },
4056                     )
4057                 };
4058                 let header = &c.function_decl_header;
4059                 let h = match &header.children {
4060                     FunctionDeclarationHeader(h) => h,
4061                     _ => panic!(),
4062                 };
4063                 let hdr = Self::p_fun_hdr(header, env)?;
4064                 if hdr.name.1 == special_members::__CONSTRUCT && !hdr.type_parameters.is_empty() {
4065                     Self::raise_parsing_error(
4066                         header,
4067                         env,
4068                         &syntax_error::no_generics_on_constructors,
4069                     );
4070                 }
4071                 let (mut member_init, mut member_def): (Vec<ast::Stmt>, Vec<ast::ClassVar>) = hdr
4072                     .parameters
4073                     .iter()
4074                     .filter_map(|p| p.visibility.map(|_| classvar_init(p)))
4075                     .unzip();
4077                 let kinds = Self::p_kinds(&h.modifiers, env)?;
4078                 let visibility = p_method_vis(&h.modifiers, &hdr.name.0, env)?;
4079                 let is_static = kinds.has(modifier::STATIC);
4080                 *env.in_static_method() = is_static;
4081                 let (mut body, body_has_yield) =
4082                     Self::mp_yielding(Self::p_function_body, &c.function_body, env)?;
4083                 if env.codegen() {
4084                     member_init.reverse();
4085                 }
4086                 member_init.append(&mut body);
4087                 let body = member_init;
4088                 *env.in_static_method() = false;
4089                 let is_abstract = kinds.has(modifier::ABSTRACT);
4090                 let is_external = !is_abstract && c.function_body.is_external();
4091                 let user_attributes = Self::p_user_attributes(&c.attribute, env)?;
4092                 let cap = ast::TypeHint((), hdr.capability);
4093                 let unsafe_cap = ast::TypeHint((), hdr.unsafe_capability);
4094                 let method = ast::Method_ {
4095                     span: Self::p_fun_pos(node, env),
4096                     annotation: (),
4097                     final_: kinds.has(modifier::FINAL),
4098                     abstract_: is_abstract,
4099                     static_: is_static,
4100                     name: hdr.name,
4101                     visibility,
4102                     tparams: hdr.type_parameters,
4103                     where_constraints: hdr.constrs,
4104                     variadic: Self::determine_variadicity(&hdr.parameters),
4105                     params: hdr.parameters,
4106                     cap,
4107                     unsafe_cap,
4108                     body: ast::FuncBody {
4109                         annotation: (),
4110                         ast: body,
4111                     },
4112                     fun_kind: Self::mk_fun_kind(hdr.suspension_kind, body_has_yield),
4113                     user_attributes,
4114                     ret: ast::TypeHint((), hdr.return_type),
4115                     external: is_external,
4116                     doc_comment: doc_comment_opt,
4117                 };
4118                 class.vars.append(&mut member_def);
4119                 Ok(class.methods.push(method))
4120             }
4121             TraitUseConflictResolution(c) => {
4122                 type Ret = Result<Either<ast::InsteadofAlias, ast::UseAsAlias>>;
4123                 let p_item = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Ret {
4124                     match &n.children {
4125                         TraitUsePrecedenceItem(c) => {
4126                             let (qualifier, name) = match &c.name.children {
4127                                 ScopeResolutionExpression(c) => (
4128                                     Self::pos_name(&c.qualifier, e)?,
4129                                     Self::p_pstring(&c.name, e)?,
4130                                 ),
4131                                 _ => Self::missing_syntax("trait use precedence item", n, e)?,
4132                             };
4133                             let removed_names =
4134                                 Self::could_map(Self::pos_name, &c.removed_names, e)?;
4135                             Self::raise_hh_error(e, Naming::unsupported_instead_of(name.0.clone()));
4136                             Ok(Either::Left(ast::InsteadofAlias(
4137                                 qualifier,
4138                                 name,
4139                                 removed_names,
4140                             )))
4141                         }
4142                         TraitUseAliasItem(c) => {
4143                             let (qualifier, name) = match &c.aliasing_name.children {
4144                                 ScopeResolutionExpression(c) => (
4145                                     Some(Self::pos_name(&c.qualifier, e)?),
4146                                     Self::p_pstring(&c.name, e)?,
4147                                 ),
4148                                 _ => (None, Self::p_pstring(&c.aliasing_name, e)?),
4149                             };
4150                             let (kinds, mut vis_raw) = Self::p_modifiers(
4151                                 |mut acc, kind| -> Vec<ast::UseAsVisibility> {
4152                                     if let Some(v) = modifier::to_use_as_visibility(kind) {
4153                                         acc.push(v);
4154                                     }
4155                                     acc
4156                                 },
4157                                 vec![],
4158                                 &c.modifiers,
4159                                 e,
4160                             )?;
4161                             let vis = if kinds.is_empty() || kinds.has_any(modifier::VISIBILITIES) {
4162                                 vis_raw
4163                             } else {
4164                                 let mut v = vec![ast::UseAsVisibility::UseAsPublic];
4165                                 v.append(&mut vis_raw);
4166                                 v
4167                             };
4168                             let aliased_name = if !c.aliased_name.is_missing() {
4169                                 Some(Self::pos_name(&c.aliased_name, e)?)
4170                             } else {
4171                                 None
4172                             };
4173                             Self::raise_hh_error(
4174                                 e,
4175                                 Naming::unsupported_trait_use_as(name.0.clone()),
4176                             );
4177                             Ok(Either::Right(ast::UseAsAlias(
4178                                 qualifier,
4179                                 name,
4180                                 aliased_name,
4181                                 vis,
4182                             )))
4183                         }
4184                         _ => Self::missing_syntax("trait use conflict resolution item", n, e),
4185                     }
4186                 };
4187                 let mut uses = Self::could_map(Self::p_hint, &c.names, env)?;
4188                 let elts = Self::could_map(p_item, &c.clauses, env)?;
4189                 class.uses.append(&mut uses);
4190                 for elt in elts.into_iter() {
4191                     match elt {
4192                         Either::Left(l) => class.insteadof_alias.push(l),
4193                         Either::Right(r) => class.use_as_alias.push(r),
4194                     }
4195                 }
4196                 Ok(())
4197             }
4198             TraitUse(c) => {
4199                 let mut uses = Self::could_map(Self::p_hint, &c.names, env)?;
4200                 Ok(class.uses.append(&mut uses))
4201             }
4202             RequireClause(c) => {
4203                 let hint = Self::p_hint(&c.name, env)?;
4204                 let is_extends = match Self::token_kind(&c.kind) {
4205                     Some(TK::Implements) => false,
4206                     Some(TK::Extends) => true,
4207                     _ => Self::missing_syntax("trait require kind", &c.kind, env)?,
4208                 };
4209                 Ok(class.reqs.push((hint, is_extends)))
4210             }
4211             XHPClassAttributeDeclaration(c) => {
4212                 type Ret = Result<Either<ast::XhpAttr, ast::Hint>>;
4213                 let p_attr = |node: S<'a, T, V>, env: &mut Env<'a, TF>| -> Ret {
4214                     let mk_attr_use = |n: S<'a, T, V>, env: &mut Env<'a, TF>| {
4215                         Ok(Either::Right(ast::Hint(
4216                             Self::p_pos(n, env),
4217                             Box::new(ast::Hint_::Happly(Self::pos_name(n, env)?, vec![])),
4218                         )))
4219                     };
4220                     match &node.children {
4221                         XHPClassAttribute(c) => {
4222                             let ast::Id(p, name) = Self::pos_name(&c.name, env)?;
4223                             if let TypeConstant(_) = &c.type_.children {
4224                                 if env.is_typechecker() {
4225                                     Self::raise_parsing_error(
4226                                         &c.type_,
4227                                         env,
4228                                         &syntax_error::xhp_class_attribute_type_constant,
4229                                     )
4230                                 }
4231                             }
4232                             let req = match &c.required.children {
4233                                 XHPRequired(_) => Some(ast::XhpAttrTag::Required),
4234                                 XHPLateinit(_) => Some(ast::XhpAttrTag::LateInit),
4235                                 _ => None,
4236                             };
4237                             let pos = if c.initializer.is_missing() {
4238                                 p.clone()
4239                             } else {
4240                                 Pos::btw(&p, &Self::p_pos(&c.initializer, env))
4241                                     .map_err(Error::Failwith)?
4242                             };
4243                             let (hint, enum_) = match &c.type_.children {
4244                                 XHPEnumType(c1) => {
4245                                     let p = Self::p_pos(&c.type_, env);
4246                                     let vals = Self::could_map(Self::p_expr, &c1.values, env)?;
4247                                     (None, Some((p, vals)))
4248                                 }
4249                                 _ => (Some(Self::p_hint(&c.type_, env)?), None),
4250                             };
4251                             let init_expr =
4252                                 Self::mp_optional(Self::p_simple_initializer, &c.initializer, env)?;
4253                             let xhp_attr = ast::XhpAttr(
4254                                 ast::TypeHint((), hint.clone()),
4255                                 ast::ClassVar {
4256                                     final_: false,
4257                                     xhp_attr: Some(ast::XhpAttrInfo { xai_tag: req }),
4258                                     abstract_: false,
4259                                     visibility: ast::Visibility::Public,
4260                                     type_: ast::TypeHint((), hint),
4261                                     id: ast::Id(p, String::from(":") + &name),
4262                                     expr: init_expr,
4263                                     user_attributes: vec![],
4264                                     doc_comment: None,
4265                                     is_promoted_variadic: false,
4266                                     is_static: false,
4267                                     span: pos,
4268                                 },
4269                                 req,
4270                                 enum_,
4271                             );
4272                             Ok(Either::Left(xhp_attr))
4273                         }
4274                         XHPSimpleClassAttribute(c) => mk_attr_use(&c.type_, env),
4275                         Token(_) => mk_attr_use(node, env),
4276                         _ => Self::missing_syntax("XHP attribute", node, env),
4277                     }
4278                 };
4279                 let attrs = Self::could_map(p_attr, &c.attributes, env)?;
4280                 for attr in attrs.into_iter() {
4281                     match attr {
4282                         Either::Left(attr) => class.xhp_attrs.push(attr),
4283                         Either::Right(xhp_attr_use) => class.xhp_attr_uses.push(xhp_attr_use),
4284                     }
4285                 }
4286                 Ok(())
4287             }
4288             XHPChildrenDeclaration(c) => {
4289                 let p = Self::p_pos(node, env);
4290                 Ok(class
4291                     .xhp_children
4292                     .push((p, Self::p_xhp_child(&c.expression, env)?)))
4293             }
4294             XHPCategoryDeclaration(c) => {
4295                 let p = Self::p_pos(node, env);
4296                 let categories =
4297                     Self::could_map(|n, e| Self::p_pstring_(n, e, Some('%')), &c.categories, env)?;
4298                 if let Some((_, cs)) = &class.xhp_category {
4299                     if let Some(category) = cs.first() {
4300                         Self::raise_hh_error(
4301                             env,
4302                             NastCheck::multiple_xhp_category(category.0.clone()),
4303                         )
4304                     }
4305                 }
4306                 Ok(class.xhp_category = Some((p, categories)))
4307             }
4308             _ => Self::missing_syntax("class element", node, env),
4309         }
4310     }
4312     fn p_class_elt(
4313         class: &mut ast::Class_,
4314         node: S<'a, T, V>,
4315         env: &mut Env<'a, TF>,
4316     ) -> Result<()> {
4317         let r = Self::p_class_elt_(class, node, env);
4318         match r {
4319             // match ocaml behavior, don't throw if missing syntax when fail_open is true
4320             Err(Error::MissingSyntax { .. }) if env.fail_open() => Ok(()),
4321             _ => r,
4322         }
4323     }
4325     fn contains_class_body(c: &ClassishDeclarationChildren<T, V>) -> bool {
4326         matches!(&c.body.children, ClassishBody(_))
4327     }
4329     fn p_where_constraint(
4330         is_class: bool,
4331         parent: S<'a, T, V>,
4332         node: S<'a, T, V>,
4333         env: &mut Env<'a, TF>,
4334     ) -> Result<Vec<ast::WhereConstraintHint>> {
4335         match &node.children {
4336             Missing => Ok(vec![]),
4337             WhereClause(c) => {
4338                 let f = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::WhereConstraintHint> {
4339                     match &n.children {
4340                         WhereConstraint(c) => {
4341                             use ast::ConstraintKind::*;
4342                             let l = Self::p_hint(&c.left_type, e)?;
4343                             let o = &c.operator;
4344                             let o = match Self::token_kind(o) {
4345                                 Some(TK::Equal) => ConstraintEq,
4346                                 Some(TK::As) => ConstraintAs,
4347                                 Some(TK::Super) => ConstraintSuper,
4348                                 _ => Self::missing_syntax("constraint operator", o, e)?,
4349                             };
4350                             Ok(ast::WhereConstraintHint(
4351                                 l,
4352                                 o,
4353                                 Self::p_hint(&c.right_type, e)?,
4354                             ))
4355                         }
4356                         _ => Self::missing_syntax("where constraint", n, e),
4357                     }
4358                 };
4359                 c.constraints
4360                     .syntax_node_to_list_skip_separator()
4361                     .map(|n| f(n, env))
4362                     .collect()
4363             }
4364             _ => {
4365                 if is_class {
4366                     Self::missing_syntax("classish declaration constraints", parent, env)
4367                 } else {
4368                     Self::missing_syntax("function header constraints", parent, env)
4369                 }
4370             }
4371         }
4372     }
4374     fn p_namespace_use_kind(kind: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::NsKind> {
4375         use ast::NsKind::*;
4376         match &kind.children {
4377             Missing => Ok(NSClassAndNamespace),
4378             _ => match Self::token_kind(kind) {
4379                 Some(TK::Namespace) => Ok(NSNamespace),
4380                 Some(TK::Type) => Ok(NSClass),
4381                 Some(TK::Function) => Ok(NSFun),
4382                 Some(TK::Const) => Ok(NSConst),
4383                 _ => Self::missing_syntax("namespace use kind", kind, env),
4384             },
4385         }
4386     }
4388     fn p_namespace_use_clause(
4389         prefix: Option<S<'a, T, V>>,
4390         kind: Result<ast::NsKind>,
4391         node: S<'a, T, V>,
4392         env: &mut Env<'a, TF>,
4393     ) -> Result<(ast::NsKind, ast::Sid, ast::Sid)> {
4394         lazy_static! {
4395             static ref NAMESPACE_USE: regex::Regex = regex::Regex::new("[^\\\\]*$").unwrap();
4396         }
4398         match &node.children {
4399             NamespaceUseClause(NamespaceUseClauseChildren {
4400                 clause_kind,
4401                 alias,
4402                 name,
4403                 ..
4404             }) => {
4405                 let ast::Id(p, n) = match (prefix, Self::pos_name(name, env)?) {
4406                     (None, id) => id,
4407                     (Some(prefix), ast::Id(p, n)) => {
4408                         ast::Id(p, Self::pos_name(prefix, env)?.1 + &n)
4409                     }
4410                 };
4411                 let alias = if alias.is_missing() {
4412                     let x = NAMESPACE_USE.find(&n).unwrap().as_str();
4413                     ast::Id(p.clone(), x.to_string())
4414                 } else {
4415                     Self::pos_name(alias, env)?
4416                 };
4417                 let kind = if clause_kind.is_missing() {
4418                     kind
4419                 } else {
4420                     Self::p_namespace_use_kind(clause_kind, env)
4421                 }?;
4422                 Ok((
4423                     kind,
4424                     ast::Id(
4425                         p,
4426                         if n.len() > 0 && n.chars().nth(0) == Some('\\') {
4427                             n
4428                         } else {
4429                             String::from("\\") + &n
4430                         },
4431                     ),
4432                     alias,
4433                 ))
4434             }
4435             _ => Self::missing_syntax("namespace use clause", node, env),
4436         }
4437     }
4439     fn p_def(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Vec<ast::Def>> {
4440         let doc_comment_opt = Self::extract_docblock(node, env);
4441         match &node.children {
4442             FunctionDeclaration(FunctionDeclarationChildren {
4443                 attribute_spec,
4444                 declaration_header,
4445                 body,
4446             }) => {
4447                 let mut env = Env::clone_and_unset_toplevel_if_toplevel(env);
4448                 let env = env.as_mut();
4449                 let hdr = Self::p_fun_hdr(declaration_header, env)?;
4450                 let is_external = body.is_external();
4451                 let (block, yield_) = if is_external {
4452                     (vec![], false)
4453                 } else {
4454                     Self::mp_yielding(&Self::p_function_body, body, env)?
4455                 };
4456                 let user_attributes = Self::p_user_attributes(attribute_spec, env)?;
4457                 let variadic = Self::determine_variadicity(&hdr.parameters);
4458                 let cap = ast::TypeHint((), hdr.capability);
4459                 let unsafe_cap = ast::TypeHint((), hdr.unsafe_capability);
4460                 let ret = ast::TypeHint((), hdr.return_type);
4461                 Ok(vec![ast::Def::mk_fun(ast::Fun_ {
4462                     span: Self::p_fun_pos(node, env),
4463                     annotation: (),
4464                     mode: env.file_mode(),
4465                     ret,
4466                     name: hdr.name,
4467                     tparams: hdr.type_parameters,
4468                     where_constraints: hdr.constrs,
4469                     params: hdr.parameters,
4470                     cap,
4471                     unsafe_cap,
4472                     body: ast::FuncBody {
4473                         ast: block,
4474                         annotation: (),
4475                     },
4476                     fun_kind: Self::mk_fun_kind(hdr.suspension_kind, yield_),
4477                     variadic,
4478                     user_attributes,
4479                     file_attributes: vec![],
4480                     external: is_external,
4481                     namespace: Self::mk_empty_ns_env(env),
4482                     doc_comment: doc_comment_opt,
4483                     static_: false,
4484                 })])
4485             }
4486             ClassishDeclaration(c) if Self::contains_class_body(c) => {
4487                 let mut env = Env::clone_and_unset_toplevel_if_toplevel(env);
4488                 let env = env.as_mut();
4489                 let mode = env.file_mode();
4490                 let user_attributes = Self::p_user_attributes(&c.attribute, env)?;
4491                 let kinds = Self::p_kinds(&c.modifiers, env)?;
4492                 let final_ = kinds.has(modifier::FINAL);
4493                 let is_xhp = matches!(
4494                     Self::token_kind(&c.name),
4495                     Some(TK::XHPElementName) | Some(TK::XHPClassName)
4496                 );
4497                 let has_xhp_keyword = matches!(Self::token_kind(&c.xhp), Some(TK::XHP));
4498                 let name = Self::pos_name(&c.name, env)?;
4499                 *env.cls_reified_generics() = HashSet::new();
4500                 let tparams = Self::p_tparam_l(true, &c.type_parameters, env)?;
4501                 let extends = Self::could_map(Self::p_hint, &c.extends_list, env)?;
4502                 *env.parent_maybe_reified() = match extends.first().map(|h| h.1.as_ref()) {
4503                     Some(ast::Hint_::Happly(_, hl)) => !hl.is_empty(),
4504                     _ => false,
4505                 };
4506                 let (implements, implements_dynamic) = Self::could_map_filter(
4507                     |node, env| -> Result<Option<ast::Hint>> {
4508                         match Self::p_hint(node, env) {
4509                             Err(e) => Err(e),
4510                             Ok(h) => match &*h.1 {
4511                                 oxidized::aast_defs::Hint_::Happly(oxidized::ast::Id(_, id), _) => {
4512                                     if id == "dynamic" {
4513                                         Ok(None)
4514                                     } else {
4515                                         Ok(Some(h))
4516                                     }
4517                                 }
4518                                 _ => Ok(Some(h)),
4519                             },
4520                         }
4521                     },
4522                     &c.implements_list,
4523                     env,
4524                 )?;
4525                 let where_constraints = Self::p_where_constraint(true, node, &c.where_clause, env)?;
4526                 let namespace = Self::mk_empty_ns_env(env);
4527                 let span = Self::p_pos(node, env);
4528                 let class_kind = match Self::token_kind(&c.keyword) {
4529                     Some(TK::Class) if kinds.has(modifier::ABSTRACT) => ast::ClassKind::Cabstract,
4530                     Some(TK::Class) => ast::ClassKind::Cnormal,
4531                     Some(TK::Interface) => ast::ClassKind::Cinterface,
4532                     Some(TK::Trait) => ast::ClassKind::Ctrait,
4533                     Some(TK::Enum) => ast::ClassKind::Cenum,
4534                     _ => Self::missing_syntax("class kind", &c.keyword, env)?,
4535                 };
4536                 let mut class_ = ast::Class_ {
4537                     span,
4538                     annotation: (),
4539                     mode,
4540                     final_,
4541                     is_xhp,
4542                     has_xhp_keyword,
4543                     kind: class_kind,
4544                     name,
4545                     tparams,
4546                     extends,
4547                     uses: vec![],
4548                     use_as_alias: vec![],
4549                     insteadof_alias: vec![],
4550                     xhp_attr_uses: vec![],
4551                     xhp_category: None,
4552                     reqs: vec![],
4553                     implements,
4554                     implements_dynamic,
4555                     where_constraints,
4556                     consts: vec![],
4557                     typeconsts: vec![],
4558                     vars: vec![],
4559                     methods: vec![],
4560                     // TODO: what is this attbiute? check ast_to_aast
4561                     attributes: vec![],
4562                     xhp_children: vec![],
4563                     xhp_attrs: vec![],
4564                     namespace,
4565                     user_attributes,
4566                     file_attributes: vec![],
4567                     enum_: None,
4568                     doc_comment: doc_comment_opt,
4569                     emit_id: None,
4570                 };
4571                 match &c.body.children {
4572                     ClassishBody(c1) => {
4573                         for elt in c1.elements.syntax_node_to_list_skip_separator() {
4574                             Self::p_class_elt(&mut class_, elt, env)?;
4575                         }
4576                     }
4577                     _ => Self::missing_syntax("classish body", &c.body, env)?,
4578                 }
4579                 Ok(vec![ast::Def::mk_class(class_)])
4580             }
4581             ConstDeclaration(c) => {
4582                 let ty = &c.type_specifier;
4583                 let decls = c.declarators.syntax_node_to_list_skip_separator();
4584                 let mut defs = vec![];
4585                 for decl in decls {
4586                     let def = match &decl.children {
4587                         ConstantDeclarator(c) => {
4588                             let name = &c.name;
4589                             let init = &c.initializer;
4590                             let gconst = ast::Gconst {
4591                                 annotation: (),
4592                                 mode: env.file_mode(),
4593                                 name: Self::pos_name(name, env)?,
4594                                 type_: Self::mp_optional(Self::p_hint, ty, env)?,
4595                                 value: Self::p_simple_initializer(init, env)?,
4596                                 namespace: Self::mk_empty_ns_env(env),
4597                                 span: Self::p_pos(node, env),
4598                                 emit_id: None,
4599                             };
4600                             ast::Def::mk_constant(gconst)
4601                         }
4602                         _ => Self::missing_syntax("constant declaration", decl, env)?,
4603                     };
4604                     defs.push(def);
4605                 }
4606                 Ok(defs)
4607             }
4608             AliasDeclaration(c) => {
4609                 let tparams = Self::p_tparam_l(false, &c.generic_parameter, env)?;
4610                 for tparam in tparams.iter() {
4611                     if tparam.reified != ast::ReifyKind::Erased {
4612                         Self::raise_parsing_error(node, env, &syntax_error::invalid_reified)
4613                     }
4614                 }
4615                 Ok(vec![ast::Def::mk_typedef(ast::Typedef {
4616                     annotation: (),
4617                     name: Self::pos_name(&c.name, env)?,
4618                     tparams,
4619                     constraint: Self::mp_optional(Self::p_tconstraint, &c.constraint, env)?
4620                         .map(|x| x.1),
4621                     user_attributes: itertools::concat(
4622                         c.attribute_spec
4623                             .syntax_node_to_list_skip_separator()
4624                             .map(|attr| Self::p_user_attribute(attr, env))
4625                             .collect::<std::result::Result<Vec<Vec<_>>, _>>()?,
4626                     ),
4627                     namespace: Self::mk_empty_ns_env(env),
4628                     mode: env.file_mode(),
4629                     vis: match Self::token_kind(&c.keyword) {
4630                         Some(TK::Type) => ast::TypedefVisibility::Transparent,
4631                         Some(TK::Newtype) => ast::TypedefVisibility::Opaque,
4632                         _ => Self::missing_syntax("kind", &c.keyword, env)?,
4633                     },
4634                     kind: Self::p_hint(&c.type_, env)?,
4635                     span: Self::p_pos(node, env),
4636                     emit_id: None,
4637                 })])
4638             }
4639             EnumDeclaration(c) => {
4640                 let p_enumerator =
4641                     |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::ClassConst> {
4642                         match &n.children {
4643                             Enumerator(c) => Ok(ast::ClassConst {
4644                                 type_: None,
4645                                 id: Self::pos_name(&c.name, e)?,
4646                                 expr: Some(Self::p_expr(&c.value, e)?),
4647                                 doc_comment: None,
4648                             }),
4649                             _ => Self::missing_syntax("enumerator", n, e),
4650                         }
4651                     };
4652                 Ok(vec![ast::Def::mk_class(ast::Class_ {
4653                     annotation: (),
4654                     mode: env.file_mode(),
4655                     user_attributes: Self::p_user_attributes(&c.attribute_spec, env)?,
4656                     file_attributes: vec![],
4657                     final_: false,
4658                     kind: ast::ClassKind::Cenum,
4659                     is_xhp: false,
4660                     has_xhp_keyword: false,
4661                     name: Self::pos_name(&c.name, env)?,
4662                     tparams: vec![],
4663                     extends: vec![],
4664                     implements: vec![],
4665                     implements_dynamic: false,
4666                     where_constraints: vec![],
4667                     consts: Self::could_map(p_enumerator, &c.enumerators, env)?,
4668                     namespace: Self::mk_empty_ns_env(env),
4669                     span: Self::p_pos(node, env),
4670                     enum_: Some(ast::Enum_ {
4671                         base: Self::p_hint(&c.base, env)?,
4672                         constraint: Self::mp_optional(Self::p_tconstraint_ty, &c.type_, env)?,
4673                         includes: Self::could_map(Self::p_hint, &c.includes_list, env)?,
4674                         enum_class: false,
4675                     }),
4677                     doc_comment: doc_comment_opt,
4678                     uses: vec![],
4679                     use_as_alias: vec![],
4680                     insteadof_alias: vec![],
4681                     xhp_attr_uses: vec![],
4682                     xhp_category: None,
4683                     reqs: vec![],
4684                     vars: vec![],
4685                     typeconsts: vec![],
4686                     methods: vec![],
4687                     attributes: vec![],
4688                     xhp_children: vec![],
4689                     xhp_attrs: vec![],
4690                     emit_id: None,
4691                 })])
4692             }
4693             EnumClassDeclaration(c) => {
4694                 let name = Self::pos_name(&c.name, env)?;
4695                 // Adding __EnumClass
4696                 let mut user_attributes = Self::p_user_attributes(&c.attribute_spec, env)?;
4697                 let enum_class_attribute = ast::UserAttribute {
4698                     name: ast::Id(name.0.clone(), special_attrs::ENUM_CLASS.to_string()),
4699                     params: vec![],
4700                 };
4701                 user_attributes.push(enum_class_attribute);
4702                 // During lowering we store the base type as is. It will be updated during
4703                 // the naming phase
4704                 let base_type = Self::p_hint(&c.base, env)?;
4706                 let name_s = name.1.clone(); // TODO: can I avoid this clone ?
4708                 // Helper to build X -> HH\Elt<enum_name, X>
4709                 let build_elt = |p: Pos, ty: ast::Hint| -> ast::Hint {
4710                     let enum_name = ast::Id(p.clone(), name_s.clone());
4711                     let enum_class = ast::Hint_::mk_happly(enum_name, vec![]);
4712                     let enum_class = ast::Hint::new(p.clone(), enum_class);
4713                     let elt_id = ast::Id(p.clone(), special_classes::ELT.to_string());
4714                     let full_type = ast::Hint_::mk_happly(elt_id, vec![enum_class, ty]);
4715                     ast::Hint::new(p, full_type)
4716                 };
4718                 let extends = Self::could_map(Self::p_hint, &c.extends_list, env)?;
4720                 let mut enum_class = ast::Class_ {
4721                     annotation: (),
4722                     mode: env.file_mode(),
4723                     user_attributes,
4724                     file_attributes: vec![],
4725                     final_: false, // TODO(T77095784): support final EDTs
4726                     kind: ast::ClassKind::Cenum,
4727                     is_xhp: false,
4728                     has_xhp_keyword: false,
4729                     name,
4730                     tparams: vec![],
4731                     extends: extends.clone(),
4732                     implements: vec![],
4733                     implements_dynamic: false,
4734                     where_constraints: vec![],
4735                     consts: vec![],
4736                     namespace: Self::mk_empty_ns_env(env),
4737                     span: Self::p_pos(node, env),
4738                     enum_: Some(ast::Enum_ {
4739                         base: base_type,
4740                         constraint: None,
4741                         includes: extends,
4742                         enum_class: true,
4743                     }),
4744                     doc_comment: doc_comment_opt,
4745                     uses: vec![],
4746                     use_as_alias: vec![],
4747                     insteadof_alias: vec![],
4748                     xhp_attr_uses: vec![],
4749                     xhp_category: None,
4750                     reqs: vec![],
4751                     vars: vec![],
4752                     typeconsts: vec![],
4753                     methods: vec![],
4754                     attributes: vec![],
4755                     xhp_children: vec![],
4756                     xhp_attrs: vec![],
4757                     emit_id: None,
4758                 };
4760                 for n in c.elements.syntax_node_to_list_skip_separator() {
4761                     match &n.children {
4762                         // TODO(T77095784): check pos and span usage
4763                         EnumClassEnumerator(c) => {
4764                             // we turn:
4765                             // - name<type>(args)
4766                             // into
4767                             // - const Elt<enum_name, type> name = new Elt('name', args)
4768                             let span = Self::p_pos(n, env);
4769                             let name = Self::pos_name(&c.name, env)?;
4770                             let pos = &name.0;
4771                             let string_name = ast::Expr_::mk_string(BString::from(name.1.clone()));
4772                             let string_name_expr = ast::Expr::new(pos.clone(), string_name);
4773                             let elt_type = Self::p_hint(&c.type_, env)?;
4774                             let full_type = build_elt(pos.clone(), elt_type);
4775                             let initial_value = Self::p_expr(&c.initial_value, env)?;
4776                             let elt_arguments = vec![string_name_expr, initial_value];
4777                             let elt_id = ast::Id(pos.clone(), special_classes::ELT.to_string());
4778                             let elt_name = E_::mk_id(elt_id.clone());
4779                             let elt_expr = ast::Expr::new(span.clone(), elt_name);
4780                             let cid_ = ast::ClassId_::CIexpr(elt_expr);
4781                             let cid = ast::ClassId(pos.clone(), cid_);
4782                             let new_expr =
4783                                 E_::mk_new(cid, vec![], elt_arguments, None, span.clone());
4784                             let init = ast::Expr::new(span, new_expr);
4785                             let class_const = ast::ClassConst {
4786                                 type_: Some(full_type),
4787                                 id: name,
4788                                 expr: Some(init),
4789                                 doc_comment: None,
4790                             };
4791                             enum_class.consts.push(class_const)
4792                         }
4793                         _ => {
4794                             let pos = Self::p_pos(n, env);
4795                             Self::raise_parsing_error_pos(
4796                                 &pos,
4797                                 env,
4798                                 &syntax_error::invalid_enum_class_enumerator,
4799                             )
4800                         }
4801                     }
4802                 }
4803                 Ok(vec![ast::Def::mk_class(enum_class)])
4804             }
4805             RecordDeclaration(c) => {
4806                 let p_field = |n: S<'a, T, V>, e: &mut Env<'a, TF>| match &n.children {
4807                     RecordField(c) => Ok((
4808                         Self::pos_name(&c.name, e)?,
4809                         Self::p_hint(&c.type_, e)?,
4810                         Self::mp_optional(Self::p_simple_initializer, &c.init, e)?,
4811                     )),
4812                     _ => Self::missing_syntax("record_field", n, e),
4813                 };
4814                 Ok(vec![ast::Def::mk_record_def(ast::RecordDef {
4815                     annotation: (),
4816                     name: Self::pos_name(&c.name, env)?,
4817                     extends: Self::could_map(Self::p_hint, &c.extends_opt, env)?
4818                         .into_iter()
4819                         .next(),
4820                     abstract_: Self::token_kind(&c.modifier) == Some(TK::Abstract),
4821                     user_attributes: Self::p_user_attributes(&c.attribute_spec, env)?,
4822                     fields: Self::could_map(p_field, &c.fields, env)?,
4823                     namespace: Self::mk_empty_ns_env(env),
4824                     span: Self::p_pos(node, env),
4825                     doc_comment: doc_comment_opt,
4826                     emit_id: None,
4827                 })])
4828             }
4829             InclusionDirective(c) if env.file_mode() != file_info::Mode::Mdecl || env.codegen() => {
4830                 let expr = Self::p_expr(&c.expression, env)?;
4831                 Ok(vec![ast::Def::mk_stmt(ast::Stmt::new(
4832                     Self::p_pos(node, env),
4833                     ast::Stmt_::mk_expr(expr),
4834                 ))])
4835             }
4836             NamespaceDeclaration(c) => {
4837                 let name = if let NamespaceDeclarationHeader(h) = &c.header.children {
4838                     &h.name
4839                 } else {
4840                     return Self::missing_syntax("namespace_declaration_header", node, env);
4841                 };
4842                 let defs = match &c.body.children {
4843                     NamespaceBody(c) => {
4844                         let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
4845                         let env1 = env1.as_mut();
4846                         itertools::concat(
4847                             c.declarations
4848                                 .syntax_node_to_list_skip_separator()
4849                                 .map(|n| Self::p_def(n, env1))
4850                                 .collect::<std::result::Result<Vec<Vec<_>>, _>>()?,
4851                         )
4852                     }
4853                     _ => vec![],
4854                 };
4855                 Ok(vec![ast::Def::mk_namespace(
4856                     Self::pos_name(name, env)?,
4857                     defs,
4858                 )])
4859             }
4860             NamespaceGroupUseDeclaration(c) => {
4861                 let uses: std::result::Result<Vec<_>, _> = c
4862                     .clauses
4863                     .syntax_node_to_list_skip_separator()
4864                     .map(|n| {
4865                         Self::p_namespace_use_clause(
4866                             Some(&c.prefix),
4867                             Self::p_namespace_use_kind(&c.kind, env),
4868                             n,
4869                             env,
4870                         )
4871                     })
4872                     .collect();
4873                 Ok(vec![ast::Def::mk_namespace_use(uses?)])
4874             }
4875             NamespaceUseDeclaration(c) => {
4876                 let uses: std::result::Result<Vec<_>, _> = c
4877                     .clauses
4878                     .syntax_node_to_list_skip_separator()
4879                     .map(|n| {
4880                         Self::p_namespace_use_clause(
4881                             None,
4882                             Self::p_namespace_use_kind(&c.kind, env),
4883                             n,
4884                             env,
4885                         )
4886                     })
4887                     .collect();
4888                 Ok(vec![ast::Def::mk_namespace_use(uses?)])
4889             }
4890             FileAttributeSpecification(_) => {
4891                 Ok(vec![ast::Def::mk_file_attributes(ast::FileAttribute {
4892                     user_attributes: Self::p_user_attribute(node, env)?,
4893                     namespace: Self::mk_empty_ns_env(env),
4894                 })])
4895             }
4896             _ if env.file_mode() == file_info::Mode::Mdecl => Ok(vec![]),
4897             _ => Ok(vec![ast::Def::mk_stmt(Self::p_stmt(node, env)?)]),
4898         }
4899     }
4901     fn post_process(env: &mut Env<'a, TF>, program: ast::Program, acc: &mut ast::Program) {
4902         use aast::{Def, Def::*, Stmt_::*};
4903         let mut saw_ns: Option<(ast::Sid, ast::Program)> = None;
4904         for def in program.into_iter() {
4905             if let Namespace(_) = &def {
4906                 if let Some((n, ns_acc)) = saw_ns {
4907                     acc.push(Def::mk_namespace(n, ns_acc));
4908                     saw_ns = None;
4909                 }
4910             }
4912             if let Namespace(ns) = def {
4913                 let (n, defs) = *ns;
4914                 if defs.is_empty() {
4915                     saw_ns = Some((n, vec![]));
4916                 } else {
4917                     let mut acc_ = vec![];
4918                     Self::post_process(env, defs, &mut acc_);
4919                     acc.push(Def::mk_namespace(n, acc_));
4920                 }
4922                 continue;
4923             }
4925             if let Stmt(s) = &def {
4926                 if s.1.is_noop() {
4927                     continue;
4928                 }
4929                 let raise_error = match &s.1 {
4930                     Markup(_) => false,
4931                     Expr(expr)
4932                         if expr.as_ref().is_import()
4933                             && !env.parser_options.po_disallow_toplevel_requires =>
4934                     {
4935                         false
4936                     }
4937                     _ => {
4938                         use file_info::Mode::*;
4939                         let mode = env.file_mode();
4940                         env.keep_errors
4941                             && env.is_typechecker()
4942                             && (mode == Mstrict
4943                                 || (mode == Mpartial
4944                                     && env
4945                                         .parser_options
4946                                         .error_codes_treated_strictly
4947                                         .contains(&1002)))
4948                     }
4949                 };
4950                 if raise_error {
4951                     Self::raise_parsing_error_pos(&s.0, env, &syntax_error::toplevel_statements);
4952                 }
4953             }
4955             if let Some((_, ns_acc)) = &mut saw_ns {
4956                 ns_acc.push(def);
4957             } else {
4958                 acc.push(def);
4959             };
4960         }
4961         if let Some((n, defs)) = saw_ns {
4962             acc.push(Def::mk_namespace(n, defs));
4963         }
4964     }
4966     fn p_program(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Program> {
4967         let nodes = node.syntax_node_to_list_skip_separator();
4968         let mut acc = vec![];
4969         for n in nodes {
4970             match &n.children {
4971                 EndOfFile(_) => break,
4972                 _ => match Self::p_def(n, env) {
4973                     Err(Error::MissingSyntax { .. }) if env.fail_open => {}
4974                     e @ Err(_) => return e,
4975                     Ok(mut def) => acc.append(&mut def),
4976                 },
4977             }
4978         }
4979         let mut program = vec![];
4980         Self::post_process(env, acc, &mut program);
4981         Ok(program)
4982     }
4984     fn p_script(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Program> {
4985         match &node.children {
4986             Script(c) => Self::p_program(&c.declarations, env),
4987             _ => Self::missing_syntax("script", node, env),
4988         }
4989     }
4991     fn lower(
4992         env: &mut Env<'a, TF>,
4993         script: S<'a, T, V>,
4994     ) -> std::result::Result<ast::Program, String> {
4995         Self::p_script(script, env).map_err(|e| match e {
4996             Error::MissingSyntax {
4997                 expecting,
4998                 pos,
4999                 node_name,
5000                 kind,
5001             } => format!(
5002                 "missing case in {:?}.\n - pos: {:?}\n - unexpected: '{:?}'\n - kind: {:?}\n",
5003                 expecting.to_string(),
5004                 pos,
5005                 node_name.to_string(),
5006                 kind,
5007             ),
5008             Error::Failwith(msg) => msg,
5009         })
5010     }
5013 struct PositionedSyntaxLowerer;
5014 impl<'a> Lowerer<'a, PositionedToken<'a>, PositionedValue<'a>, PositionedTokenFactory<'a>>
5015     for PositionedSyntaxLowerer
5019 pub fn lower<'a>(
5020     env: &mut Env<'a, PositionedTokenFactory<'a>>,
5021     script: S<'a, PositionedToken<'a>, PositionedValue<'a>>,
5022 ) -> std::result::Result<ast::Program, String> {
5023     PositionedSyntaxLowerer::lower(env, script)