1 // Copyright (c) 2019, Facebook, Inc.
2 // All rights reserved.
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};
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;
21 aast_visitor::{AstParams, Node, Visitor},
24 doc_comment::DocComment,
25 errors::{Error as HHError, Naming, NastCheck},
27 global_options::GlobalOptions,
28 namespace_env::Env as NamespaceEnv,
32 use parser_core_types::{
33 indexed_source_text::IndexedSourceText,
34 lexable_token::LexablePositionedToken,
35 source_text::SourceText,
36 syntax::{SyntaxValueType, SyntaxValueWithKind},
38 positioned_token::{PositionedToken, TokenFactory as PositionedTokenFactory},
39 positioned_value::PositionedValue,
41 syntax_variant_generated::{SyntaxVariant::*, *},
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;
51 cell::{Ref, RefCell, RefMut},
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 {
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 {
87 RightOfAssignmentInUsingStatement,
92 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
93 pub enum SuspensionKind {
98 #[derive(Copy, Clone, Eq, PartialEq)]
108 suspension_kind: SuspensionKind,
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>,
119 fn make_empty<TF: Clone>(env: &Env<TF>) -> Self {
121 suspension_kind: SuspensionKind::SKSync,
122 name: ast::Id(env.mk_none_pos(), String::from("<ANONYMOUS>")),
124 type_parameters: vec![],
127 unsafe_capability: None,
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> {
162 pub keep_errors: 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,
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.
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,
188 state: Rc<RefCell<State>>,
191 impl<'a, TF: Clone> Env<'a, TF> {
196 show_all_errors: 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>,
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;
214 let mut ns_uses = hh_autoimport::NAMESPACES_MAP.clone();
216 .po_auto_namespace_map
219 &ns_uses.insert(k.into(), v.into());
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(),
228 auto_ns_map: parser_options.po_auto_namespace_map.clone(),
230 disable_xhp_element_mangling: parser_options.po_disable_xhp_element_mangling,
240 disable_lowering_parsing_error,
242 top_level_statements: true,
248 pos_none: Pos::make_none(),
249 empty_ns_env: RcOc::new(empty_ns_env),
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![],
263 exp_recursion_depth: 0,
268 fn file_mode(&self) -> file_info::Mode {
272 fn should_surface_error(&self) -> bool {
273 (!self.quick_mode || self.show_all_errors) && self.keep_errors
276 fn is_typechecker(&self) -> bool {
280 fn codegen(&self) -> bool {
284 fn source_text(&self) -> &SourceText<'a> {
285 self.indexed_source_text.source_text()
288 fn fail_open(&self) -> bool {
292 fn cls_reified_generics(&mut self) -> RefMut<HashSet<String>> {
293 RefMut::map(self.state.borrow_mut(), |s| &mut s.cls_reified_generics)
296 fn in_static_method(&mut self) -> RefMut<bool> {
297 RefMut::map(self.state.borrow_mut(), |s| &mut s.in_static_method)
300 fn parent_maybe_reified(&mut self) -> RefMut<bool> {
301 RefMut::map(self.state.borrow_mut(), |s| &mut s.parent_maybe_reified)
304 pub fn lowpri_errors(&mut self) -> RefMut<Vec<(Pos, String)>> {
305 RefMut::map(self.state.borrow_mut(), |s| &mut s.lowpri_errors)
308 pub fn hh_errors(&mut self) -> RefMut<Vec<HHError>> {
309 RefMut::map(self.state.borrow_mut(), |s| &mut s.hh_errors)
312 pub fn lint_errors(&mut self) -> RefMut<Vec<LintError>> {
313 RefMut::map(self.state.borrow_mut(), |s| &mut s.lint_errors)
316 fn top_docblock(&self) -> Ref<Option<DocComment>> {
317 Ref::map(self.state.borrow(), |s| {
318 s.doc_comments.last().unwrap_or(&None)
322 fn exp_recursion_depth(&self) -> RefMut<usize> {
323 RefMut::map(self.state.borrow_mut(), |s| &mut s.exp_recursion_depth)
326 fn next_local_id(&self) -> isize {
327 let mut id = RefMut::map(self.state.borrow_mut(), |s| &mut s.local_id_counter);
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)
336 fn pop_docblock(&mut self) {
337 RefMut::map(self.state.borrow_mut(), |s| &mut s.doc_comments).pop();
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;
346 fn mk_none_pos(&self) -> Pos {
347 self.pos_none.clone()
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;
362 fn check_stack_limit(&self) {
365 .map(|limit| limit.panic_if_exceeded());
369 impl<'a, TF> AsMut<Env<'a, TF>> for Env<'a, TF> {
370 fn as_mut(&mut self) -> &mut Env<'a, TF> {
381 kind: syntax_kind::SyntaxKind,
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>
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())
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)
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)
409 fn raise_parsing_error_(
410 node_or_pos: Either<S<'a, T, V>, &Pos>,
411 env: &mut Env<'a, TF>,
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(
420 node.position_exclusive(env.indexed_source_text)
421 .unwrap_or_else(|| env.mk_none_pos())
425 env.lowpri_errors().push((pos, String::from(msg)))
429 fn raise_hh_error(env: &mut Env<'a, TF>, err: HHError) {
430 env.hh_errors().push(err);
433 fn raise_lint_error(env: &mut Env<'a, TF>, err: LintError) {
434 env.lint_errors().push(err);
437 fn failwith<N>(msg: impl Into<String>) -> Result<N> {
438 Err(Error::Failwith(msg.into()))
441 fn text(node: S<'a, T, V>, env: &Env<TF>) -> String {
442 String::from(node.text(env.source_text()))
445 fn text_str<'b>(node: S<'a, T, V>, env: &'b Env<TF>) -> &'b str {
446 node.text(env.source_text())
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()
454 Self::raise_parsing_error_pos(
457 &syntax_error::lowering_parsing_error(text, syntax_kind),
462 fn missing_syntax_<N>(
466 env: &mut Env<'a, TF>,
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 {
476 Err(Error::MissingSyntax {
477 expecting: String::from(expecting),
478 pos: Self::p_pos(node, env),
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)
488 fn is_num_octal_lit(s: &str) -> bool {
489 !s.chars().any(|c| c == '8' || c == '9')
492 fn mp_optional<F, R>(p: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Option<R>>
494 F: FnOnce(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
496 match &node.children {
498 _ => p(node, env).map(Some),
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());
510 s += Self::text_str(&li.item, env);
511 s += Self::text_str(&li.separator, env);
513 _ => s += Self::text_str(&i, env),
516 return Ok(ast::Id(p, s));
519 Self::missing_syntax("qualified name", node, env)
522 fn pos_name(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Sid> {
523 Self::pos_name_(node, env, None)
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))
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))
536 fn p_pstring(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Pstring> {
537 Self::p_pstring_(node, env, None)
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)?;
549 fn drop_prefix(s: &str, prefix: char) -> &str {
550 if s.len() > 0 && s.chars().nth(0) == Some(prefix) {
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),
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);
570 let p = Self::p_pos(node, env);
571 Ok(ast::Id(p, String::from(name)))
578 env: &mut Env<'a, TF>,
583 F: Fn(&str) -> std::result::Result<BString, InvalidString>,
585 if let Some('b') = content.chars().nth(0) {
586 content = content.get(1..).unwrap();
589 let len = content.len();
590 let no_quotes_result = extract_unquoted_string(content, 0, len);
591 match no_quotes_result {
593 let result = unescaper(&no_quotes);
597 Self::raise_parsing_error(
600 &format!("Malformed string literal <<{}>>", &no_quotes),
607 Self::raise_parsing_error(
610 &format!("Malformed string literal <<{}>>", &content),
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(""))
626 // TODO: return Cow<[u8]>
627 fn unesc_xhp(s: &[u8]) -> Vec<u8> {
629 static ref WHITESPACE: Regex = Regex::new("[\x20\t\n\r\x0c]+").unwrap();
631 WHITESPACE.replace_all(s, &b" "[..]).into_owned()
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()
641 fn get_quoted_content(s: &[u8]) -> &[u8] {
643 static ref QUOTED: Regex = Regex::new(r#"^[\x20\t\n\r\x0c]*"((?:.|\n)*)""#).unwrap();
647 .map_or(None, |c| c.get(1))
648 .map_or(s, |m| m.as_bytes())
651 fn token_kind(node: S<'a, T, V>) -> Option<TK> {
652 match &node.children {
653 Token(t) => Some(t.kind()),
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> {
667 fn visit_hint(&mut self, c: &mut (), h: &ast::Hint) -> std::result::Result<(), ()> {
669 ast::Hint_::Happly(id, _) => {
672 ast::Hint_::Haccess(_, ids) => {
673 ids.iter().for_each(|id| self.0(&id.1));
681 if *env.in_static_method() {
682 let f = |id: &String| {
683 Self::fail_if_invalid_reified_generic(node, env, id);
685 let mut visitor = Checker(f);
686 visitor.visit_hint(&mut (), hint).unwrap();
690 fn p_closure_parameter(
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)?;
700 _ => Self::missing_syntax("closure parameter", node, env),
704 fn mp_shape_expression_field<F, R>(
707 env: &mut Env<'a, TF>,
708 ) -> Result<(ast::ShapeFieldName, R)>
710 F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
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)?;
718 _ => Self::missing_syntax("shape field", node, env),
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 == "\"\"";
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 {
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(
745 &syntax_error::shape_field_int_like_string,
748 return Ok(SFlitStr((p, str_)));
752 match &node.children {
753 ScopeResolutionExpression(c) => Ok(SFclassConst(
754 Self::pos_name(&c.qualifier, env)?,
755 Self::p_pstring(&c.name, env)?,
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))))
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 {
778 let (name, hint) = Self::mp_shape_expression_field(Self::p_hint, node, env)?;
779 Ok(ast::ShapeFieldInfo {
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)?))
792 fn p_hint_(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Hint_> {
794 let unary = |kw, ty, env: &mut Env<'a, TF>| {
796 Self::pos_name(kw, env)?,
797 Self::could_map(Self::p_hint, ty, env)?,
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)?;
805 Self::map_flatten_(&Self::p_hint, ty, env, vec![key])?,
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(
817 &syntax_error::invalid_typehint_alias(name, canonical),
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);
829 Ok(Happly(ast::Id(pos, name), vec![]))
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(
841 &syntax_error::shape_type_ellipsis_without_trailing_comma,
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(
857 Naming::fd_name_already_bound(f.name.get_pos().clone()),
862 Ok(Hshape(ast::NastShapeInfo {
863 allows_unknown_fields,
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(
874 KeysetTypeSpecifier(c) => Ok(Happly(
875 Self::pos_name(&c.keyword, env)?,
876 Self::could_map(Self::p_hint, &c.type_, env)?,
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)?,
892 let process = |name: ast::Sid, mut args: Vec<ast::Hint>| -> ast::Hint_ {
894 let eq = |s| name.1.eq_ignore_ascii_case(s);
895 if (args[0].1.is_hfun()
898 || eq(rx::RX_SHALLOW)
900 || (args[0].1.is_happly()
902 || eq(rx::MAYBE_MUTABLE)
903 || eq(rx::OWNED_MUTABLE)))
905 return *args.pop().unwrap().1;
910 Ok(process(name, type_args))
912 Ok(Happly(name, type_args))
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
921 .syntax_node_to_list_skip_separator()
922 .partition(|n| match &n.children {
923 VariadicParameter(_) => false,
926 let (type_hints, kinds) = param_list
928 .map(|p| Self::p_closure_parameter(p, env))
929 .collect::<std::result::Result<Vec<_>, _>>()?
932 let variadic_hints = variadic_hints
934 .map(|v| match &v.children {
935 VariadicParameter(c) => {
936 if c.type_.is_missing() {
937 Self::raise_parsing_error(
940 "Cannot use ... without a typehint",
943 Ok(Some(Self::p_hint(&c.type_, env)?))
945 _ => panic!("expect variadic parameter"),
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()
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,
959 param_mutability: vec![],
960 variadic_ty: variadic_hints.into_iter().next().unwrap_or(None),
962 return_ty: Self::p_hint(&c.return_type, env)?,
963 is_mutable_return: true,
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);
972 Ok(*Self::soften_hint(&attrs, hint).1)
975 let child = Self::pos_name(&c.right_type, env)?;
976 match Self::p_hint_(&c.left_type, env)? {
977 Haccess(root, mut cs) => {
979 Ok(Haccess(root, cs))
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]))
986 Self::missing_syntax("type constant base", node, env)
989 _ => Self::missing_syntax("type constant base", node, env),
992 ReifiedTypeArgument(_) => {
993 Self::raise_parsing_error(node, env, &syntax_error::invalid_reified);
994 Self::missing_syntax("refied type", node, env)
996 _ => Self::missing_syntax("type hint", node, env),
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);
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),
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),
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),
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)?,
1035 _ => Ok(ast::Afield::AFvalue(Self::p_expr(node, env)?)),
1039 fn check_intrinsic_type_arg_varity(
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();
1047 2 => Some(ast::CollectionTarg::CollectionTKV(
1048 ast::Targ((), tys.next().unwrap()),
1049 ast::Targ((), tys.next().unwrap()),
1051 1 => Some(ast::CollectionTarg::CollectionTV(ast::Targ(
1053 tys.next().unwrap(),
1057 Self::raise_parsing_error(
1060 &syntax_error::collection_intrinsic_many_typeargs,
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),
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),
1087 fn wrap_unescaper<F>(unescaper: F, s: &str) -> Result<BString>
1089 F: FnOnce(&str) -> std::result::Result<BString, InvalidString>,
1091 unescaper(s).map_err(|e| Error::Failwith(e.msg))
1094 fn fail_if_invalid_class_creation(
1096 env: &mut Env<'a, TF>,
1097 id: impl AsRef<str>,
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()))
1105 Self::raise_parsing_error(node, env, &syntax_error::static_method_reified_obj_creation);
1109 fn fail_if_invalid_reified_generic(
1111 env: &mut Env<'a, TF>,
1112 id: impl AsRef<str>,
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(
1119 &syntax_error::cls_reified_generic_in_static_method,
1124 fn rfind(s: &[u8], mut i: usize, c: u8) -> Result<usize> {
1126 return Self::failwith("index out of range");
1135 Self::failwith("char not found")
1139 nodes: &'a [Syntax<'a, T, V>],
1140 env: &mut Env<'a, TF>,
1141 ) -> Result<(TokenOp, 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'\"'))
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) {
1154 Self::raise_parsing_error(first.unwrap(), env, "Malformed String2 SyntaxList");
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),
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),
1170 return Ok((first_token_op, last_taken_op));
1174 Ok((first_token_op, Noop))
1175 } else if is_heredoc(text) {
1176 let trim_size = text
1178 .position(|c| *c == b'\n')
1179 .ok_or_else(|| Error::Failwith(String::from("newline not found")))?
1181 let first_token_op = match trim_size {
1182 _ if trim_size == text.len() => Skip,
1183 _ => LeftTrim(trim_size),
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();
1189 let n = Self::rfind(text, len - 2, b'\n')?;
1190 let last_token_op = match n {
1192 _ => RightTrim(len - n),
1194 return Ok((first_token_op, last_token_op));
1198 Ok((first_token_op, Noop))
1203 _ => Ok((Noop, Noop)),
1207 fn process_token_op(
1208 env: &mut Env<'a, TF>,
1211 ) -> Result<Option<S<'a, T, V>>> {
1214 LeftTrim(n) => match &node.children {
1216 let token = env.token_factory.trim_left(t, n);
1217 let node = env.arena.alloc(<Syntax<'a, T, V>>::make_token(token));
1220 _ => Self::failwith("Token expected"),
1222 RightTrim(n) => match &node.children {
1224 let token = env.token_factory.trim_right(t, n);
1225 let node = env.arena.alloc(<Syntax<'a, T, V>>::make_token(token));
1228 _ => Self::failwith("Token expected"),
1234 fn p_string2(nodes: &'a [Syntax<'a, T, V>], env: &mut Env<'a, TF>) -> Result<Vec<ast::Expr>> {
1236 let (head_op, tail_op) = Self::prep_string2(nodes, env)?;
1237 let mut result = Vec::with_capacity(nodes.len());
1239 let last = nodes.len() - 1;
1243 _ if i == last => tail_op,
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(
1260 &syntax_error::outside_dollar_str_interp,
1263 result.push(Self::p_expr_with_loc(
1264 ExprLocation::InDoubleQuotedString,
1273 result.push(Self::p_expr_with_loc(
1274 ExprLocation::InDoubleQuotedString,
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)
1287 Self::could_map(p_expr, node, env)
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)
1295 location: ExprLocation,
1297 env: &mut Env<'a, TF>,
1298 ) -> Result<ast::Expr> {
1299 Self::p_expr_impl(location, node, env, None)
1303 location: ExprLocation,
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)
1317 ParenthesizedExpression(c) => {
1318 Self::p_expr_impl(location, &c.expression, env, parent_pos)
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_))
1329 location: ExprLocation,
1330 parent: S<'a, T, V>,
1332 env: &mut Env<'a, TF>,
1333 ) -> Result<ast::Expr_> {
1334 match &expr.children {
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(
1341 LintError::lowercase_constant(Self::p_pos(expr, e), s),
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)))
1349 (_, Some(TK::OctalLiteral))
1350 if env.is_typechecker() && !Self::is_num_octal_lit(s) =>
1352 Self::raise_parsing_error(
1355 &syntax_error::invalid_octal_integer,
1357 Self::missing_syntax("octal", expr, env)
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)))
1367 (_, Some(TK::DoubleQuotedStringLiteral)) => {
1368 Ok(E_::String(Self::mk_str(expr, env, unescape_double, s)))
1370 (_, Some(TK::HeredocStringLiteral)) => {
1371 Ok(E_::String(Self::mk_str(expr, env, unescape_heredoc, s)))
1373 (_, Some(TK::NowdocStringLiteral)) => {
1374 Ok(E_::String(Self::mk_str(expr, env, unescape_nowdoc, s)))
1376 (_, Some(TK::NullLiteral)) => {
1377 check_lint_err(env, s, literal::NULL);
1380 (_, Some(TK::BooleanLiteral)) => {
1381 if s.eq_ignore_ascii_case(literal::FALSE) {
1382 check_lint_err(env, s, literal::FALSE);
1384 } else if s.eq_ignore_ascii_case(literal::TRUE) {
1385 check_lint_err(env, s, literal::TRUE);
1388 Self::missing_syntax(&format!("boolean (not: {})", s), expr, env)
1391 _ => Self::missing_syntax("literal", expr, env),
1394 SyntaxList(ts) => Ok(E_::String2(Self::p_string2(ts, env)?)),
1395 _ => Self::missing_syntax("literal expressoin", expr, env),
1399 fn p_expr_with_loc_(
1400 location: ExprLocation,
1402 env: &mut Env<'a, TF>,
1403 ) -> Result<ast::Expr_> {
1404 Self::p_expr_impl_(location, node, env, None)
1408 location: ExprLocation,
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()))
1416 *env.exp_recursion_depth() += 1;
1417 let r = Self::p_expr_impl__(location, node, env, parent_pos);
1418 *env.exp_recursion_depth() -= 1;
1424 location: ExprLocation,
1426 env: &mut Env<'a, TF>,
1427 parent_pos: Option<Pos>,
1428 ) -> Result<ast::Expr_> {
1429 env.check_stack_limit();
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();
1443 let vararg = Self::p_expr(&c.expression, e)?;
1444 return Ok((args, Some(vararg)));
1448 Ok((Self::could_map(Self::p_expr, arg_list_node, e)?, None))
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))
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)?,
1464 Self::could_map(Self::p_afield, v, e)?,
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)),
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;
1479 E_::mk_obj_get(a.clone(), b.clone(), c.clone(), true),
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))
1488 let (args, varargs) = split_args_vararg(args, e)?;
1489 Ok(E_::mk_call(recv, vec![], args, varargs))
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);
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))
1505 let pos = match parent_pos {
1506 None => Self::p_pos(node, env),
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)?,
1519 let ast::Id(p, n) = Self::pos_name(&c.signature, env)?;
1521 vec![ast::FunParam {
1522 annotation: p.clone(),
1523 type_hint: ast::TypeHint((), None),
1529 user_attributes: vec![],
1536 _ => Self::missing_syntax("lambda signature", &c.signature, env)?,
1538 let (body, yield_) = if !c.body.is_compound_statement() {
1539 Self::mp_yielding(Self::p_function_body, &c.body, env)?
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())?
1544 let external = c.body.is_external();
1545 let fun = ast::Fun_ {
1548 mode: env.file_mode(),
1549 ret: ast::TypeHint((), ret),
1550 name: ast::Id(pos, String::from(";anonymous")),
1552 where_constraints: vec![],
1553 body: ast::FuncBody {
1557 fun_kind: Self::mk_fun_kind(suspension_kind, yield_),
1558 variadic: Self::determine_variadicity(¶ms),
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![],
1565 namespace: Self::mk_empty_ns_env(env),
1569 Ok(E_::mk_lfun(fun, vec![]))
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))
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)
1579 KeysetIntrinsicExpression(c) => {
1580 p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env)
1582 VectorIntrinsicExpression(c) => {
1583 p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env)
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)
1593 _ => (Self::pos_name(&c.name, env)?, None),
1595 Ok(E_::mk_collection(
1598 Self::could_map(Self::p_afield, &c.initializers, env)?,
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),
1607 _ => Self::missing_syntax("VarrayIntrinsicExpression type args", node, env)?,
1611 Self::could_map(Self::p_expr, &c.members, env)?,
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);
1618 Some(ast::CollectionTarg::CollectionTKV(tk, tv)) => Ok(E_::mk_darray(
1620 Self::could_map(Self::p_member, &c.members, env)?,
1622 None => Ok(E_::mk_darray(
1624 Self::could_map(Self::p_member, &c.members, env)?,
1626 _ => Self::missing_syntax("DarrayIntrinsicExpression type args", node, env),
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> {
1634 Missing => Ok(E::new(e.mk_none_pos(), E_::Omitted)),
1635 _ => Self::p_expr(n, e),
1638 Ok(E_::List(Self::could_map(
1639 &p_binder_or_ignore,
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) {
1667 match get_hhas_adata() {
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))?;
1673 Self::p_expr(recv, env)?,
1675 vec![E::new(literal_expression_pos, E_::String(s.into()))],
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)?,
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)),
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;
1705 E_::mk_obj_get(a.clone(), b.clone(), c.clone(), true),
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))
1714 let (args, varargs) = split_args_vararg(args, env)?;
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()));
1722 Ok(E_::mk_call(recv, targs, args, varargs))
1726 FunctionPointerExpression(c) => {
1727 let targs = match &c.type_args.children {
1728 TypeArguments(c) => Self::could_map(Self::p_targ, &c.types, env)?,
1732 let recv = Self::p_expr(&c.receiver, env)?;
1735 aast::Expr_::Id(id) => Ok(E_::mk_function_pointer(
1736 aast::FunctionPtrId::FPId(*(id.to_owned())),
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()),
1746 Self::raise_parsing_error(
1749 &syntax_error::function_pointer_bad_recv,
1751 Self::missing_syntax("function or static method", node, env)
1755 Self::raise_parsing_error(
1758 &syntax_error::function_pointer_bad_recv,
1760 Self::missing_syntax("function or static method", node, env)
1764 QualifiedName(_) => match location {
1765 ExprLocation::InDoubleQuotedString => {
1766 let ast::Id(_, n) = Self::pos_qualified_name(node, env)?;
1767 Ok(E_::String(n.into()))
1769 _ => Ok(E_::mk_id(Self::pos_qualified_name(node, env)?)),
1771 VariableExpression(c) => Ok(E_::mk_lvar(Self::lid_from_pos_name(
1776 PipeVariableExpression(_) => Ok(E_::mk_lvar(mk_lid(
1778 special_idents::DOLLAR_DOLLAR.into(),
1780 InclusionExpression(c) => Ok(E_::mk_import(
1781 Self::p_import_flavor(&c.require, env)?,
1782 Self::p_expr(&c.filename, env)?,
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)?,
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
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);
1809 let expr = Self::p_expr(operand, env)?;
1810 mk_unop(Usilence, expr)
1813 Self::p_expr_impl(ExprLocation::TopLevel, operand, env, Some(pos))?;
1817 let expr = Self::p_expr(operand, env)?;
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(
1833 E_::mk_id(ast::Id(pos, special_functions::ECHO.into())),
1839 Some(TK::Dollar) => {
1840 Self::raise_parsing_error(
1843 &syntax_error::invalid_variable_name,
1847 _ => Self::missing_syntax("unary operator", node, env),
1851 BinaryExpression(c) => {
1852 use ExprLocation::*;
1853 let rlocation = if Self::token_kind(&c.operator) == Some(TK::Equal) {
1855 AsStatement => RightOfAssignment,
1856 UsingStatement => RightOfAssignmentInUsingStatement,
1862 let bop_ast_node = Self::p_bop(
1865 Self::p_expr(&c.left_operand, env)?,
1866 Self::p_expr_with_loc(rlocation, &c.right_operand, env)?,
1869 if let Some((ast::Bop::Eq(_), lhs, _)) = bop_ast_node.as_binop() {
1870 Self::check_lvalue(lhs, env);
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))?,
1883 (InDoubleQuotedString, _) => Ok(E_::String(Self::wrap_unescaper(
1885 Self::text_str(node, env),
1890 | (UsingStatement, _)
1891 | (RightOfAssignment, _)
1892 | (RightOfAssignmentInUsingStatement, _)
1893 | (RightOfReturn, _) => Ok(E_::mk_id(Self::pos_name(node, env)?)),
1896 YieldExpression(c) => {
1897 use ExprLocation::*;
1898 env.saw_yield = true;
1899 if location != AsStatement
1900 && location != RightOfAssignment
1901 && location != RightOfAssignmentInUsingStatement
1903 Self::raise_parsing_error(node, env, &syntax_error::invalid_yield);
1905 if Self::text_str(&c.operand, env) == "break" {
1907 } else if c.operand.is_missing() {
1908 Ok(E_::mk_yield(ast::Afield::AFvalue(E::new(pos, E_::Null))))
1910 Ok(E_::mk_yield(Self::p_afield(&c.operand, env)?))
1913 DefineExpression(c) => {
1914 let name = Self::pos_name(&c.keyword, env)?;
1919 .syntax_node_to_list_skip_separator()
1920 .map(|x| Self::p_expr(x, env))
1921 .collect::<std::result::Result<Vec<_>, _>>()?,
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);
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)),
1940 let E(p, expr_) = Self::p_expr(&c.name, env)?;
1942 E_::String(id) => Ok(E_::mk_class_const(
1943 ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
1946 String::from_utf8(id.into())
1947 .map_err(|e| Error::Failwith(e.to_string()))?,
1951 let ast::Id(p, n) = *id;
1952 Ok(E_::mk_class_const(
1953 ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
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)),
1965 _ => Ok(E_::mk_class_get(
1966 ast::ClassId(pos, ast::ClassId_::CIexpr(qual)),
1967 ast::ClassGetExpr::CGexpr(E(p, expr_)),
1974 CastExpression(c) => Ok(E_::mk_cast(
1975 Self::p_hint(&c.type_, env)?,
1976 Self::p_expr(&c.operand, env)?,
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 {
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))
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)?,
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)?,
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)
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",
2023 (mk_id_expr(name), hints)
2025 SimpleTypeSpecifier(_) => {
2026 let name = Self::pos_name(&c.type_, env)?;
2027 (mk_id_expr(name), vec![])
2029 _ => (Self::p_expr(&c.type_, env)?, vec![]),
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);
2036 ast::ClassId(pos.clone(), ast::ClassId_::CIexpr(e)),
2043 GenericTypeSpecifier(c) => {
2044 if !c.argument_list.is_missing() {
2045 Self::raise_parsing_error(
2048 &syntax_error::targs_not_allowed,
2051 Ok(E_::mk_id(Self::pos_name(&c.class_type, env)?))
2053 RecordCreationExpression(c) => {
2054 let id = Self::pos_name(&c.type_, env)?;
2057 Self::could_map(Self::p_member, &c.members, env)?,
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);
2067 Ok(E_::mk_prefixed_string(
2069 Self::p_expr(&c.str, env)?,
2072 IsExpression(c) => Ok(E_::mk_is(
2073 Self::p_expr(&c.left_operand, env)?,
2074 Self::p_hint(&c.right_operand, env)?,
2076 AsExpression(c) => Ok(E_::mk_as(
2077 Self::p_expr(&c.left_operand, env)?,
2078 Self::p_hint(&c.right_operand, env)?,
2081 NullableAsExpression(c) => Ok(E_::mk_as(
2082 Self::p_expr(&c.left_operand, env)?,
2083 Self::p_hint(&c.right_operand, env)?,
2086 AnonymousFunction(c) => {
2087 if env.parser_options.po_disable_static_closures
2088 && Self::token_kind(&c.static_keyword) == Some(TK::Static)
2090 Self::raise_parsing_error(
2093 &syntax_error::static_closures_are_disabled,
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),
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),
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())?
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),
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")),
2122 where_constraints: vec![],
2123 body: ast::FuncBody {
2127 fun_kind: Self::mk_fun_kind(suspension_kind, yield_),
2128 variadic: Self::determine_variadicity(¶ms),
2130 cap: ast::TypeHint((), None), // TODO(T70095684)
2131 unsafe_cap: ast::TypeHint((), None), // TODO(T70095684)
2133 file_attributes: vec![],
2135 namespace: Self::mk_empty_ns_env(env),
2137 static_: !c.static_keyword.is_missing(),
2139 let uses = p_use(&c.use_, env).unwrap_or_else(|_| vec![]);
2140 Ok(E_::mk_efun(fun, uses))
2142 AwaitableCreationExpression(c) => {
2143 let suspension_kind = Self::mk_suspension_kind(&c.async_);
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_ {
2152 mode: env.file_mode(),
2153 ret: ast::TypeHint((), None),
2154 name: ast::Id(name_pos, String::from(";anonymous")),
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)]
2166 fun_kind: Self::mk_fun_kind(suspension_kind, yld),
2167 variadic: Self::determine_variadicity(&[]),
2169 cap: ast::TypeHint((), None), // TODO(T70095684)
2170 unsafe_cap: ast::TypeHint((), None), // TODO(T70095684)
2172 file_attributes: vec![],
2174 namespace: Self::mk_empty_ns_env(env),
2179 E::new(pos, E_::mk_lfun(body, vec![])),
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)?
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)
2197 ast::Id(name.0, String::from(":") + &name.1)
2201 // TODO: update pos_name to support prefix
2205 Self::failwith("expect xhp open")
2208 EnumAtomExpression(c) => Ok(E_::EnumAtom(Self::pos_name(&c.expression, env)?.1)),
2209 _ => Self::missing_syntax_(Some(E_::Null), "expression", node, env),
2213 fn check_lvalue(ast::Expr(p, expr_): &ast::Expr, env: &mut Env<'a, TF>) {
2215 let mut raise = |s| Self::raise_parsing_error_pos(p, env, s);
2219 raise("Invalid lvalue")
2222 (_, ast::Expr(_, Id(_)), ast::OgNullFlavor::OGNullsafe, _) => {
2223 raise("?-> syntax is not supported for lvalues")
2225 (_, ast::Expr(_, Id(sid)), _, _) if sid.1.as_bytes()[0] == b':' => {
2226 raise("->: syntax is not supported for lvalues")
2233 if let ClassConst(_) = (ag.0).1 {
2234 raise("Array-like class consts are not valid lvalues");
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?")
2241 _ => raise("Invalid lvalue"),
2245 Self::check_lvalue(i, env);
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"),
2257 fn p_xhp_embedded<F>(escaper: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<ast::Expr>
2259 F: FnOnce(&[u8]) -> Vec<u8>,
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()),
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 */
2274 html_entities::decode(&Self::unesc_xhp(node.full_text(env.source_text())));
2275 Ok(ast::Expr::new(p, E_::make_string(text)))
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)))
2282 Self::p_expr(node, env)
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
2296 ast::Expr::new(env.mk_none_pos(), E_::Null)
2298 Self::p_xhp_embedded(Self::unesc_xhp_attr, attr_expr, env)?
2300 Ok(ast::XhpAttribute::XhpSimple(name, expr))
2302 XHPSpreadAttribute(c) => {
2303 let expr = Self::p_xhp_embedded(Self::unesc_xhp, &c.expression, env)?;
2304 Ok(ast::XhpAttribute::XhpSpread(expr))
2306 _ => Self::missing_syntax("XHP attribute", node, env),
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)
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)) => {
2320 .concatenate(s.get_token().unwrap(), e.get_token().unwrap());
2321 let node = env.arena.alloc(<Syntax<T, V>>::make_token(token));
2332 Token(t) if t.kind() == TK::XHPComment => {
2333 if state.0.is_some() {
2334 combine(&mut state)?;
2338 if state.0.is_none() {
2345 combine(&mut state)?;
2350 combine(&mut state)?;
2359 env: &mut Env<'a, TF>,
2360 ) -> Result<ast::Expr_> {
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_`.
2408 Some(TK::BarGreaterThan) => {
2410 ast::Lid::from_counter(pos, env.next_local_id(), special_idents::DOLLAR_DOLLAR);
2411 Ok(E_::mk_pipe(lid, lhs, rhs))
2413 Some(TK::QuestionColon) => Ok(E_::mk_eif(lhs, None, rhs)),
2414 _ => Self::missing_syntax("binary operator", node, env),
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)
2423 Ok((loc, Self::could_map(p_expr, n, e)?))
2428 mut nodes: Iter<S<'a, T, V>>,
2429 env: &mut Env<'a, TF>,
2430 ) -> Result<Vec<ast::Stmt>> {
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>| {
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)?,
2448 let using = Self::lift_awaits_in_statement_(f, Either::Right(pos), env)?;
2453 r.push(Self::p_stmt(n, env)?);
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)?
2465 .filter(|stmt| !stmt.1.is_noop())
2467 let body = if blk.len() == 0 {
2468 vec![Self::mk_noop(env)]
2472 Ok(ast::Stmt::new(pos, ast::Stmt_::mk_block(body)))
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)
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),
2492 fn with_new_nonconcurrent_scope<F, R>(f: F, env: &mut Env<'a, TF>) -> R
2494 F: FnOnce(&mut Env<'a, TF>) -> R,
2496 let saved_lifted_awaits = env.lifted_awaits.take();
2497 let result = f(env);
2498 env.lifted_awaits = saved_lifted_awaits;
2502 fn with_new_concurrent_scope<F, R>(f: F, env: &mut Env<'a, TF>) -> Result<(LiftedAwaitExprs, R)>
2504 F: FnOnce(&mut Env<'a, TF>) -> Result<R>,
2506 let saved_lifted_awaits = env.lifted_awaits.replace(LiftedAwaits {
2508 lift_kind: LiftedAwaitKind::LiftedFromConcurrent,
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")?,
2517 Ok((awaits, result))
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");
2528 .sort_unstable_by(|a1, a2| Pos::cmp(&(a1.1).0, &(a2.1).0));
2532 fn clear_statement_scope<F, R>(f: F, env: &mut Env<'a, TF>) -> R
2534 F: FnOnce(&mut Env<'a, TF>) -> R,
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;
2548 fn lift_awaits_in_statement<F>(
2551 env: &mut Env<'a, TF>,
2552 ) -> Result<ast::Stmt>
2554 F: FnOnce(&mut Env<'a, TF>) -> Result<ast::Stmt>,
2556 Self::lift_awaits_in_statement_(f, Either::Left(node), env)
2559 fn lift_awaits_in_statement_<F>(
2561 pos: Either<S<'a, T, V>, &Pos>,
2562 env: &mut Env<'a, TF>,
2563 ) -> Result<ast::Stmt>
2565 F: FnOnce(&mut Env<'a, TF>) -> Result<ast::Stmt>,
2567 use LiftedAwaitKind::*;
2568 let (lifted_awaits, result) = match env.lifted_awaits {
2569 Some(LiftedAwaits { lift_kind, .. }) if lift_kind == LiftedFromConcurrent => {
2573 let saved = env.lifted_awaits.replace(LiftedAwaits {
2575 lift_kind: LiftedFromStatement,
2577 let result = f(env);
2578 let lifted_awaits = mem::replace(&mut env.lifted_awaits, saved);
2579 let result = result?;
2580 (lifted_awaits, result)
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(),
2590 return Ok(ast::Stmt::new(
2592 ast::Stmt_::mk_awaitall(awaits, vec![result]),
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))
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))
2621 .map(|aw| aw.awaits.push((None, expr)));
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);
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> {
2650 Ok(ast::Case::Case(Self::p_expr(&c.expression, e)?, vec![]))
2652 DefaultLabel(_) => Ok(ast::Case::Default(Self::p_pos(n, e), vec![])),
2653 _ => Self::missing_syntax("switch label", n, e),
2656 let p_section = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<Vec<ast::Case>> {
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));
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"),
2671 _ => Self::missing_syntax("switch section", n, e),
2674 let f = |env: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2678 Self::p_expr(&c.expression, env)?,
2679 itertools::concat(Self::could_map(p_section, &c.sections, env)?),
2683 Self::lift_awaits_in_statement(f, node, env)
2687 |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<(ast::Expr, ast::Block)> {
2689 ElseifClause(c) => Ok((
2690 Self::p_expr(&c.condition, e)?,
2691 Self::p_block(true, &c.statement, e)?,
2693 _ => Self::missing_syntax("elseif clause", n, e),
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)?,
2704 let else_ifs = Self::could_map(p_else_if, &c.elseif_clauses, env)?;
2705 let else_if = else_ifs
2708 .fold(else_, |child, (cond, stmts)| {
2709 vec![new(pos.clone(), S_::mk_if(cond, stmts, child))]
2711 Ok(new(pos, S_::mk_if(condition, statement, else_if)))
2713 Self::lift_awaits_in_statement(f, node, env)
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))
2723 S_::mk_expr(Self::p_expr_with_loc(ExprLocation::AsStatement, expr, e)?),
2727 if Self::is_simple_assignment_await_expression(expr)
2728 || Self::is_simple_await_expression(expr)
2732 Self::lift_awaits_in_statement(f, node, env)
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)?)))
2744 DoStatement(c) => Ok(new(
2747 Self::p_block(false /* remove noop */, &c.body, env)?,
2748 Self::p_expr(&c.condition, env)?,
2751 WhileStatement(c) => Ok(new(
2754 Self::p_expr(&c.condition, env)?,
2755 Self::p_block(true, &c.body, env)?,
2758 UsingStatementBlockScoped(c) => {
2759 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
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)?,
2770 Self::lift_awaits_in_statement(f, node, env)
2772 UsingStatementFunctionScoped(c) => {
2773 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
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)],
2784 Self::lift_awaits_in_statement(f, node, env)
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)))
2794 Self::lift_awaits_in_statement(f, node, env)
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)),
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),
2810 let blk = Self::p_block(true, &c.body, e)?;
2811 Ok(new(pos, S_::mk_foreach(col, akv, blk)))
2813 Self::lift_awaits_in_statement(f, node, env)
2815 TryStatement(c) => Ok(new(
2818 Self::p_block(false, &c.compound_statement, env)?,
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)?,
2826 _ => Self::missing_syntax("catch clause", n, e),
2831 match &c.finally_clause.children {
2832 FinallyClause(c) => Self::p_block(false, &c.body, env)?,
2837 ReturnStatement(c) => {
2838 let f = |e: &mut Env<'a, TF>| -> Result<ast::Stmt> {
2839 let expr = match &c.expression.children {
2841 _ => Some(Self::p_expr_with_loc(
2842 ExprLocation::RightOfReturn,
2847 Ok(ast::Stmt::new(pos, ast::Stmt_::mk_return(expr)))
2849 if Self::is_simple_await_expression(&c.expression) {
2852 Self::lift_awaits_in_statement(f, node, env)
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))
2862 _ => Self::missing_syntax("id", &c.keyword, e)?,
2864 let args = Self::could_map(Self::p_expr, &c.expressions, e)?;
2867 S_::mk_expr(ast::Expr::new(pos, E_::mk_call(echo, vec![], args, None))),
2870 Self::lift_awaits_in_statement(f, node, env)
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 {
2877 .for_each(|arg| Self::check_mutate_class_const(arg, node, e))
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))
2884 _ => Self::missing_syntax("id", &c.keyword, e)?,
2888 S_::mk_expr(ast::Expr::new(pos, E_::mk_call(unset, vec![], args, None))),
2891 Self::lift_awaits_in_statement(f, node, env)
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),
2901 let stmt = match stmt {
2902 S_::Block(stmts) => {
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
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() {
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() {
2935 body_stmts.push(new_n);
2937 let assign_stmt = new(
2941 E_::mk_binop(Eq(op), e1, tmp_n),
2944 assign_stmts.push(assign_stmt);
2950 Self::failwith("Expect assignment stmt")?;
2952 Self::raise_parsing_error_pos(
2955 &syntax_error::statement_without_await_in_concurrent_block,
2960 body_stmts.append(&mut assign_stmts);
2961 new(stmt_pos, S_::mk_block(body_stmts))
2963 _ => Self::failwith("Unexpected concurrent stmt structure")?,
2965 Ok(new(keyword_pos, S_::mk_awaitall(lifted_awaits, vec![stmt])))
2967 MarkupSection(_) => Self::p_markup(node, env),
2968 _ => Self::missing_syntax_(
2969 Some(new(env.mk_none_pos(), S_::Noop)),
2976 fn check_mutate_class_const(e: &ast::Expr, node: S<'a, T, V>, env: &mut Env<'a, TF>) {
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)
2986 fn is_hashbang(node: S<'a, T, V>, env: &Env<TF>) -> bool {
2987 let text = Self::text_str(node, env);
2989 static ref RE: regex::Regex = regex::Regex::new("^#!.*\n").unwrap();
2991 text.lines().nth(1).is_none() && // only one line
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())
3004 let ext = f.path().extension().unwrap(); // has_extension ensures this is a Some
3005 Self::raise_parsing_error(
3008 &syntax_error::error1060(&ext.to_str().unwrap()),
3010 } else if markup_hashbang.width() > 0 && !Self::is_hashbang(markup_hashbang, env) {
3011 Self::raise_parsing_error(node, env, &syntax_error::error1001);
3013 let stmt_ = ast::Stmt_::mk_markup((pos.clone(), Self::text(markup_hashbang, env)));
3014 Ok(ast::Stmt::new(pos, stmt_))
3016 _ => Self::failwith("invalid node"),
3020 fn p_modifiers<F: Fn(R, modifier::Kind) -> R, R>(
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);
3032 init = on_kind(init, kind);
3034 _ => Self::missing_syntax("kind", n, env)?,
3037 Ok((kind_set, init))
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)
3044 fn could_map<R, F>(f: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Vec<R>>
3046 F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
3048 Self::map_flatten_(f, node, env, vec![])
3051 fn map_flatten_<R, F>(
3054 env: &mut Env<'a, TF>,
3058 F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
3060 let op = |mut v: Vec<R>, a| {
3064 Self::map_fold(&f, &op, node, env, acc)
3067 fn could_map_filter<R, F>(
3070 env: &mut Env<'a, TF>,
3071 ) -> Result<(Vec<R>, bool)>
3073 F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<Option<R>>,
3075 Self::map_flatten_filter_(f, node, env, (vec![], false))
3079 fn map_flatten_filter_<R, F>(
3082 env: &mut Env<'a, TF>,
3083 acc: (Vec<R>, bool),
3084 ) -> Result<(Vec<R>, bool)>
3086 F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<Option<R>>,
3088 let op = |mut v: (Vec<R>, bool), a| -> (Vec<R>, bool) {
3090 Option::None => (v.0, true),
3091 Option::Some(a) => {
3097 Self::map_fold(&f, &op, node, env, acc)
3100 fn map_fold<A, R, F, O>(
3104 env: &mut Env<'a, TF>,
3108 F: Fn(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
3111 for n in node.syntax_node_to_list_skip_separator() {
3112 acc = op(acc, f(n, env)?);
3117 fn p_visibility(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<Option<ast::Visibility>> {
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)
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))
3131 fn p_visibility_last_win(
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)
3139 fn p_visibility_last_win_or(
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))
3147 fn has_soft(attrs: &[ast::UserAttribute]) -> bool {
3148 attrs.iter().any(|attr| attr.name.1 == special_attrs::SOFT)
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))
3159 fn p_fun_param_default_value(
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),
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),
3176 fn param_template(node: S<'a, T, V>, env: &Env<TF>) -> ast::FunParam {
3177 let pos = Self::p_pos(node, env);
3179 annotation: pos.clone(),
3180 type_hint: ast::TypeHint((), None),
3183 name: Self::text(node, env),
3186 user_attributes: vec![],
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 {
3201 let (is_variadic, name) = match &name.children {
3202 DecoratedExpression(DecoratedExpressionChildren {
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);
3212 decorator == "..." || nested_decorator == "...",
3216 _ => (decorator == "...", expression),
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(
3228 &syntax_error::no_attributes_on_variadic_parameter,
3231 let pos = Self::p_pos(name, env);
3233 annotation: pos.clone(),
3234 type_hint: ast::TypeHint((), hint),
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.
3245 visibility: Self::p_visibility(visibility, env)?,
3248 VariadicParameter(_) => {
3249 let mut param = Self::param_template(node, env);
3250 param.is_variadic = true;
3253 Token(_) if Self::text_str(node, env) == "..." => {
3254 let mut param = Self::param_template(node, env);
3255 param.is_variadic = true;
3258 _ => Self::missing_syntax("function parameter", node, env),
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),
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)?,
3281 Self::p_hint(&c.type_, env)?,
3283 _ => Self::missing_syntax("type constraint", node, env),
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 {
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);
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,
3308 if is_reified && variance != ast::Variance::Invariant {
3309 Self::raise_parsing_error(
3312 &syntax_error::non_invariant_reified_generic,
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,
3320 let parameters = Self::p_tparam_l(is_class, param_params, env)?;
3323 name: Self::pos_name(name, env)?,
3325 constraints: Self::could_map(Self::p_tconstraint, constraints, env)?,
3330 _ => Self::missing_syntax("type parameter", node, env),
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)
3344 _ => Self::missing_syntax("type parameter", node, env),
3350 env: &mut Env<'a, TF>,
3351 ) -> Result<(Option<ast::Hint>, Option<ast::Hint>)> {
3352 match &node.children {
3353 Missing => Ok((None, None)),
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
3359 /* Could make [] into Hmixed, but it just turns into empty intersection anyway */
3360 ast::Hint_::Hintersection(hints)
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)))
3367 _ => Self::missing_syntax("capability", node, env),
3371 fn p_capability_provisional(
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))
3382 _ => Self::missing_syntax("capability_provisional", node, env),
3386 /* Just temporary to handle both syntaxes. This will be removed when p_capability_provisional is removed */
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,
3396 "Cannot use both the [ and @{ syntax for coeffects",
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)
3403 Self::p_capability_provisional(capability_provisional, env)
3407 fn p_fun_hdr(node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<FunHdr> {
3408 match &node.children {
3409 FunctionDeclarationHeader(FunctionDeclarationHeaderChildren {
3413 type_parameter_list,
3417 capability_provisional,
3420 if name.value.is_missing() {
3421 Self::raise_parsing_error(name, env, &syntax_error::empty_method_name);
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)?;
3444 LambdaSignature(LambdaSignatureChildren {
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)?;
3458 Token(_) => Ok(FunHdr::make_empty(env)),
3459 _ => Self::missing_syntax("function header", node, env),
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()),
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);
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),
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() {
3501 Ok(vec![ast::Stmt(p, stmt_)])
3505 fn mk_noop(env: &Env<TF>) -> ast::Stmt {
3506 ast::Stmt::noop(env.mk_none_pos())
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() => {
3524 if !e.top_level_statements
3525 && ((e.file_mode() == file_info::Mode::Mdecl && !e.codegen())
3530 Self::p_block(false /*remove noop*/, node, e)
3536 let f = |e: &mut Env<'a, TF>| {
3537 let expr = Self::p_expr(node, e)?;
3540 ast::Stmt_::mk_return(Some(expr)),
3543 if Self::is_simple_await_expression(node) {
3546 Ok(vec![Self::lift_awaits_in_statement(f, node, e)?])
3551 Self::with_new_nonconcurrent_scope(f, env)
3554 fn mk_suspension_kind(async_keyword: S<'a, T, V>) -> SuspensionKind {
3555 Self::mk_suspension_kind_(!async_keyword.is_missing())
3558 fn mk_suspension_kind_(has_async: bool) -> SuspensionKind {
3560 SuspensionKind::SKAsync
3562 SuspensionKind::SKSync
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,
3577 fn process_attribute_constructor_call(
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")
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()
3594 Self::raise_parsing_error(node, env, &syntax_error::soft_no_arguments);
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);
3601 constructor_call_argument_list,
3604 Ok(ast::UserAttribute { name, params })
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(
3614 Self::is_valid_attribute_arg(n, e);
3622 match &node.children {
3623 ParenthesizedExpression(c) => Self::is_valid_attribute_arg(&c.expression, env),
3624 // Normal literals (string, int, etc)
3625 LiteralExpression(_) => {}
3627 ScopeResolutionExpression(c) => {
3628 if let Some(TK::Class) = Self::token_kind(&c.name) {
3630 Self::raise_parsing_error(
3633 &syntax_error::expression_as_attribute_arguments,
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(
3646 &syntax_error::expression_as_attribute_arguments,
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);
3656 Self::raise_parsing_error(
3659 &syntax_error::expression_as_attribute_arguments,
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);
3676 ElementInitializer(c) => {
3677 Self::is_valid_attribute_arg(&c.key, env);
3678 Self::is_valid_attribute_arg(&c.value, env);
3680 // Everything else is not allowed
3681 _ => Self::raise_parsing_error(
3684 &syntax_error::expression_as_attribute_arguments,
3689 fn p_user_attribute(
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> {
3695 ConstructorCall(c) => {
3696 Self::process_attribute_constructor_call(node, &c.argument_list, &c.type_, e)
3698 _ => Self::missing_syntax("attribute", node, e),
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> {
3707 Attribute(c) => p_attr(&c.attribute_name, e),
3708 _ => Self::missing_syntax("attribute", node, e),
3714 _ => Self::missing_syntax("attribute specification", node, env),
3718 fn p_user_attributes(
3720 env: &mut Env<'a, TF>,
3721 ) -> Result<Vec<ast::UserAttribute>> {
3723 &Self::p_user_attribute,
3724 &|mut acc: Vec<ast::UserAttribute>, mut x: Vec<ast::UserAttribute>| {
3734 fn mp_yielding<F, R>(p: F, node: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<(R, bool)>
3736 F: FnOnce(S<'a, T, V>, &mut Env<'a, TF>) -> Result<R>,
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;
3746 fn mk_empty_ns_env(env: &Env<TF>) -> RcOc<NamespaceEnv> {
3747 RcOc::clone(&env.empty_ns_env)
3750 fn extract_docblock(node: S<'a, T, V>, env: &Env<TF>) -> Option<DocComment> {
3751 #[derive(Copy, Clone, Eq, PartialEq)]
3764 // `parse` mixes loop and recursion to use less stack space.
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();
3775 if s.2 == str.len() {
3780 match (s.1, chars[s.2] as char) {
3781 (LineCmt, '\n') => s = (next, Free, next),
3782 (EndEmbedded, '/') => s = (next, Free, next),
3784 let r = parse(str, next, Free, next);
3786 d @ Some(_) => break d,
3787 None => break Some((s.0, s.2 + 1, String::from(&str[s.0..s.2 + 1]))),
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),
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();
3823 .indexed_source_text
3824 .relative_pos(anchor + start, anchor + end);
3825 let ps = (pos, txt);
3826 oxidized::doc_comment::DocComment::new(ps)
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)?,
3843 Ok(ChildUnary(Box::new(operand), operator))
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)))
3850 XHPChildrenParenthesizedList(c) => {
3851 let children: std::result::Result<Vec<_>, _> = c
3853 .syntax_node_to_list_skip_separator()
3854 .map(|c| Self::p_xhp_child(c, env))
3856 Ok(ChildList(children?))
3858 _ => Self::missing_syntax("xhp children", node, env),
3863 class: &mut ast::Class_,
3865 env: &mut Env<'a, TF>,
3867 use ast::Visibility;
3868 let doc_comment_opt = Self::extract_docblock(node, env);
3869 let has_fun_header = |m: &MethodishDeclarationChildren<T, V>| {
3871 m.function_decl_header.children,
3872 FunctionDeclarationHeader(_)
3875 let p_method_vis = |
3878 env: &mut Env<'a, TF>,
3879 | -> Result<Visibility> {
3880 match Self::p_visibility_last_win(node, env)? {
3882 Self::raise_hh_error(env, Naming::method_needs_visibility(name_pos.clone()));
3883 Ok(Visibility::Public)
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> {
3898 ConstantDeclarator(c) => {
3899 let id = Self::pos_name(&c.name, e)?;
3900 let expr = if n.is_abstract() {
3904 Self::p_simple_initializer,
3909 Ok(ast::ClassConst {
3910 type_: type_.clone(),
3913 doc_comment: doc_comment_opt.clone(),
3916 _ => Self::missing_syntax("constant declarator", n, e),
3922 Ok(class.consts.append(&mut class_consts))
3924 TypeConstDeclaration(c) => {
3925 if !c.type_parameters.is_missing() {
3926 Self::raise_parsing_error(node, env, &syntax_error::tparams_in_tconst);
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)?;
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(
3941 NastCheck::not_abstract_without_typeconst(name.0.clone()),
3943 (constraint.clone(), ast::TypeconstAbstractKind::TCConcrete)
3945 (false, None, Some(_)) => (type__, ast::TypeconstAbstractKind::TCConcrete),
3946 (false, Some(_), Some(_)) => {
3947 (type__, ast::TypeconstAbstractKind::TCPartiallyAbstract)
3949 (true, _, None) => (
3951 ast::TypeconstAbstractKind::TCAbstract(type__),
3953 (true, _, Some(_)) => (None, ast::TypeconstAbstractKind::TCAbstract(type__)),
3955 Ok(class.typeconsts.push(ast::ClassTypeconst {
3956 abstract_: abstract_kind,
3962 doc_comment: doc_comment_opt,
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 {
3976 let name_exprs = Self::could_map(
3977 |n, e| -> Result<(Pos, ast::Sid, Option<ast::Expr>)> {
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,
3987 Ok((pos, name, expr))
3989 _ => Self::missing_syntax("property declarator", n, e),
3997 for name_expr in name_exprs.into_iter() {
3998 class.vars.push(ast::ClassVar {
3999 final_: kinds.has(modifier::FINAL),
4001 abstract_: kinds.has(modifier::ABSTRACT),
4003 type_: ast::TypeHint((), type_.clone()),
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),
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(¶m.name, '$');
4020 let span = match ¶m.expr {
4021 Some(ast::Expr(pos_end, _)) => {
4022 Pos::btw(p, pos_end).unwrap_or_else(|_| p.clone())
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())) };
4031 ast::Stmt_::mk_expr(e(E_::mk_binop(
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,
4039 e(E_::mk_lvar(lid(¶m.name))),
4046 visibility: param.visibility.unwrap(),
4047 type_: param.type_hint.clone(),
4048 id: ast::Id(p.clone(), cvname.to_string()),
4050 user_attributes: param.user_attributes.clone(),
4052 is_promoted_variadic: param.is_variadic,
4058 let header = &c.function_decl_header;
4059 let h = match &header.children {
4060 FunctionDeclarationHeader(h) => h,
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(
4068 &syntax_error::no_generics_on_constructors,
4071 let (mut member_init, mut member_def): (Vec<ast::Stmt>, Vec<ast::ClassVar>) = hdr
4074 .filter_map(|p| p.visibility.map(|_| classvar_init(p)))
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)?;
4084 member_init.reverse();
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),
4097 final_: kinds.has(modifier::FINAL),
4098 abstract_: is_abstract,
4102 tparams: hdr.type_parameters,
4103 where_constraints: hdr.constrs,
4104 variadic: Self::determine_variadicity(&hdr.parameters),
4105 params: hdr.parameters,
4108 body: ast::FuncBody {
4112 fun_kind: Self::mk_fun_kind(hdr.suspension_kind, body_has_yield),
4114 ret: ast::TypeHint((), hdr.return_type),
4115 external: is_external,
4116 doc_comment: doc_comment_opt,
4118 class.vars.append(&mut member_def);
4119 Ok(class.methods.push(method))
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 {
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)?,
4131 _ => Self::missing_syntax("trait use precedence item", n, e)?,
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(
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)?,
4148 _ => (None, Self::p_pstring(&c.aliasing_name, e)?),
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) {
4161 let vis = if kinds.is_empty() || kinds.has_any(modifier::VISIBILITIES) {
4164 let mut v = vec![ast::UseAsVisibility::UseAsPublic];
4165 v.append(&mut vis_raw);
4168 let aliased_name = if !c.aliased_name.is_missing() {
4169 Some(Self::pos_name(&c.aliased_name, e)?)
4173 Self::raise_hh_error(
4175 Naming::unsupported_trait_use_as(name.0.clone()),
4177 Ok(Either::Right(ast::UseAsAlias(
4184 _ => Self::missing_syntax("trait use conflict resolution item", n, e),
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() {
4192 Either::Left(l) => class.insteadof_alias.push(l),
4193 Either::Right(r) => class.use_as_alias.push(r),
4199 let mut uses = Self::could_map(Self::p_hint, &c.names, env)?;
4200 Ok(class.uses.append(&mut uses))
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)?,
4209 Ok(class.reqs.push((hint, is_extends)))
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![])),
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(
4228 &syntax_error::xhp_class_attribute_type_constant,
4232 let req = match &c.required.children {
4233 XHPRequired(_) => Some(ast::XhpAttrTag::Required),
4234 XHPLateinit(_) => Some(ast::XhpAttrTag::LateInit),
4237 let pos = if c.initializer.is_missing() {
4240 Pos::btw(&p, &Self::p_pos(&c.initializer, env))
4241 .map_err(Error::Failwith)?
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)))
4249 _ => (Some(Self::p_hint(&c.type_, env)?), None),
4252 Self::mp_optional(Self::p_simple_initializer, &c.initializer, env)?;
4253 let xhp_attr = ast::XhpAttr(
4254 ast::TypeHint((), hint.clone()),
4257 xhp_attr: Some(ast::XhpAttrInfo { xai_tag: req }),
4259 visibility: ast::Visibility::Public,
4260 type_: ast::TypeHint((), hint),
4261 id: ast::Id(p, String::from(":") + &name),
4263 user_attributes: vec![],
4265 is_promoted_variadic: false,
4272 Ok(Either::Left(xhp_attr))
4274 XHPSimpleClassAttribute(c) => mk_attr_use(&c.type_, env),
4275 Token(_) => mk_attr_use(node, env),
4276 _ => Self::missing_syntax("XHP attribute", node, env),
4279 let attrs = Self::could_map(p_attr, &c.attributes, env)?;
4280 for attr in attrs.into_iter() {
4282 Either::Left(attr) => class.xhp_attrs.push(attr),
4283 Either::Right(xhp_attr_use) => class.xhp_attr_uses.push(xhp_attr_use),
4288 XHPChildrenDeclaration(c) => {
4289 let p = Self::p_pos(node, env);
4292 .push((p, Self::p_xhp_child(&c.expression, env)?)))
4294 XHPCategoryDeclaration(c) => {
4295 let p = Self::p_pos(node, env);
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(
4302 NastCheck::multiple_xhp_category(category.0.clone()),
4306 Ok(class.xhp_category = Some((p, categories)))
4308 _ => Self::missing_syntax("class element", node, env),
4313 class: &mut ast::Class_,
4315 env: &mut Env<'a, TF>,
4317 let r = Self::p_class_elt_(class, node, env);
4319 // match ocaml behavior, don't throw if missing syntax when fail_open is true
4320 Err(Error::MissingSyntax { .. }) if env.fail_open() => Ok(()),
4325 fn contains_class_body(c: &ClassishDeclarationChildren<T, V>) -> bool {
4326 matches!(&c.body.children, ClassishBody(_))
4329 fn p_where_constraint(
4331 parent: S<'a, T, V>,
4333 env: &mut Env<'a, TF>,
4334 ) -> Result<Vec<ast::WhereConstraintHint>> {
4335 match &node.children {
4336 Missing => Ok(vec![]),
4338 let f = |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::WhereConstraintHint> {
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)?,
4350 Ok(ast::WhereConstraintHint(
4353 Self::p_hint(&c.right_type, e)?,
4356 _ => Self::missing_syntax("where constraint", n, e),
4360 .syntax_node_to_list_skip_separator()
4366 Self::missing_syntax("classish declaration constraints", parent, env)
4368 Self::missing_syntax("function header constraints", parent, env)
4374 fn p_namespace_use_kind(kind: S<'a, T, V>, env: &mut Env<'a, TF>) -> Result<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),
4388 fn p_namespace_use_clause(
4389 prefix: Option<S<'a, T, V>>,
4390 kind: Result<ast::NsKind>,
4392 env: &mut Env<'a, TF>,
4393 ) -> Result<(ast::NsKind, ast::Sid, ast::Sid)> {
4395 static ref NAMESPACE_USE: regex::Regex = regex::Regex::new("[^\\\\]*$").unwrap();
4398 match &node.children {
4399 NamespaceUseClause(NamespaceUseClauseChildren {
4405 let ast::Id(p, n) = match (prefix, Self::pos_name(name, env)?) {
4407 (Some(prefix), ast::Id(p, n)) => {
4408 ast::Id(p, Self::pos_name(prefix, env)?.1 + &n)
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())
4415 Self::pos_name(alias, env)?
4417 let kind = if clause_kind.is_missing() {
4420 Self::p_namespace_use_kind(clause_kind, env)
4426 if n.len() > 0 && n.chars().nth(0) == Some('\\') {
4429 String::from("\\") + &n
4435 _ => Self::missing_syntax("namespace use clause", node, env),
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 {
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 {
4454 Self::mp_yielding(&Self::p_function_body, body, env)?
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),
4464 mode: env.file_mode(),
4467 tparams: hdr.type_parameters,
4468 where_constraints: hdr.constrs,
4469 params: hdr.parameters,
4472 body: ast::FuncBody {
4476 fun_kind: Self::mk_fun_kind(hdr.suspension_kind, yield_),
4479 file_attributes: vec![],
4480 external: is_external,
4481 namespace: Self::mk_empty_ns_env(env),
4482 doc_comment: doc_comment_opt,
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)
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(),
4506 let (implements, implements_dynamic) = Self::could_map_filter(
4507 |node, env| -> Result<Option<ast::Hint>> {
4508 match Self::p_hint(node, env) {
4510 Ok(h) => match &*h.1 {
4511 oxidized::aast_defs::Hint_::Happly(oxidized::ast::Id(_, id), _) => {
4512 if id == "dynamic" {
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)?,
4536 let mut class_ = ast::Class_ {
4548 use_as_alias: vec![],
4549 insteadof_alias: vec![],
4550 xhp_attr_uses: vec![],
4560 // TODO: what is this attbiute? check ast_to_aast
4562 xhp_children: vec![],
4566 file_attributes: vec![],
4568 doc_comment: doc_comment_opt,
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)?;
4577 _ => Self::missing_syntax("classish body", &c.body, env)?,
4579 Ok(vec![ast::Def::mk_class(class_)])
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![];
4586 let def = match &decl.children {
4587 ConstantDeclarator(c) => {
4589 let init = &c.initializer;
4590 let gconst = ast::Gconst {
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),
4600 ast::Def::mk_constant(gconst)
4602 _ => Self::missing_syntax("constant declaration", decl, env)?,
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)
4615 Ok(vec![ast::Def::mk_typedef(ast::Typedef {
4617 name: Self::pos_name(&c.name, env)?,
4619 constraint: Self::mp_optional(Self::p_tconstraint, &c.constraint, env)?
4621 user_attributes: itertools::concat(
4623 .syntax_node_to_list_skip_separator()
4624 .map(|attr| Self::p_user_attribute(attr, env))
4625 .collect::<std::result::Result<Vec<Vec<_>>, _>>()?,
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)?,
4634 kind: Self::p_hint(&c.type_, env)?,
4635 span: Self::p_pos(node, env),
4639 EnumDeclaration(c) => {
4641 |n: S<'a, T, V>, e: &mut Env<'a, TF>| -> Result<ast::ClassConst> {
4643 Enumerator(c) => Ok(ast::ClassConst {
4645 id: Self::pos_name(&c.name, e)?,
4646 expr: Some(Self::p_expr(&c.value, e)?),
4649 _ => Self::missing_syntax("enumerator", n, e),
4652 Ok(vec![ast::Def::mk_class(ast::Class_ {
4654 mode: env.file_mode(),
4655 user_attributes: Self::p_user_attributes(&c.attribute_spec, env)?,
4656 file_attributes: vec![],
4658 kind: ast::ClassKind::Cenum,
4660 has_xhp_keyword: false,
4661 name: Self::pos_name(&c.name, env)?,
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)?,
4677 doc_comment: doc_comment_opt,
4679 use_as_alias: vec![],
4680 insteadof_alias: vec![],
4681 xhp_attr_uses: vec![],
4688 xhp_children: vec![],
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()),
4701 user_attributes.push(enum_class_attribute);
4702 // During lowering we store the base type as is. It will be updated during
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)
4718 let extends = Self::could_map(Self::p_hint, &c.extends_list, env)?;
4720 let mut enum_class = ast::Class_ {
4722 mode: env.file_mode(),
4724 file_attributes: vec![],
4725 final_: false, // TODO(T77095784): support final EDTs
4726 kind: ast::ClassKind::Cenum,
4728 has_xhp_keyword: false,
4731 extends: extends.clone(),
4733 implements_dynamic: false,
4734 where_constraints: vec![],
4736 namespace: Self::mk_empty_ns_env(env),
4737 span: Self::p_pos(node, env),
4738 enum_: Some(ast::Enum_ {
4744 doc_comment: doc_comment_opt,
4746 use_as_alias: vec![],
4747 insteadof_alias: vec![],
4748 xhp_attr_uses: vec![],
4755 xhp_children: vec![],
4760 for n in c.elements.syntax_node_to_list_skip_separator() {
4762 // TODO(T77095784): check pos and span usage
4763 EnumClassEnumerator(c) => {
4765 // - name<type>(args)
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)?;
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_);
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),
4791 enum_class.consts.push(class_const)
4794 let pos = Self::p_pos(n, env);
4795 Self::raise_parsing_error_pos(
4798 &syntax_error::invalid_enum_class_enumerator,
4803 Ok(vec![ast::Def::mk_class(enum_class)])
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)?,
4812 _ => Self::missing_syntax("record_field", n, e),
4814 Ok(vec![ast::Def::mk_record_def(ast::RecordDef {
4816 name: Self::pos_name(&c.name, env)?,
4817 extends: Self::could_map(Self::p_hint, &c.extends_opt, env)?
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,
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),
4836 NamespaceDeclaration(c) => {
4837 let name = if let NamespaceDeclarationHeader(h) = &c.header.children {
4840 return Self::missing_syntax("namespace_declaration_header", node, env);
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();
4848 .syntax_node_to_list_skip_separator()
4849 .map(|n| Self::p_def(n, env1))
4850 .collect::<std::result::Result<Vec<Vec<_>>, _>>()?,
4855 Ok(vec![ast::Def::mk_namespace(
4856 Self::pos_name(name, env)?,
4860 NamespaceGroupUseDeclaration(c) => {
4861 let uses: std::result::Result<Vec<_>, _> = c
4863 .syntax_node_to_list_skip_separator()
4865 Self::p_namespace_use_clause(
4867 Self::p_namespace_use_kind(&c.kind, env),
4873 Ok(vec![ast::Def::mk_namespace_use(uses?)])
4875 NamespaceUseDeclaration(c) => {
4876 let uses: std::result::Result<Vec<_>, _> = c
4878 .syntax_node_to_list_skip_separator()
4880 Self::p_namespace_use_clause(
4882 Self::p_namespace_use_kind(&c.kind, env),
4888 Ok(vec![ast::Def::mk_namespace_use(uses?)])
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),
4896 _ if env.file_mode() == file_info::Mode::Mdecl => Ok(vec![]),
4897 _ => Ok(vec![ast::Def::mk_stmt(Self::p_stmt(node, env)?)]),
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));
4912 if let Namespace(ns) = def {
4913 let (n, defs) = *ns;
4914 if defs.is_empty() {
4915 saw_ns = Some((n, vec![]));
4917 let mut acc_ = vec![];
4918 Self::post_process(env, defs, &mut acc_);
4919 acc.push(Def::mk_namespace(n, acc_));
4925 if let Stmt(s) = &def {
4929 let raise_error = match &s.1 {
4932 if expr.as_ref().is_import()
4933 && !env.parser_options.po_disallow_toplevel_requires =>
4938 use file_info::Mode::*;
4939 let mode = env.file_mode();
4941 && env.is_typechecker()
4943 || (mode == Mpartial
4946 .error_codes_treated_strictly
4951 Self::raise_parsing_error_pos(&s.0, env, &syntax_error::toplevel_statements);
4955 if let Some((_, ns_acc)) = &mut saw_ns {
4961 if let Some((n, defs)) = saw_ns {
4962 acc.push(Def::mk_namespace(n, defs));
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![];
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),
4979 let mut program = vec![];
4980 Self::post_process(env, acc, &mut program);
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),
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 {
5002 "missing case in {:?}.\n - pos: {:?}\n - unexpected: '{:?}'\n - kind: {:?}\n",
5003 expecting.to_string(),
5005 node_name.to_string(),
5008 Error::Failwith(msg) => msg,
5013 struct PositionedSyntaxLowerer;
5014 impl<'a> Lowerer<'a, PositionedToken<'a>, PositionedValue<'a>, PositionedTokenFactory<'a>>
5015 for PositionedSyntaxLowerer
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)