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.
8 use hh_autoimport_rust as hh_autoimport;
9 use itertools::{Either, Either::Left, Either::Right};
10 use naming_special_names_rust::{classes as special_classes, special_functions, special_idents};
11 use ocamlrep::rc::RcOc;
16 aast_visitor::{Node, Visitor},
18 doc_comment::DocComment,
20 global_options::GlobalOptions,
21 namespace_env::Env as NamespaceEnv,
25 use parser_core_types::{
26 indexed_source_text::IndexedSourceText, lexable_token::LexablePositionedToken,
27 positioned_syntax::PositionedSyntaxTrait, source_text::SourceText, syntax::*, syntax_error,
28 syntax_kind, syntax_trait::SyntaxTrait, token_kind::TokenKind as TK,
30 use regex::bytes::Regex;
32 cell::{Ref, RefCell, RefMut},
36 result::Result::{Err, Ok},
40 use crate::lowerer_modifier as modifier;
43 ($ty:ident) => {oxidized::aast::$ty};
44 // NOTE: In <,> pattern, comma prevents rustfmt eating <>
45 ($ty:ident<,>) => {oxidized::aast::$ty<Pos, (), (), ()>}
49 ($ty:ty) => { std::result::Result<$ty, Error> }
52 macro_rules! ret_aast {
53 ($ty:ident) => { std::result::Result<aast!($ty), Error> };
54 ($ty:ident<,>) => { std::result::Result<aast!($ty<,>), Error> }
57 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
58 pub enum LiftedAwaitKind {
63 type LiftedAwaitExprs = Vec<(Option<aast!(Lid)>, aast!(Expr<,>))>;
65 #[derive(Debug, Clone)]
66 pub struct LiftedAwaits {
67 pub awaits: LiftedAwaitExprs,
68 lift_kind: LiftedAwaitKind,
71 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
72 pub enum ExprLocation {
79 RightOfAssignmentInUsingStatement,
85 fn in_string(self) -> bool {
86 self == ExprLocation::InDoubleQuotedString || self == ExprLocation::InBacktickedString
90 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
91 pub enum SuspensionKind {
97 #[derive(Copy, Clone, Eq, PartialEq)]
107 suspension_kind: SuspensionKind,
109 constrs: Vec<aast_defs::WhereConstraint>,
110 type_parameters: Vec<aast!(Tparam<,>)>,
111 parameters: Vec<aast!(FunParam<,>)>,
112 return_type: Option<aast!(Hint)>,
116 fn make_empty(env: &Env) -> Self {
118 suspension_kind: SuspensionKind::SKSync,
119 name: ast_defs::Id(env.mk_none_pos(), String::from("<ANONYMOUS>")),
121 type_parameters: vec![],
130 /* Whether we've seen COMPILER_HALT_OFFSET. The value of COMPILER_HALT_OFFSET
131 defaults to 0 if HALT_COMPILER isn't called.
132 None -> COMPILER_HALT_OFFSET isn't in the source file
133 Some 0 -> COMPILER_HALT_OFFSET is in the source file, but HALT_COMPILER isn't
134 Some x -> COMPILER_HALT_OFFSET is in the source file,
135 HALT_COMPILER is at x bytes offset in the file.
137 pub saw_compiler_halt_offset: Option<usize>,
138 pub cls_reified_generics: HashSet<String>,
139 pub in_static_method: bool,
140 pub parent_maybe_reified: bool,
141 /* This provides a generic mechanism to delay raising parsing errors;
142 * since we're moving FFP errors away from CST to a stage after lowering
143 * _and_ want to prioritize errors before lowering, the lowering errors
144 * must be merely stored when the lowerer runs (until check for FFP runs (on AST)
145 * and raised _after_ FFP error checking (unless we run the lowerer twice,
146 * which would be expensive). */
147 pub lowpri_errors: Vec<(Pos, String)>,
148 pub doc_comments: Vec<Option<DocComment>>,
150 pub local_id_counter: isize,
153 #[derive(Debug, Clone)]
156 pub keep_errors: bool,
158 /* Show errors even in quick mode. Does not override keep_errors. Hotfix
159 * until we can properly set up saved states to surface parse errors during
160 * typechecking properly. */
161 pub show_all_errors: bool,
163 file_mode: file_info::Mode,
164 pub top_level_statements: bool, /* Whether we are (still) considering TLSs*/
166 // Cache none pos, lazy_static doesn't allow Rc.
168 empty_ns_env: RcOc<NamespaceEnv>,
170 pub saw_yield: bool, /* Information flowing back up */
171 pub lifted_awaits: Option<LiftedAwaits>,
172 pub tmp_var_counter: isize,
174 pub indexed_source_text: &'a IndexedSourceText<'a>,
175 pub parser_options: &'a GlobalOptions,
177 state: Rc<RefCell<State>>,
185 show_all_errors: bool,
186 mode: file_info::Mode,
187 indexed_source_text: &'a IndexedSourceText<'a>,
188 parser_options: &'a GlobalOptions,
190 // Ported from namespace_env.ml
191 let mut ns_uses = hh_autoimport::NAMESPACES_MAP.clone();
193 .po_auto_namespace_map
196 &ns_uses.insert(k.into(), v.into());
198 let empty_ns_env = NamespaceEnv {
200 class_uses: s_map::SMap::new(),
201 fun_uses: hh_autoimport::FUNCS_MAP.clone(),
202 const_uses: hh_autoimport::CONSTS_MAP.clone(),
203 record_def_uses: s_map::SMap::new(),
205 auto_ns_map: parser_options.po_auto_namespace_map.clone(),
216 top_level_statements: true,
222 pos_none: Pos::make_none(),
223 empty_ns_env: RcOc::new(empty_ns_env),
225 state: Rc::new(RefCell::new(State {
226 saw_compiler_halt_offset: None,
227 cls_reified_generics: HashSet::new(),
228 in_static_method: false,
229 parent_maybe_reified: false,
230 lowpri_errors: vec![],
231 doc_comments: vec![],
237 fn file_mode(&self) -> file_info::Mode {
241 fn should_surface_error(&self) -> bool {
242 (!self.quick_mode || self.show_all_errors) && self.keep_errors
245 fn is_typechecker(&self) -> bool {
249 fn codegen(&self) -> bool {
253 fn source_text(&self) -> &SourceText<'a> {
254 self.indexed_source_text.source_text()
257 fn fail_open(&self) -> bool {
261 fn saw_compiler_halt_offset(&mut self) -> RefMut<Option<usize>> {
262 RefMut::map(self.state.borrow_mut(), |s| &mut s.saw_compiler_halt_offset)
265 fn cls_reified_generics(&mut self) -> RefMut<HashSet<String>> {
266 RefMut::map(self.state.borrow_mut(), |s| &mut s.cls_reified_generics)
269 fn in_static_method(&mut self) -> RefMut<bool> {
270 RefMut::map(self.state.borrow_mut(), |s| &mut s.in_static_method)
273 fn parent_maybe_reified(&mut self) -> RefMut<bool> {
274 RefMut::map(self.state.borrow_mut(), |s| &mut s.parent_maybe_reified)
277 pub fn lowpri_errors(&mut self) -> RefMut<Vec<(Pos, String)>> {
278 RefMut::map(self.state.borrow_mut(), |s| &mut s.lowpri_errors)
281 fn top_docblock(&self) -> Ref<Option<DocComment>> {
282 Ref::map(self.state.borrow(), |s| {
283 s.doc_comments.last().unwrap_or(&None)
287 fn next_local_id(&self) -> isize {
288 let mut id = RefMut::map(self.state.borrow_mut(), |s| &mut s.local_id_counter);
293 fn push_docblock(&mut self, doc_comment: Option<DocComment>) {
294 RefMut::map(self.state.borrow_mut(), |s| &mut s.doc_comments).push(doc_comment)
297 fn pop_docblock(&mut self) {
298 RefMut::map(self.state.borrow_mut(), |s| &mut s.doc_comments).pop();
301 fn make_tmp_var_name(&mut self) -> String {
302 let name = String::from(special_idents::TMP_VAR_PREFIX) + &self.tmp_var_counter.to_string();
303 self.tmp_var_counter += 1;
307 fn mk_none_pos(&self) -> Pos {
308 self.pos_none.clone()
311 fn clone_and_unset_toplevel_if_toplevel<'b, 'c>(
313 ) -> impl AsMut<Env<'c>> + 'b {
314 if e.top_level_statements {
315 let mut cloned = e.clone();
316 cloned.top_level_statements = false;
324 impl<'a> AsMut<Env<'a>> for Env<'a> {
325 fn as_mut(&mut self) -> &mut Env<'a> {
336 kind: syntax_kind::SyntaxKind,
342 pub aast: aast!(Program<,>),
345 use parser_core_types::syntax::SyntaxVariant::*;
347 pub trait Lowerer<'a, T, V>
349 T: LexablePositionedToken<'a>,
350 Syntax<T, V>: PositionedSyntaxTrait,
351 V: SyntaxValueWithKind + SyntaxValueType<T> + std::fmt::Debug,
353 fn mode_annotation(mode: file_info::Mode) -> file_info::Mode {
355 file_info::Mode::Mphp => file_info::Mode::Mdecl,
360 // Turns a syntax node into a list of nodes; if it is a separated syntax
361 // list then the separators are filtered from the resulting list.
362 fn syntax_to_list(include_separators: bool, node: &Syntax<T, V>) -> Vec<&Syntax<T, V>> {
363 fn on_list_item<T1, V1>(sep: bool, x: &ListItemChildren<T1, V1>) -> Vec<&Syntax<T1, V1>> {
365 vec![&x.list_item, &x.list_separator]
374 .map(|x| match &x.syntax {
375 ListItem(x) => on_list_item(include_separators, x),
380 ListItem(x) => on_list_item(include_separators, x),
385 fn p_pos(node: &Syntax<T, V>, env: &Env) -> Pos {
386 node.position_exclusive(env.indexed_source_text)
387 .unwrap_or_else(|| env.mk_none_pos())
390 fn raise_parsing_error(node: &Syntax<T, V>, env: &mut Env, msg: &str) {
391 Self::raise_parsing_error_(Either::Left(node), env, msg)
394 fn raise_parsing_error_pos(pos: &Pos, env: &mut Env, msg: &str) {
395 Self::raise_parsing_error_(Either::Right(pos), env, msg)
398 fn raise_parsing_error_(node_or_pos: Either<&Syntax<T, V>, &Pos>, env: &mut Env, msg: &str) {
399 if env.should_surface_error() {
400 let pos = node_or_pos.either(|node| Self::p_pos(node, env), |pos| pos.clone());
401 env.lowpri_errors().push((pos, String::from(msg)))
402 } else if env.codegen() {
403 let pos = node_or_pos.either(
405 node.position_exclusive(env.indexed_source_text)
406 .unwrap_or_else(|| env.mk_none_pos())
410 env.lowpri_errors().push((pos, String::from(msg)))
414 fn raise_nast_error(msg: &str) {
415 // A placehold for error raised in ast_to_aast.ml
419 fn failwith<N>(msg: impl Into<String>) -> ret!(N) {
420 Err(Error::Failwith(msg.into()))
424 fn text(node: &Syntax<T, V>, env: &Env) -> String {
425 String::from(node.text(env.source_text()))
429 fn text_str<'b>(node: &'b Syntax<T, V>, env: &'b Env) -> &'b str {
430 node.text(env.source_text())
433 fn lowering_error(env: &mut Env, pos: &Pos, text: &str, syntax_kind: &str) {
434 if env.is_typechecker() && env.lowpri_errors().is_empty() {
435 // TODO: Ocaml also checks Errors.currently_has_errors
436 Self::raise_parsing_error_pos(
439 &syntax_error::lowering_parsing_error(text, syntax_kind),
444 fn missing_syntax<N>(
450 let pos = Self::p_pos(node, env);
451 let text = Self::text(node, env);
452 Self::lowering_error(env, &pos, &text, expecting);
453 if let Some(x) = fallback {
458 Err(Error::APIMissingSyntax {
459 expecting: String::from(expecting),
460 pos: Self::p_pos(node, env),
466 fn is_num_octal_lit(s: &str) -> bool {
467 !s.chars().any(|c| c == '8' || c == '9')
470 fn mp_optional<F, R>(p: F, node: &Syntax<T, V>, env: &mut Env) -> ret!(Option<R>)
472 F: FnOnce(&Syntax<T, V>, &mut Env) -> ret!(R),
476 _ => p(node, env).map(Some),
480 fn pos_qualified_name(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Sid) {
481 if let QualifiedName(c) = &node.syntax {
482 if let SyntaxList(l) = &c.qualified_name_parts.syntax {
483 let p = Self::p_pos(node, env);
484 let mut s = String::with_capacity(node.width());
488 s += li.list_item.text(env.source_text());
489 s += li.list_separator.text(env.source_text());
491 _ => s += i.text(env.source_text()),
494 return Ok(ast_defs::Id(p, s));
497 Self::missing_syntax(None, "qualified name", node, env)
501 fn pos_name(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Sid) {
502 Self::pos_name_(node, env, None)
505 fn lid_from_pos_name(pos: Pos, name: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Lid) {
506 let name = Self::pos_name(name, env)?;
507 Ok(aast::Lid::new(pos, name.1))
510 fn lid_from_name(name: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Lid) {
511 let name = Self::pos_name(name, env)?;
512 Ok(aast::Lid::new(name.0, name.1))
515 // TODO: after porting unify Sid and Pstring
517 fn p_pstring(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Pstring) {
518 Self::p_pstring_(node, env, None)
525 drop_prefix: Option<char>,
526 ) -> ret_aast!(Pstring) {
527 let ast_defs::Id(p, id) = Self::pos_name_(node, env, drop_prefix)?;
532 fn drop_prefix(s: &str, prefix: char) -> &str {
533 if s.len() > 0 && s.chars().nth(0) == Some(prefix) {
540 fn pos_name_(node: &Syntax<T, V>, env: &mut Env, drop_prefix: Option<char>) -> ret_aast!(Sid) {
542 QualifiedName(_) => Self::pos_qualified_name(node, env),
543 SimpleTypeSpecifier(c) => Self::pos_name_(&c.simple_type_specifier, env, drop_prefix),
545 let mut name = node.text(env.indexed_source_text.source_text());
546 if name == "__COMPILER_HALT_OFFSET__" {
547 *env.saw_compiler_halt_offset() = Some(0);
549 if let Some(prefix) = drop_prefix {
550 name = Self::drop_prefix(name, prefix);
552 let p = Self::p_pos(node, env);
553 Ok(ast_defs::Id(p, String::from(name)))
558 fn mk_str<F>(node: &Syntax<T, V>, env: &mut Env, unescaper: F, mut content: &str) -> String
560 F: Fn(&str) -> std::result::Result<String, InvalidString>,
562 if let Some('b') = content.chars().nth(0) {
563 content = content.get(1..).unwrap();
566 let len = content.len();
567 let no_quotes_result = extract_unquoted_string(content, 0, len);
568 match no_quotes_result {
570 let result = unescaper(&no_quotes);
574 Self::raise_parsing_error(
577 &format!("Malformed string literal <<{}>>", &no_quotes),
584 Self::raise_parsing_error(
587 &format!("Malformed string literal <<{}>>", &content),
594 fn unesc_dbl(s: &str) -> std::result::Result<String, InvalidString> {
595 let unesc_s = unescape_double(s)?;
596 match unesc_s.as_str() {
597 "''" | "\"\"" => Ok(String::from("")),
602 // TODO: return Cow<[u8]>
603 fn unesc_xhp(s: &[u8]) -> Vec<u8> {
605 static ref WHITESPACE: Regex = Regex::new("[\x20\t\n\r\x0c]+").unwrap();
607 WHITESPACE.replace_all(s, &b" "[..]).into_owned()
610 fn unesc_xhp_attr(s: &[u8]) -> Vec<u8> {
611 // TODO: change unesc_dbl to &[u8] -> Vec<u8>
612 let r = Self::get_quoted_content(s);
613 let r = unsafe { std::str::from_utf8_unchecked(r) };
614 Self::unesc_dbl(r).unwrap().into_bytes()
617 fn get_quoted_content(s: &[u8]) -> &[u8] {
619 static ref QUOTED: Regex = Regex::new(r#"^[\x20\t\n\r\x0c]*"((?:.|\n)*)""#).unwrap();
623 .map_or(None, |c| c.get(1))
624 .map_or(s, |m| m.as_bytes())
627 fn as_list(node: &Syntax<T, V>) -> Vec<&Syntax<T, V>> {
628 fn strip_list_item<T1, V1>(node: &Syntax<T1, V1>) -> &Syntax<T1, V1> {
630 ListItem(i) => &i.list_item,
635 SyntaxList(l) => l.iter().map(strip_list_item).collect(),
641 fn token_kind(node: &Syntax<T, V>) -> Option<TK> {
643 Token(t) => Some(t.kind()),
648 fn check_valid_reified_hint(env: &mut Env, node: &Syntax<T, V>, hint: &aast!(Hint)) {
649 struct Checker<F: FnMut(&String)>(F);
650 impl<F: FnMut(&String)> Visitor for Checker<F> {
659 ) -> &mut dyn Visitor<Context = Self::Context, Ex = Pos, Fb = (), En = (), Hi = ()>
664 fn visit_hint(&mut self, c: &mut (), h: &aast!(Hint)) {
666 aast::Hint_::Happly(id, _) => {
669 aast::Hint_::Haccess(_, ids) => {
670 ids.iter().for_each(|id| self.0(&id.1));
678 if *env.in_static_method() {
679 let f = |id: &String| {
680 Self::fail_if_invalid_reified_generic(node, env, id);
682 let mut visitor = Checker(f);
683 visitor.visit_hint(&mut (), hint);
687 fn p_closure_parameter(
690 ) -> ret!((aast!(Hint), Option<ast_defs::ParamKind>)) {
692 ClosureParameterTypeSpecifier(c) => {
693 let kind = Self::mp_optional(
695 &c.closure_parameter_call_convention,
698 let hint = Self::p_hint(&c.closure_parameter_type, env)?;
701 _ => Self::missing_syntax(None, "closure parameter", node, env),
705 fn mp_shape_expression_field<F, R>(
709 ) -> ret!((ast_defs::ShapeFieldName, R))
711 F: Fn(&Syntax<T, V>, &mut Env) -> ret!(R),
714 FieldInitializer(c) => {
715 let name = Self::p_shape_field_name(&c.field_initializer_name, env)?;
716 let value = f(&c.field_initializer_value, env)?;
719 _ => Self::missing_syntax(None, "shape field", node, env),
723 fn p_shape_field_name(node: &Syntax<T, V>, env: &mut Env) -> ret!(ast_defs::ShapeFieldName) {
724 use ast_defs::ShapeFieldName::*;
725 let is_valid_shape_literal = |t: &T| {
726 let is_str = t.kind() == TK::SingleQuotedStringLiteral
727 || t.kind() == TK::DoubleQuotedStringLiteral;
728 let text = t.text(env.source_text());
729 let is_empty = text == "\'\'" || text == "\"\"";
732 if let LiteralExpression(c) = &node.syntax {
733 if let Token(t) = &c.literal_expression.syntax {
734 if is_valid_shape_literal(t) {
735 let ast_defs::Id(p, n) = Self::pos_name(node, env)?;
736 let str_ = Self::mk_str(node, env, Self::unesc_dbl, &n);
737 match ocaml_helper::int_of_string_opt(&str_.as_bytes()) {
738 Some(_) => Self::raise_parsing_error(
741 &syntax_error::shape_field_int_like_string,
745 return Ok(SFlitStr((p, str_)));
750 ScopeResolutionExpression(c) => Ok(SFclassConst(
751 Self::pos_name(&c.scope_resolution_qualifier, env)?,
752 Self::p_pstring(&c.scope_resolution_name, env)?,
755 Self::raise_parsing_error(node, env, &syntax_error::invalid_shape_field_name);
756 let ast_defs::Id(p, n) = Self::pos_name(node, env)?;
757 Ok(SFlitStr((p, Self::mk_str(node, env, Self::unesc_dbl, &n))))
762 fn p_shape_field(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(ShapeFieldInfo) {
764 FieldSpecifier(c) => {
765 let optional = !c.field_question.is_missing();
766 let name = Self::p_shape_field_name(&c.field_name, env)?;
767 let hint = Self::p_hint(&c.field_type, env)?;
768 Ok(aast::ShapeFieldInfo {
775 let (name, hint) = Self::mp_shape_expression_field(Self::p_hint, node, env)?;
776 Ok(aast::ShapeFieldInfo {
785 fn p_targ(node: &Syntax<T, V>, env: &mut Env) -> ret!(aast::Targ<()>) {
786 Ok(aast::Targ((), Self::p_hint(node, env)?))
789 fn p_hint_(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Hint_) {
790 use aast_defs::Hint_::*;
791 let unary = |kw, ty, env: &mut Env| {
793 Self::pos_name(kw, env)?,
794 Self::could_map(Self::p_hint, ty, env)?,
797 let binary = |kw, key, ty, env: &mut Env| {
798 let kw = Self::pos_name(kw, env)?;
799 let key = Self::p_hint(key, env)?;
802 Self::map_flatten_(&Self::p_hint, ty, env, vec![key])?,
806 /* Dirty hack; CastExpression can have type represented by token */
807 Token(_) | SimpleTypeSpecifier(_) | QualifiedName(_) => {
808 Ok(Happly(Self::pos_name(node, env)?, vec![]))
810 ShapeTypeSpecifier(c) => {
811 let allows_unknown_fields = !c.shape_type_ellipsis.is_missing();
812 /* if last element lacks a separator and ellipsis is present, error */
813 if let Some(l) = Self::syntax_to_list(true, &c.shape_type_fields).last() {
814 if l.is_missing() && allows_unknown_fields {
815 Self::raise_parsing_error(
818 &syntax_error::shape_type_ellipsis_without_trailing_comma,
823 let field_map = Self::could_map(Self::p_shape_field, &c.shape_type_fields, env)?;
825 Ok(Hshape(aast::NastShapeInfo {
826 allows_unknown_fields,
830 TupleTypeSpecifier(c) => {
831 Ok(Htuple(Self::could_map(Self::p_hint, &c.tuple_types, env)?))
833 UnionTypeSpecifier(c) => {
834 Ok(Hunion(Self::could_map(&Self::p_hint, &c.union_types, env)?))
836 IntersectionTypeSpecifier(c) => Ok(Hintersection(Self::could_map(
838 &c.intersection_types,
841 KeysetTypeSpecifier(c) => Ok(Happly(
842 Self::pos_name(&c.keyset_type_keyword, env)?,
843 Self::could_map(Self::p_hint, &c.keyset_type_type, env)?,
845 VectorTypeSpecifier(c) => unary(&c.vector_type_keyword, &c.vector_type_type, env),
846 ClassnameTypeSpecifier(c) => unary(&c.classname_keyword, &c.classname_type, env),
847 TupleTypeExplicitSpecifier(c) => unary(&c.tuple_type_keyword, &c.tuple_type_types, env),
848 VarrayTypeSpecifier(c) => unary(&c.varray_keyword, &c.varray_type, env),
849 VectorArrayTypeSpecifier(c) => {
850 unary(&c.vector_array_keyword, &c.vector_array_type, env)
852 DarrayTypeSpecifier(c) => {
853 binary(&c.darray_keyword, &c.darray_key, &c.darray_value, env)
855 MapArrayTypeSpecifier(c) => binary(
856 &c.map_array_keyword,
861 DictionaryTypeSpecifier(c) => {
862 unary(&c.dictionary_type_keyword, &c.dictionary_type_members, env)
864 GenericTypeSpecifier(c) => {
865 let name = Self::pos_name(&c.generic_class_type, env)?;
866 let args = &c.generic_argument_list;
867 let type_args = match &args.syntax {
868 TypeArguments(c) => {
869 Self::could_map(Self::p_hint, &c.type_arguments_types, env)?
871 _ => Self::missing_syntax(None, "generic type arguments", args, env)?,
874 // aorenste: Not sure why the original code had this as
875 // unimplemented!(), but returning the type is better than
877 Ok(Happly(name, type_args))
879 Ok(Happly(name, type_args))
882 NullableTypeSpecifier(c) => Ok(Hoption(Self::p_hint(&c.nullable_type, env)?)),
883 LikeTypeSpecifier(c) => Ok(Hlike(Self::p_hint(&c.like_type, env)?)),
884 SoftTypeSpecifier(c) => Ok(Hsoft(Self::p_hint(&c.soft_type, env)?)),
885 ClosureTypeSpecifier(c) => {
886 let (param_list, variadic_hints): (Vec<&Syntax<T, V>>, Vec<&Syntax<T, V>>) =
887 Self::as_list(&c.closure_parameter_list)
889 .partition(|n| match &n.syntax {
890 VariadicParameter(_) => false,
893 let (type_hints, kinds) = param_list
895 .map(|p| Self::p_closure_parameter(p, env))
896 .collect::<std::result::Result<Vec<_>, _>>()?
899 let variadic_hints = variadic_hints
901 .map(|v| match &v.syntax {
902 VariadicParameter(c) => {
903 let vtype = &c.variadic_parameter_type;
904 if vtype.is_missing() {
905 Self::raise_parsing_error(
908 "Cannot use ... without a typehint",
911 Ok(Some(Self::p_hint(vtype, env)?))
913 _ => panic!("expect variadic parameter"),
915 .collect::<std::result::Result<Vec<_>, _>>()?;
916 if variadic_hints.len() > 1 {
917 return Self::failwith(format!(
918 "{} variadic parameters found. There should be no more than one.",
919 variadic_hints.len().to_string()
922 Ok(Hfun(aast::HintFun {
923 reactive_kind: aast::FuncReactive::FNonreactive,
924 is_coroutine: !c.closure_coroutine.is_missing(),
925 param_tys: type_hints,
927 param_mutability: vec![],
928 variadic_ty: variadic_hints.into_iter().next().unwrap_or(None),
929 return_ty: Self::p_hint(&c.closure_return_type, env)?,
930 is_mutable_return: true,
933 AttributizedSpecifier(c) => {
934 let attrs = Self::p_user_attribute(&c.attributized_specifier_attribute_spec, env)?;
935 let hint = Self::p_hint(&c.attributized_specifier_type, env)?;
936 if attrs.iter().any(|attr| attr.name.1 != "__Soft") {
937 Self::raise_parsing_error(node, env, &syntax_error::only_soft_allowed);
939 Ok(*Self::soften_hint(&attrs, hint).1)
942 let child = Self::pos_name(&c.type_constant_right_type, env)?;
943 match Self::p_hint_(&c.type_constant_left_type, env)? {
944 Haccess(root, mut cs) => {
946 Ok(Haccess(root, cs))
948 Happly(ty, param) => {
949 if param.is_empty() {
950 let root = aast::Hint::new(ty.0.clone(), Happly(ty, param));
951 Ok(Haccess(root, vec![child]))
953 Self::missing_syntax(None, "type constant base", node, env)
956 _ => Self::missing_syntax(None, "type constant base", node, env),
960 let pos = Self::p_pos(&c.pu_access_left_type, env);
961 let child = Self::pos_name(&c.pu_access_right_type, env)?;
962 match Self::p_hint_(&c.pu_access_left_type, env)? {
963 h @ HpuAccess(_, _) => Ok(HpuAccess(aast::Hint::new(pos, h), child)),
964 Happly(id, hints) => {
965 if hints.is_empty() {
966 Ok(HpuAccess(aast::Hint::new(pos, Happly(id, hints)), child))
968 Self::missing_syntax(None, "pocket universe access base", node, env)
971 _ => Self::missing_syntax(None, "pocket universe access base", node, env),
974 ReifiedTypeArgument(_) => {
975 Self::raise_parsing_error(node, env, &syntax_error::invalid_reified);
976 Self::missing_syntax(None, "refied type", node, env)
978 _ => Self::missing_syntax(None, "type hint", node, env),
982 fn p_hint(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Hint) {
983 let hint_ = Self::p_hint_(node, env)?;
984 let pos = Self::p_pos(node, env);
985 let hint = aast::Hint::new(pos, hint_);
986 Self::check_valid_reified_hint(env, node, &hint);
990 fn p_simple_initializer(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Expr<,>) {
992 SimpleInitializer(c) => Self::p_expr(&c.simple_initializer_value, env),
993 _ => Self::missing_syntax(None, "simple initializer", node, env),
997 fn p_member(node: &Syntax<T, V>, env: &mut Env) -> ret!((aast!(Expr<,>), aast!(Expr<,>))) {
999 ElementInitializer(c) => Ok((
1000 Self::p_expr(&c.element_key, env)?,
1001 Self::p_expr(&c.element_value, env)?,
1003 _ => Self::missing_syntax(None, "darray intrinsic expression element", node, env),
1007 fn expand_type_args(ty: &Syntax<T, V>, env: &mut Env) -> ret!(Vec<aast!(Hint)>) {
1009 TypeArguments(c) => Self::could_map(Self::p_hint, &c.type_arguments_types, env),
1014 fn p_afield(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Afield<,>) {
1015 match &node.syntax {
1016 ElementInitializer(c) => Ok(aast::Afield::AFkvalue(
1017 Self::p_expr(&c.element_key, env)?,
1018 Self::p_expr(&c.element_value, env)?,
1020 _ => Ok(aast::Afield::AFvalue(Self::p_expr(node, env)?)),
1024 fn check_intrinsic_type_arg_varity(
1025 node: &Syntax<T, V>,
1027 tys: Vec<aast!(Hint)>,
1028 ) -> Option<aast::CollectionTarg<()>> {
1029 let count = tys.len();
1030 let mut tys = tys.into_iter();
1032 2 => Some(aast::CollectionTarg::CollectionTKV(
1033 aast::Targ((), tys.next().unwrap()),
1034 aast::Targ((), tys.next().unwrap()),
1036 1 => Some(aast::CollectionTarg::CollectionTV(aast::Targ(
1038 tys.next().unwrap(),
1042 Self::raise_parsing_error(
1045 &syntax_error::collection_intrinsic_many_typeargs,
1052 fn p_import_flavor(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(ImportFlavor) {
1053 use aast::ImportFlavor::*;
1054 match Self::token_kind(node) {
1055 Some(TK::Include) => Ok(Include),
1056 Some(TK::Require) => Ok(Require),
1057 Some(TK::Include_once) => Ok(IncludeOnce),
1058 Some(TK::Require_once) => Ok(RequireOnce),
1059 _ => Self::missing_syntax(None, "import flavor", node, env),
1063 fn p_null_flavor(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(OgNullFlavor) {
1064 use aast::OgNullFlavor::*;
1065 match Self::token_kind(node) {
1066 Some(TK::QuestionMinusGreaterThan) => Ok(OGNullsafe),
1067 Some(TK::MinusGreaterThan) => Ok(OGNullthrows),
1068 _ => Self::missing_syntax(None, "null flavor", node, env),
1073 fn wrap_unescaper<F>(unescaper: F, s: &str) -> ret!(String)
1075 F: FnOnce(&str) -> std::result::Result<String, InvalidString>,
1077 unescaper(s).map_err(|e| Error::Failwith(e.msg))
1080 fn fail_if_invalid_class_creation(node: &Syntax<T, V>, env: &mut Env, id: impl AsRef<str>) {
1081 let id = id.as_ref();
1082 let is_in_static_method = *env.in_static_method();
1083 if is_in_static_method
1084 && ((id == special_classes::SELF && !env.cls_reified_generics().is_empty())
1085 || (id == special_classes::PARENT && *env.parent_maybe_reified()))
1087 Self::raise_parsing_error(node, env, &syntax_error::static_method_reified_obj_creation);
1091 fn fail_if_invalid_reified_generic(node: &Syntax<T, V>, env: &mut Env, id: impl AsRef<str>) {
1092 let is_in_static_method = *env.in_static_method();
1093 if is_in_static_method && env.cls_reified_generics().contains(id.as_ref()) {
1094 Self::raise_parsing_error(
1097 &syntax_error::cls_reified_generic_in_static_method,
1102 // (hrust) `i` is initial index
1103 fn rfind(s: &[u8], mut i: usize, c: u8) -> ret!(usize) {
1105 return Self::failwith("index out of range");
1114 Self::failwith("char not found")
1117 fn prep_string2(nodes: &[Syntax<T, V>], env: &mut Env) -> ret!((TokenOp, TokenOp)) {
1119 let is_qoute = |c| c == b'\"' || c == b'`';
1120 let start_is_qoute = |s: &[u8]| {
1121 (s.len() > 0 && is_qoute(s[0])) || (s.len() > 1 && (s[0] == b'b' && s[1] == b'\"'))
1123 let last_is_qoute = |s: &[u8]| s.len() > 0 && is_qoute(s[s.len() - 1]);
1124 let is_heredoc = |s: &[u8]| (s.len() > 3 && &s[0..3] == b"<<<");
1125 let mut nodes = nodes.iter();
1126 let first = nodes.next();
1127 match first.map(|n| &n.syntax) {
1130 Self::raise_parsing_error(first.unwrap(), env, "Malformed String2 SyntaxList");
1132 let text = t.text_raw(env.source_text());
1133 if start_is_qoute(text) {
1134 let first_token_op = match text[0] {
1135 b'b' if text.len() > 2 => LeftTrim(2),
1136 _ if is_qoute(text[0]) && text.len() > 1 => LeftTrim(1),
1139 if let Some(Token(t)) = nodes.last().map(|n| &n.syntax) {
1140 let last_text = t.text_raw(env.source_text());
1141 if last_is_qoute(last_text) {
1142 let last_taken_op = match last_text.len() {
1143 n if n > 1 => RightTrim(1),
1146 return Ok((first_token_op, last_taken_op));
1150 Ok((first_token_op, Noop))
1151 } else if is_heredoc(text) {
1152 let trim_size = text
1154 .position(|c| *c == b'\n')
1155 .ok_or_else(|| Error::Failwith(String::from("newline not found")))?
1157 let first_token_op = match trim_size {
1158 _ if trim_size == text.len() => Skip,
1159 _ => LeftTrim(trim_size),
1161 if let Some(Token(t)) = nodes.last().map(|n| &n.syntax) {
1162 let text = t.text_raw(env.source_text());
1163 let len = text.len();
1165 let n = Self::rfind(text, len - 2, b'\n')?;
1166 let last_token_op = match n {
1168 _ => RightTrim(len - n),
1170 return Ok((first_token_op, last_token_op));
1174 Ok((first_token_op, Noop))
1179 _ => Ok((Noop, Noop)),
1183 fn process_token_op(op: TokenOp, node: &Syntax<T, V>) -> ret!(Option<Syntax<T, V>>) {
1186 LeftTrim(n) => match &node.syntax {
1188 let mut token = t.clone_value();
1189 token.trim_left(n).map_err(Error::Failwith)?;
1190 let node = <Syntax<T, V>>::make_token(token);
1193 _ => Self::failwith("Token expected"),
1195 RightTrim(n) => match &node.syntax {
1197 let mut token = t.clone_value();
1198 token.trim_right(n).map_err(Error::Failwith)?;
1199 let node = <Syntax<T, V>>::make_token(token);
1202 _ => Self::failwith("Token expected"),
1208 fn p_string2(nodes: &[Syntax<T, V>], env: &mut Env) -> ret!(Vec<aast!(Expr<,>)>) {
1210 let (head_op, tail_op) = Self::prep_string2(nodes, env)?;
1211 let mut result = Vec::with_capacity(nodes.len());
1213 let last = nodes.len() - 1;
1217 _ if i == last => tail_op,
1226 let node = Self::process_token_op(op, &nodes[i])?;
1227 let node = node.as_ref().unwrap_or(&nodes[i]);
1229 if Self::token_kind(node) == Some(TK::Dollar) && i < last {
1230 if let EmbeddedBracedExpression(c) = &nodes[i + 1].syntax {
1231 Self::raise_parsing_error(
1234 &syntax_error::outside_dollar_str_interp,
1237 result.push(Self::p_expr_with_loc(
1238 ExprLocation::InDoubleQuotedString,
1247 result.push(Self::p_expr_with_loc(
1248 ExprLocation::InDoubleQuotedString,
1257 fn p_expr_l(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Expr<,>) {
1258 Self::p_expr_l_with_loc(ExprLocation::TopLevel, node, env)
1261 fn p_expr_l_with_loc(
1263 node: &Syntax<T, V>,
1265 ) -> ret_aast!(Expr<,>) {
1266 let p_expr = |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(Expr<,>) {
1267 Self::p_expr_with_loc(loc, n, e)
1270 Self::p_pos(node, env),
1271 E_::ExprList(Self::could_map(p_expr, node, env)?),
1276 fn p_expr(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Expr<,>) {
1277 Self::p_expr_with_loc(ExprLocation::TopLevel, node, env)
1282 location: ExprLocation,
1283 node: &Syntax<T, V>,
1285 ) -> ret_aast!(Expr<,>) {
1286 Self::p_expr_impl(location, node, env, None)
1290 location: ExprLocation,
1291 node: &Syntax<T, V>,
1293 parent_pos: Option<Pos>,
1294 ) -> ret_aast!(Expr<,>) {
1295 match &node.syntax {
1296 BracedExpression(c) => {
1297 let expr = &c.braced_expression_expression;
1298 let inner = Self::p_expr_impl(location, expr, env, parent_pos)?;
1299 let inner_pos = &inner.0;
1300 let inner_expr_ = &inner.1;
1303 Lvar(_) | String(_) | Int(_) | Float(_) => Ok(inner),
1304 _ => Ok(aast::Expr::new(
1306 E_::mk_braced_expr(inner),
1310 ParenthesizedExpression(c) => Self::p_expr_impl(
1312 &c.parenthesized_expression_expression,
1317 let pos = Self::p_pos(node, env);
1318 let expr_ = Self::p_expr_impl_(location, node, env, parent_pos)?;
1319 Ok(aast::Expr::new(pos, expr_))
1325 location: ExprLocation,
1326 parent: &Syntax<T, V>,
1327 expr: &Syntax<T, V>,
1329 ) -> ret_aast!(Expr_<,>) {
1330 match &expr.syntax {
1332 let s = expr.text(env.indexed_source_text.source_text());
1333 match (location, Self::token_kind(expr)) {
1334 (ExprLocation::InDoubleQuotedString, _) if env.codegen() => {
1335 Ok(E_::String(Self::mk_str(expr, env, Self::unesc_dbl, s)))
1337 (ExprLocation::InBacktickedString, _) if env.codegen() => {
1338 Ok(E_::String(Self::mk_str(expr, env, unescape_backtick, s)))
1340 (_, Some(TK::OctalLiteral))
1341 if env.is_typechecker() && !Self::is_num_octal_lit(s) =>
1343 Self::raise_parsing_error(
1346 &syntax_error::invalid_octal_integer,
1348 Self::missing_syntax(None, "octal", expr, env)
1350 (_, Some(TK::DecimalLiteral))
1351 | (_, Some(TK::OctalLiteral))
1352 | (_, Some(TK::HexadecimalLiteral))
1353 | (_, Some(TK::BinaryLiteral)) => Ok(E_::Int(s.replace("_", ""))),
1354 (_, Some(TK::FloatingLiteral)) => Ok(E_::Float(String::from(s))),
1355 (_, Some(TK::SingleQuotedStringLiteral)) => {
1356 Ok(E_::String(Self::mk_str(expr, env, unescape_single, s)))
1358 (_, Some(TK::DoubleQuotedStringLiteral)) => {
1359 Ok(E_::String(Self::mk_str(expr, env, unescape_double, s)))
1361 (_, Some(TK::HeredocStringLiteral)) => {
1362 Ok(E_::String(Self::mk_str(expr, env, unescape_heredoc, s)))
1364 (_, Some(TK::NowdocStringLiteral)) => {
1365 Ok(E_::String(Self::mk_str(expr, env, unescape_nowdoc, s)))
1367 (_, Some(TK::NullLiteral)) => {
1368 // TODO: Handle Lint
1371 (_, Some(TK::BooleanLiteral)) => {
1372 // TODO: Handle Lint
1373 if s.eq_ignore_ascii_case("false") {
1375 } else if s.eq_ignore_ascii_case("true") {
1378 Self::missing_syntax(None, &format!("boolean (not: {})", s), expr, env)
1381 _ => Self::missing_syntax(None, "literal", expr, env),
1384 SyntaxList(ts) => Ok(E_::String2(Self::p_string2(ts.as_slice(), env)?)),
1385 _ => Self::missing_syntax(None, "literal expressoin", expr, env),
1389 fn p_expr_with_loc_(
1390 location: ExprLocation,
1391 node: &Syntax<T, V>,
1393 ) -> ret_aast!(Expr_<,>) {
1394 Self::p_expr_impl_(location, node, env, None)
1398 location: ExprLocation,
1399 node: &Syntax<T, V>,
1401 parent_pos: Option<Pos>,
1402 ) -> ret_aast!(Expr_<,>) {
1403 use aast::Expr as E;
1404 let split_args_varargs = |arg_list_node: &Syntax<T, V>,
1406 -> ret!((Vec<aast!(Expr<,>)>, Vec<aast!(Expr<,>)>)) {
1407 let mut arg_list = Self::as_list(arg_list_node);
1408 if let Some(last_arg) = arg_list.last() {
1409 if let DecoratedExpression(c) = &last_arg.syntax {
1410 if Self::token_kind(&c.decorated_expression_decorator) == Some(TK::DotDotDot) {
1411 let _ = arg_list.pop();
1412 let args: std::result::Result<Vec<_>, _> =
1413 arg_list.iter().map(|a| Self::p_expr(a, e)).collect();
1415 let vararg = Self::p_expr(&c.decorated_expression_expression, e)?;
1416 return Ok((args, vec![vararg]));
1420 Ok((Self::could_map(Self::p_expr, arg_list_node, e)?, vec![]))
1422 let mk_lid = |p: Pos, s: String| aast::Lid(p, (0, s));
1423 let mk_name_lid = |name: &Syntax<T, V>, env: &mut Env| {
1424 let name = Self::pos_name(name, env)?;
1425 Ok(mk_lid(name.0, name.1))
1427 let mk_lvar = |name: &Syntax<T, V>, env: &mut Env| Ok(E_::mk_lvar(mk_name_lid(name, env)?));
1428 let mk_id_expr = |name: aast!(Sid)| E::new(name.0.clone(), E_::mk_id(name));
1429 let p_intri_expr = |kw, ty, v, e: &mut Env| {
1430 let hints = Self::expand_type_args(ty, e)?;
1431 let hints = Self::check_intrinsic_type_arg_varity(node, e, hints);
1432 Ok(E_::mk_collection(
1433 Self::pos_name(kw, e)?,
1435 Self::could_map(Self::p_afield, v, e)?,
1438 let p_special_call =
1439 |recv: &Syntax<T, V>, args: &Syntax<T, V>, e: &mut Env| -> ret_aast!(Expr_<,>) {
1440 let pos_if_has_parens = match &recv.syntax {
1441 ParenthesizedExpression(_) => Some(Self::p_pos(recv, e)),
1444 let recv = Self::p_expr(recv, e)?;
1445 let recv = match (&recv.1, pos_if_has_parens) {
1446 (E_::ObjGet(_), Some(p)) => E::new(p, E_::mk_parenthesized_expr(recv)),
1447 (E_::ClassGet(_), Some(p)) => E::new(p, E_::mk_parenthesized_expr(recv)),
1450 let (args, varargs) = split_args_varargs(args, e)?;
1452 aast::CallType::Cnormal,
1459 let p_obj_get = |recv: &Syntax<T, V>,
1461 name: &Syntax<T, V>,
1463 -> ret_aast!(Expr_<,>) {
1464 if recv.is_object_creation_expression() && !e.codegen() {
1465 Self::raise_parsing_error(recv, e, &syntax_error::invalid_constructor_method_call);
1467 let recv = Self::p_expr(recv, e)?;
1468 let name = Self::p_expr_with_loc(ExprLocation::MemberSelect, name, e)?;
1469 let op = Self::p_null_flavor(op, e)?;
1470 Ok(E_::mk_obj_get(recv, name, op))
1472 let pos = match parent_pos {
1473 None => Self::p_pos(node, env),
1476 match &node.syntax {
1477 LambdaExpression(c) => {
1478 let suspension_kind =
1479 Self::mk_suspension_kind(node, env, &c.lambda_async, &c.lambda_coroutine);
1480 let (params, ret) = match &c.lambda_signature.syntax {
1481 LambdaSignature(c) => (
1482 Self::could_map(Self::p_fun_param, &c.lambda_parameters, env)?,
1483 Self::mp_optional(Self::p_hint, &c.lambda_type, env)?,
1486 let ast_defs::Id(p, n) = Self::pos_name(&c.lambda_signature, env)?;
1488 vec![aast::FunParam {
1489 annotation: p.clone(),
1490 type_hint: aast::TypeHint((), None),
1491 is_reference: false,
1497 user_attributes: vec![],
1503 _ => Self::missing_syntax(None, "lambda signature", &c.lambda_signature, env)?,
1505 let (body, yield_) = if !c.lambda_body.is_compound_statement() {
1506 Self::mp_yielding(Self::p_function_body, &c.lambda_body, env)?
1508 let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
1509 Self::mp_yielding(&Self::p_function_body, &c.lambda_body, env1.as_mut())?
1511 let external = c.lambda_body.is_external();
1512 let fun = aast::Fun_ {
1515 mode: Self::mode_annotation(env.file_mode()),
1516 ret: aast::TypeHint((), ret),
1517 name: ast_defs::Id(pos, String::from(";anonymous")),
1519 where_constraints: vec![],
1520 body: aast::FuncBody {
1524 fun_kind: Self::mk_fun_kind(suspension_kind, yield_),
1525 variadic: Self::determine_variadicity(¶ms),
1527 user_attributes: Self::p_user_attributes(&c.lambda_attribute_spec, env)?,
1528 file_attributes: vec![],
1530 namespace: Self::mk_empty_ns_env(env),
1534 Ok(E_::mk_lfun(fun, vec![]))
1536 BracedExpression(c) => {
1537 Self::p_expr_with_loc_(location, &c.braced_expression_expression, env)
1539 EmbeddedBracedExpression(c) => Self::p_expr_impl_(
1541 &c.embedded_braced_expression_expression,
1545 ParenthesizedExpression(c) => {
1546 Self::p_expr_with_loc_(location, &c.parenthesized_expression_expression, env)
1548 DictionaryIntrinsicExpression(c) => p_intri_expr(
1549 &c.dictionary_intrinsic_keyword,
1550 &c.dictionary_intrinsic_explicit_type,
1551 &c.dictionary_intrinsic_members,
1554 KeysetIntrinsicExpression(c) => p_intri_expr(
1555 &c.keyset_intrinsic_keyword,
1556 &c.keyset_intrinsic_explicit_type,
1557 &c.keyset_intrinsic_members,
1560 VectorIntrinsicExpression(c) => p_intri_expr(
1561 &c.vector_intrinsic_keyword,
1562 &c.vector_intrinsic_explicit_type,
1563 &c.vector_intrinsic_members,
1566 CollectionLiteralExpression(c) => {
1567 let collection_name = &c.collection_literal_name;
1568 let (collection_name, hints) = match &collection_name.syntax {
1569 SimpleTypeSpecifier(c) => {
1570 (Self::pos_name(&c.simple_type_specifier, env)?, None)
1572 GenericTypeSpecifier(c) => {
1573 let hints = Self::expand_type_args(&c.generic_argument_list, env)?;
1574 let hints = Self::check_intrinsic_type_arg_varity(node, env, hints);
1575 (Self::pos_name(&c.generic_class_type, env)?, hints)
1577 _ => (Self::pos_name(collection_name, env)?, None),
1579 Ok(E_::mk_collection(
1582 Self::could_map(Self::p_afield, &c.collection_literal_initializers, env)?,
1585 VarrayIntrinsicExpression(c) => {
1586 let hints = Self::expand_type_args(&c.varray_intrinsic_explicit_type, env)?;
1587 let hints = Self::check_intrinsic_type_arg_varity(node, env, hints);
1588 let targ = match hints {
1589 Some(aast::CollectionTarg::CollectionTV(ty)) => Some(ty),
1591 _ => Self::missing_syntax(
1593 "VarrayIntrinsicExpression type args",
1600 Self::could_map(Self::p_expr, &c.varray_intrinsic_members, env)?,
1603 DarrayIntrinsicExpression(c) => {
1604 let hints = Self::expand_type_args(&c.darray_intrinsic_explicit_type, env)?;
1605 let hints = Self::check_intrinsic_type_arg_varity(node, env, hints);
1607 Some(aast::CollectionTarg::CollectionTKV(tk, tv)) => Ok(E_::mk_darray(
1609 Self::could_map(Self::p_member, &c.darray_intrinsic_members, env)?,
1611 None => Ok(E_::mk_darray(
1613 Self::could_map(Self::p_member, &c.darray_intrinsic_members, env)?,
1616 Self::missing_syntax(None, "DarrayIntrinsicExpression type args", node, env)
1620 ArrayIntrinsicExpression(c) => {
1621 /* TODO: Or tie in with other intrinsics and post-process to Array */
1622 Ok(E_::Array(Self::could_map(
1624 &c.array_intrinsic_members,
1628 ArrayCreationExpression(c) => {
1629 /* TODO: Or tie in with other intrinsics and post-process to Array */
1630 Ok(E_::Array(Self::could_map(
1632 &c.array_creation_members,
1636 ListExpression(c) => {
1637 /* TODO: Or tie in with other intrinsics and post-process to List */
1638 let p_binder_or_ignore = |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(Expr<,>) {
1640 Missing => Ok(E::new(e.mk_none_pos(), E_::Omitted)),
1641 _ => Self::p_expr(n, e),
1644 Ok(E_::List(Self::could_map(
1645 &p_binder_or_ignore,
1650 EvalExpression(c) => p_special_call(&c.eval_keyword, &c.eval_argument, env),
1651 IssetExpression(c) => p_special_call(&c.isset_keyword, &c.isset_argument_list, env),
1652 TupleExpression(c) => {
1653 p_special_call(&c.tuple_expression_keyword, &c.tuple_expression_items, env)
1655 FunctionCallExpression(c) => {
1656 let recv = &c.function_call_receiver;
1657 let args = &c.function_call_argument_list;
1658 let get_hhas_adata = || {
1659 if Self::text_str(recv, env) == "__hhas_adata" {
1660 if let SyntaxList(l) = &args.syntax {
1661 if let Some(li) = l.first() {
1662 if let ListItem(i) = &li.syntax {
1663 if let LiteralExpression(le) = &i.list_item.syntax {
1664 let expr = &le.literal_expression;
1665 if Self::token_kind(expr) == Some(TK::NowdocStringLiteral) {
1675 match get_hhas_adata() {
1677 let literal_expression_pos = Self::p_pos(expr, env);
1678 let s = extract_unquoted_string(Self::text_str(expr, env), 0, expr.width())
1679 .map_err(|e| Error::Failwith(e.msg))?;
1681 aast::CallType::Cnormal,
1682 Self::p_expr(recv, env)?,
1684 vec![E::new(literal_expression_pos, E_::String(s))],
1689 let targs = match (&recv.syntax, &c.function_call_type_args.syntax) {
1690 (_, TypeArguments(c)) => {
1691 Self::could_map(Self::p_targ, &c.type_arguments_types, env)?
1693 /* TODO might not be needed */
1694 (GenericTypeSpecifier(c), _) => match &c.generic_argument_list.syntax {
1695 TypeArguments(c) => {
1696 Self::could_map(Self::p_targ, &c.type_arguments_types, env)?
1703 /* preserve parens on receiver of call expression
1704 to allow distinguishing between
1705 ($a->b)() // invoke on callable property
1706 $a->b() // method call */
1707 let pos_if_has_parens = match &recv.syntax {
1708 ParenthesizedExpression(_) => Some(Self::p_pos(recv, env)),
1711 let recv = Self::p_expr(recv, env)?;
1712 let recv = match (&recv.1, pos_if_has_parens) {
1713 (E_::ObjGet(_), Some(p)) => E::new(p, E_::mk_parenthesized_expr(recv)),
1714 (E_::ClassGet(_), Some(p)) => {
1715 E::new(p, E_::mk_parenthesized_expr(recv))
1719 let (args, varargs) = split_args_varargs(args, env)?;
1721 aast::CallType::Cnormal,
1730 QualifiedName(_) => {
1731 if location.in_string() {
1732 let ast_defs::Id(_, n) = Self::pos_qualified_name(node, env)?;
1735 Ok(E_::mk_id(Self::pos_qualified_name(node, env)?))
1738 VariableExpression(c) => Ok(E_::mk_lvar(Self::lid_from_pos_name(
1740 &c.variable_expression,
1743 PipeVariableExpression(_) => Ok(E_::mk_lvar(mk_lid(pos, String::from("$$")))),
1744 InclusionExpression(c) => Ok(E_::mk_import(
1745 Self::p_import_flavor(&c.inclusion_require, env)?,
1746 Self::p_expr(&c.inclusion_filename, env)?,
1748 MemberSelectionExpression(c) => {
1749 p_obj_get(&c.member_object, &c.member_operator, &c.member_name, env)
1751 SafeMemberSelectionExpression(c) => p_obj_get(
1752 &c.safe_member_object,
1753 &c.safe_member_operator,
1754 &c.safe_member_name,
1757 EmbeddedMemberSelectionExpression(c) => p_obj_get(
1758 &c.embedded_member_object,
1759 &c.embedded_member_operator,
1760 &c.embedded_member_name,
1763 PrefixUnaryExpression(_) | PostfixUnaryExpression(_) | DecoratedExpression(_) => {
1764 let (operand, op, postfix) = match &node.syntax {
1765 PrefixUnaryExpression(c) => {
1766 (&c.prefix_unary_operand, &c.prefix_unary_operator, false)
1768 PostfixUnaryExpression(c) => {
1769 (&c.postfix_unary_operand, &c.postfix_unary_operator, true)
1771 DecoratedExpression(c) => (
1772 &c.decorated_expression_expression,
1773 &c.decorated_expression_decorator,
1776 _ => Self::missing_syntax(None, "unary exppr", node, env)?,
1779 let expr = Self::p_expr(operand, env)?;
1781 * FFP does not destinguish between ++$i and $i++ on the level of token
1782 * kind annotation. Prevent duplication by switching on `postfix` for
1783 * the two operatores for which AST /does/ differentiate between
1786 use ast_defs::Uop::*;
1787 let mk_unop = |op, e| Ok(E_::mk_unop(op, e));
1788 match Self::token_kind(op) {
1789 Some(TK::PlusPlus) if postfix => mk_unop(Upincr, expr),
1790 Some(TK::MinusMinus) if postfix => mk_unop(Updecr, expr),
1791 Some(TK::PlusPlus) => mk_unop(Uincr, expr),
1792 Some(TK::MinusMinus) => mk_unop(Udecr, expr),
1793 Some(TK::Exclamation) => mk_unop(Unot, expr),
1794 Some(TK::Tilde) => mk_unop(Utild, expr),
1795 Some(TK::Plus) => mk_unop(Uplus, expr),
1796 Some(TK::Minus) => mk_unop(Uminus, expr),
1798 if env.parser_options.po_disallow_silence {
1799 Self::raise_parsing_error(op, env, &syntax_error::no_silence);
1802 mk_unop(Usilence, expr)
1805 Self::p_expr_impl(ExprLocation::TopLevel, operand, env, Some(pos))?;
1809 Some(TK::Inout) => Ok(E_::mk_callconv(ast_defs::ParamKind::Pinout, expr)),
1810 Some(TK::Await) => Self::lift_await(pos, expr, env, location),
1811 Some(TK::Suspend) => Ok(E_::mk_suspend(expr)),
1812 Some(TK::Clone) => Ok(E_::mk_clone(expr)),
1813 Some(TK::Print) => Ok(E_::mk_call(
1814 aast::CallType::Cnormal,
1817 E_::mk_id(ast_defs::Id(pos, String::from("echo"))),
1823 Some(TK::Dollar) => {
1824 let E(p, expr_) = expr;
1826 E_::String(s) | E_::Int(s) | E_::Float(s) => {
1828 Self::raise_parsing_error(
1831 &syntax_error::invalid_variable_name,
1834 let id = String::with_capacity(1 + s.len()) + "$" + &s;
1835 let lid = aast::Lid(pos, (0, id));
1836 Ok(E_::mk_lvar(lid))
1839 Self::raise_parsing_error(
1842 &syntax_error::invalid_variable_variable,
1848 _ => Self::missing_syntax(None, "unary operator", node, env),
1851 BinaryExpression(c) => {
1852 use ExprLocation::*;
1853 let rlocation = if Self::token_kind(&c.binary_operator) == Some(TK::Equal) {
1855 AsStatement => RightOfAssignment,
1856 UsingStatement => RightOfAssignmentInUsingStatement,
1862 // Ocaml evaluates right first then left, ordering will affect
1863 // tmp var count in lifted await statement.
1864 let right = Self::p_expr_with_loc(rlocation, &c.binary_right_operand, env)?;
1865 let left = Self::p_expr(&c.binary_left_operand, env)?;
1866 let bop_ast_node = Self::p_bop(pos, &c.binary_operator, left, right, env)?;
1867 if let E_::Binop(bop) = &bop_ast_node {
1868 if let (ast_defs::Bop::Eq(_), lhs, _) = bop.as_ref() {
1869 Self::check_lvalue(lhs, env);
1875 use ExprLocation::*;
1876 match (location, t.kind()) {
1877 (MemberSelect, TK::Variable) => mk_lvar(node, env),
1878 (InDoubleQuotedString, _) => Ok(E_::String(Self::wrap_unescaper(
1880 Self::text_str(node, env),
1882 (InBacktickedString, _) => Ok(E_::String(Self::wrap_unescaper(
1884 Self::text_str(node, env),
1889 | (UsingStatement, _)
1890 | (RightOfAssignment, _)
1891 | (RightOfAssignmentInUsingStatement, _)
1892 | (RightOfReturn, _) => Ok(E_::mk_id(Self::pos_name(node, env)?)),
1895 YieldExpression(c) => {
1896 use ExprLocation::*;
1897 env.saw_yield = true;
1898 if location != AsStatement
1899 && location != RightOfAssignment
1900 && location != RightOfAssignmentInUsingStatement
1902 Self::raise_parsing_error(node, env, &syntax_error::invalid_yield);
1904 if c.yield_operand.text(env.source_text()) == "break" {
1906 } else if c.yield_operand.is_missing() {
1907 Ok(E_::mk_yield(aast::Afield::AFvalue(E::new(pos, E_::Null))))
1909 Ok(E_::mk_yield(Self::p_afield(&c.yield_operand, env)?))
1912 YieldFromExpression(c) => {
1913 use ExprLocation::*;
1914 env.saw_yield = true;
1915 if location != AsStatement
1916 && location != RightOfAssignment
1917 && location != RightOfAssignmentInUsingStatement
1918 && location != RightOfReturn
1920 Self::raise_parsing_error(node, env, &syntax_error::invalid_yield_from);
1922 Ok(E_::mk_yield_from(Self::p_expr(&c.yield_from_operand, env)?))
1924 DefineExpression(c) => {
1925 let name = Self::pos_name(&c.define_keyword, env)?;
1927 aast_defs::CallType::Cnormal,
1930 Self::as_list(&c.define_argument_list)
1932 .map(|x| Self::p_expr(x, env))
1933 .collect::<std::result::Result<Vec<_>, _>>()?,
1937 ScopeResolutionExpression(c) => {
1938 let qual = Self::p_expr(&c.scope_resolution_qualifier, env)?;
1939 let qual = if env.codegen() {
1941 } else if let E_::Lvar(a) = qual.1 {
1943 E::new(pos.clone(), E_::mk_id(ast_defs::Id(pos, (a.1).1)))
1947 if let E_::Id(id) = &qual.1 {
1948 Self::fail_if_invalid_reified_generic(node, env, &id.1);
1950 match &c.scope_resolution_name.syntax {
1951 Token(token) if token.kind() == TK::Variable => {
1952 let ast_defs::Id(p, name) = Self::pos_name(&c.scope_resolution_name, env)?;
1953 Ok(E_::mk_class_get(
1954 aast::ClassId(pos, aast::ClassId_::CIexpr(qual)),
1955 aast::ClassGetExpr::CGstring((p, name)),
1959 let E(p, expr_) = Self::p_expr(&c.scope_resolution_name, env)?;
1961 E_::String(id) => Ok(E_::mk_class_const(
1962 aast::ClassId(pos, aast::ClassId_::CIexpr(qual)),
1966 let ast_defs::Id(p, n) = *id;
1967 Ok(E_::mk_class_const(
1968 aast::ClassId(pos, aast::ClassId_::CIexpr(qual)),
1973 let aast::Lid(p, (_, n)) = *id;
1974 Ok(E_::mk_class_get(
1975 aast::ClassId(pos, aast::ClassId_::CIexpr(qual)),
1976 aast::ClassGetExpr::CGstring((p, n)),
1979 _ => Ok(E_::mk_class_get(
1980 aast::ClassId(pos, aast::ClassId_::CIexpr(qual)),
1981 aast::ClassGetExpr::CGexpr(E(p, expr_)),
1987 CastExpression(c) => Ok(E_::mk_cast(
1988 Self::p_hint(&c.cast_type, env)?,
1989 Self::p_expr(&c.cast_operand, env)?,
1991 ConditionalExpression(c) => {
1992 let alter = Self::p_expr(&c.conditional_alternative, env)?;
1993 let consequence = Self::mp_optional(Self::p_expr, &c.conditional_consequence, env)?;
1994 let condition = Self::p_expr(&c.conditional_test, env)?;
1995 Ok(E_::mk_eif(condition, consequence, alter))
1997 SubscriptExpression(c) => Ok(E_::mk_array_get(
1998 Self::p_expr(&c.subscript_receiver, env)?,
1999 Self::mp_optional(Self::p_expr, &c.subscript_index, env)?,
2001 EmbeddedSubscriptExpression(c) => Ok(E_::mk_array_get(
2002 Self::p_expr(&c.embedded_subscript_receiver, env)?,
2004 |n, e| Self::p_expr_with_loc(location, n, e),
2005 &c.embedded_subscript_index,
2009 ShapeExpression(c) => Ok(E_::Shape(Self::could_map(
2010 |n: &Syntax<T, V>, e: &mut Env| {
2011 Self::mp_shape_expression_field(&Self::p_expr, n, e)
2013 &c.shape_expression_fields,
2016 ObjectCreationExpression(c) => {
2017 Self::p_expr_impl_(location, &c.object_creation_object, env, Some(pos))
2019 ConstructorCall(c) => {
2020 let (args, varargs) = split_args_varargs(&c.constructor_call_argument_list, env)?;
2021 let (e, hl) = match &c.constructor_call_type.syntax {
2022 GenericTypeSpecifier(c) => {
2023 let name = Self::pos_name(&c.generic_class_type, env)?;
2024 let hints = match &c.generic_argument_list.syntax {
2025 TypeArguments(c) => {
2026 Self::could_map(Self::p_targ, &c.type_arguments_types, env)?
2028 _ => Self::missing_syntax(
2030 "generic type arguments",
2031 &c.generic_argument_list,
2035 (mk_id_expr(name), hints)
2037 SimpleTypeSpecifier(_) => {
2038 let name = Self::pos_name(&c.constructor_call_type, env)?;
2039 (mk_id_expr(name), vec![])
2041 _ => (Self::p_expr(&c.constructor_call_type, env)?, vec![]),
2043 if let E_::Id(name) = &e.1 {
2044 Self::fail_if_invalid_reified_generic(node, env, &name.1);
2045 Self::fail_if_invalid_class_creation(node, env, &name.1);
2048 aast::ClassId(pos.clone(), aast::ClassId_::CIexpr(e)),
2055 GenericTypeSpecifier(c) => {
2056 if !c.generic_argument_list.is_missing() {
2057 Self::raise_parsing_error(
2058 &c.generic_argument_list,
2060 &syntax_error::targs_not_allowed,
2063 let name = Self::pos_name(&c.generic_class_type, env)?;
2066 RecordCreationExpression(c) => {
2067 let id = Self::pos_name(&c.record_creation_type, env)?;
2068 let is_record_array =
2069 Self::token_kind(&c.record_creation_array_token) == Some(TK::At);
2073 Self::could_map(Self::p_member, &c.record_creation_members, env)?,
2076 LiteralExpression(c) => Self::p_expr_lit(location, node, &c.literal_expression, env),
2077 PrefixedStringExpression(c) => {
2078 /* Temporarily allow only`re`- prefixed strings */
2079 let name_text = Self::text(&c.prefixed_string_name, env);
2080 if name_text != "re" {
2081 Self::raise_parsing_error(node, env, &syntax_error::non_re_prefix);
2083 Ok(E_::mk_prefixed_string(
2085 Self::p_expr(&c.prefixed_string_str, env)?,
2088 IsExpression(c) => Ok(E_::mk_is(
2089 Self::p_expr(&c.is_left_operand, env)?,
2090 Self::p_hint(&c.is_right_operand, env)?,
2092 AsExpression(c) => Ok(E_::mk_as(
2093 Self::p_expr(&c.as_left_operand, env)?,
2094 Self::p_hint(&c.as_right_operand, env)?,
2097 NullableAsExpression(c) => Ok(E_::mk_as(
2098 Self::p_expr(&c.nullable_as_left_operand, env)?,
2099 Self::p_hint(&c.nullable_as_right_operand, env)?,
2102 AnonymousFunction(c) => {
2103 if env.parser_options.po_disable_static_closures
2104 && Self::token_kind(&c.anonymous_static_keyword) == Some(TK::Static)
2106 Self::raise_parsing_error(
2109 &syntax_error::static_closures_are_disabled,
2112 let p_arg = |n: &Syntax<T, V>, e: &mut Env| match &n.syntax {
2113 Token(_) => mk_name_lid(n, e),
2114 _ => Self::missing_syntax(None, "use variable", n, e),
2116 let p_use = |n: &Syntax<T, V>, e: &mut Env| match &n.syntax {
2117 AnonymousFunctionUseClause(c) => {
2118 Self::could_map(p_arg, &c.anonymous_use_variables, e)
2122 let suspension_kind = Self::mk_suspension_kind(
2125 &c.anonymous_async_keyword,
2126 &c.anonymous_coroutine_keyword,
2128 let (body, yield_) = {
2129 let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
2130 Self::mp_yielding(&Self::p_function_body, &c.anonymous_body, env1.as_mut())?
2133 Self::extract_docblock(node, env).or_else(|| env.top_docblock().clone());
2134 let user_attributes = Self::p_user_attributes(&c.anonymous_attribute_spec, env)?;
2135 let external = c.anonymous_body.is_external();
2136 let params = Self::could_map(Self::p_fun_param, &c.anonymous_parameters, env)?;
2137 let name_pos = Self::p_function(node, env);
2138 let fun = aast::Fun_ {
2139 span: Self::p_pos(node, env),
2141 mode: Self::mode_annotation(env.file_mode()),
2142 ret: aast::TypeHint(
2144 Self::mp_optional(Self::p_hint, &c.anonymous_type, env)?,
2146 name: ast_defs::Id(name_pos, String::from(";anonymous")),
2148 where_constraints: vec![],
2149 body: aast::FuncBody {
2153 fun_kind: Self::mk_fun_kind(suspension_kind, yield_),
2154 variadic: Self::determine_variadicity(¶ms),
2157 file_attributes: vec![],
2159 namespace: Self::mk_empty_ns_env(env),
2161 static_: !c.anonymous_static_keyword.is_missing(),
2163 let uses = p_use(&c.anonymous_use, env).unwrap_or_else(|_| vec![]);
2164 Ok(E_::mk_efun(fun, uses))
2166 AwaitableCreationExpression(c) => {
2167 let suspension_kind =
2168 Self::mk_suspension_kind(node, env, &c.awaitable_async, &c.awaitable_coroutine);
2169 let (blk, yld) = Self::mp_yielding(
2170 &Self::p_function_body,
2171 &c.awaitable_compound_statement,
2174 let user_attributes = Self::p_user_attributes(&c.awaitable_attribute_spec, env)?;
2175 let external = c.awaitable_compound_statement.is_external();
2176 let name_pos = Self::p_function(node, env);
2177 let body = aast::Fun_ {
2180 mode: Self::mode_annotation(env.file_mode()),
2181 ret: aast::TypeHint((), None),
2182 name: ast_defs::Id(name_pos, String::from(";anonymous")),
2184 where_constraints: vec![],
2185 body: aast::FuncBody {
2186 ast: if blk.len() == 0 {
2187 let pos = Self::p_pos(&c.awaitable_compound_statement, env);
2188 vec![aast::Stmt::noop(pos)]
2194 fun_kind: Self::mk_fun_kind(suspension_kind, yld),
2195 variadic: Self::determine_variadicity(&[]),
2198 file_attributes: vec![],
2200 namespace: Self::mk_empty_ns_env(env),
2205 aast::CallType::Cnormal,
2206 E::new(pos, E_::mk_lfun(body, vec![])),
2212 XHPExpression(c) if c.xhp_open.is_xhp_open() => {
2213 if let XHPOpen(c1) = &c.xhp_open.syntax {
2214 let name = Self::pos_name(&c1.xhp_open_name, env)?;
2215 let attrs = Self::could_map(Self::p_xhp_attr, &c1.xhp_open_attributes, env)?;
2216 let exprs = Self::aggregate_xhp_tokens(&c.xhp_body)?
2219 Either::Left(n) => Self::p_xhp_embedded(Self::unesc_xhp, &n, env),
2220 Either::Right(n) => Self::p_xhp_embedded(Self::unesc_xhp, n, env),
2222 .collect::<std::result::Result<Vec<_>, _>>()?;
2225 // TODO: update pos_name to support prefix
2226 ast_defs::Id(name.0, String::from(":") + &name.1),
2231 Self::failwith("expect xhp open")
2234 PocketAtomExpression(c) => Ok(E_::PUAtom(
2235 Self::pos_name(&c.pocket_atom_expression, env)?.1,
2237 PocketIdentifierExpression(c) => {
2238 let mk_class_id = |e: aast!(Expr<,>)| aast::ClassId(pos, aast::ClassId_::CIexpr(e));
2239 let qual = Self::p_expr(&c.pocket_identifier_qualifier, env)?;
2240 let qual = if env.codegen() {
2242 } else if let E_::Lvar(a) = qual.1 {
2244 let expr = E::new(p.clone(), E_::mk_id(ast_defs::Id(p, (a.1).1)));
2249 let E(p, expr_) = Self::p_expr(&c.pocket_identifier_field, env)?;
2250 let field = match expr_ {
2251 E_::String(id) => (p, id),
2253 let ast_defs::Id(p, n) = *id;
2256 _ => Self::missing_syntax(None, "PocketIdentifierExpression field", node, env)?,
2258 let E(p, expr_) = Self::p_expr(&c.pocket_identifier_name, env)?;
2259 let name = match expr_ {
2260 E_::String(id) => (p, id),
2262 let ast_defs::Id(p, n) = *id;
2265 _ => Self::missing_syntax(None, "PocketIdentifierExpression name", node, env)?,
2267 Ok(E_::mk_puidentifier(qual, field, name))
2269 _ => Self::missing_syntax(Some(E_::Null), "expression", node, env),
2273 fn check_lvalue(aast::Expr(p, expr_): &aast!(Expr<,>), env: &mut Env) {
2275 let mut raise = |s| Self::raise_parsing_error_pos(p, env, s);
2277 ObjGet(og) => match og.as_ref() {
2278 (_, aast::Expr(_, Id(_)), ast_defs::OgNullFlavor::OGNullsafe) => {
2279 raise("?-> syntax is not supported for lvalues")
2281 (_, aast::Expr(_, Id(sid)), _) if sid.1.as_bytes()[0] == b':' => {
2282 raise("->: syntax is not supported for lvalues")
2287 if let ClassConst(_) = (ag.0).1 {
2288 raise("Array-like class consts are not valid lvalues");
2291 Call(c) => match &(c.1).1 {
2292 Id(sid) if sid.1 == "tuple" => {
2293 raise("Tuple cannot be used as an lvalue. Maybe you meant list?")
2295 _ => raise("Invalid lvalue"),
2299 Self::check_lvalue(i, env);
2302 Array(_) | Darray(_) | Varray(_) | Shape(_) | Collection(_) | Record(_) | Null
2303 | True | False | Id(_) | Clone(_) | ClassConst(_) | Int(_) | Float(_)
2304 | PrefixedString(_) | String(_) | String2(_) | Yield(_) | YieldBreak | YieldFrom(_)
2305 | Await(_) | Suspend(_) | ExprList(_) | Cast(_) | Unop(_) | Binop(_) | Eif(_)
2306 | New(_) | Efun(_) | Lfun(_) | Xml(_) | Import(_) | Pipe(_) | Callconv(_) | Is(_)
2307 | As(_) | ParenthesizedExpr(_) | PUIdentifier(_) => raise("Invalid lvalue"),
2312 fn p_xhp_embedded<F>(escaper: F, node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Expr<,>)
2314 F: FnOnce(&[u8]) -> Vec<u8>,
2316 if let Some(kind) = Self::token_kind(node) {
2317 if env.codegen() && TK::XHPStringLiteral == kind {
2318 let p = Self::p_pos(node, env);
2319 /* for XHP string literals (attribute values) just extract
2320 value from quotes and decode HTML entities */
2321 let text = html_entities::decode(&Self::get_quoted_content(
2322 node.full_text(env.source_text()),
2324 Ok(aast::Expr::new(p, E_::make_string(text)))
2325 } else if env.codegen() && TK::XHPBody == kind {
2326 let p = Self::p_pos(node, env);
2327 /* for XHP body - only decode HTML entities */
2329 html_entities::decode(&Self::unesc_xhp(node.full_text(env.source_text())));
2330 Ok(aast::Expr::new(p, E_::make_string(text)))
2332 let p = Self::p_pos(node, env);
2333 let s = escaper(node.full_text(env.source_text()));
2334 Ok(aast::Expr::new(p, E_::make_string(s)))
2337 let expr = Self::p_expr(node, env)?;
2339 E_::BracedExpr(e) => Ok(*e),
2345 fn p_xhp_attr(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(XhpAttribute<,>) {
2346 match &node.syntax {
2347 XHPSimpleAttribute(c) => {
2348 let attr_expr = &c.xhp_simple_attribute_expression;
2349 let name = Self::p_pstring(&c.xhp_simple_attribute_name, env)?;
2350 let expr = if attr_expr.is_braced_expression()
2351 && env.file_mode() == file_info::Mode::Mdecl
2354 aast::Expr::new(env.mk_none_pos(), E_::Null)
2356 Self::p_xhp_embedded(Self::unesc_xhp_attr, attr_expr, env)?
2358 Ok(aast::XhpAttribute::XhpSimple(name, expr))
2360 XHPSpreadAttribute(c) => {
2362 Self::p_xhp_embedded(Self::unesc_xhp, &c.xhp_spread_attribute_expression, env)?;
2363 Ok(aast::XhpAttribute::XhpSpread(expr))
2365 _ => Self::missing_syntax(None, "XHP attribute", node, env),
2369 fn aggregate_xhp_tokens<'b>(
2370 nodes: &'b Syntax<T, V>,
2371 ) -> ret!(Vec<Either<Syntax<T, V>, &'b Syntax<T, V>>>) {
2372 let nodes = Self::as_list(nodes);
2373 let mut state = (None, None, vec![]); // (start, end, result)
2374 let combine = |state: &mut (
2375 Option<&'b Syntax<T, V>>,
2376 Option<&'b Syntax<T, V>>,
2377 Vec<Either<Syntax<T, V>, &'b Syntax<T, V>>>,
2379 match (state.0, state.1) {
2380 (Some(s), None) => state.2.push(Right(s)),
2381 (Some(s), Some(e)) => {
2382 let token = T::concatenate(s.get_token().unwrap(), e.get_token().unwrap())
2383 .map_err(Error::Failwith)?;
2384 let node = <Syntax<T, V>>::make_token(token);
2385 state.2.push(Left(node))
2395 Token(t) if t.kind() == TK::XHPComment => {
2396 if state.0.is_some() {
2397 combine(&mut state)?;
2401 if state.0.is_none() {
2408 combine(&mut state)?;
2409 state.2.push(Right(n));
2413 combine(&mut state)?;
2419 node: &Syntax<T, V>,
2420 lhs: aast!(Expr<,>),
2421 rhs: aast!(Expr<,>),
2423 ) -> ret_aast!(Expr_<,>) {
2424 use ast_defs::Bop::*;
2425 let mk = |op, l, r| Ok(E_::mk_binop(op, l, r));
2426 let mk_eq = |op, l, r| Ok(E_::mk_binop(Eq(Some(Box::new(op))), l, r));
2427 match Self::token_kind(node) {
2428 Some(TK::Equal) => mk(Eq(None), lhs, rhs),
2429 Some(TK::Bar) => mk(Bar, lhs, rhs),
2430 Some(TK::Ampersand) => mk(Amp, lhs, rhs),
2431 Some(TK::Plus) => mk(Plus, lhs, rhs),
2432 Some(TK::Minus) => mk(Minus, lhs, rhs),
2433 Some(TK::Star) => mk(Star, lhs, rhs),
2434 Some(TK::Carat) => mk(Xor, lhs, rhs),
2435 Some(TK::Slash) => mk(Slash, lhs, rhs),
2436 Some(TK::Dot) => mk(Dot, lhs, rhs),
2437 Some(TK::Percent) => mk(Percent, lhs, rhs),
2438 Some(TK::LessThan) => mk(Lt, lhs, rhs),
2439 Some(TK::GreaterThan) => mk(Gt, lhs, rhs),
2440 Some(TK::EqualEqual) => mk(Eqeq, lhs, rhs),
2441 Some(TK::LessThanEqual) => mk(Lte, lhs, rhs),
2442 Some(TK::GreaterThanEqual) => mk(Gte, lhs, rhs),
2443 Some(TK::StarStar) => mk(Starstar, lhs, rhs),
2444 Some(TK::ExclamationEqual) => mk(Diff, lhs, rhs),
2445 Some(TK::BarEqual) => mk_eq(Bar, lhs, rhs),
2446 Some(TK::PlusEqual) => mk_eq(Plus, lhs, rhs),
2447 Some(TK::MinusEqual) => mk_eq(Minus, lhs, rhs),
2448 Some(TK::StarEqual) => mk_eq(Star, lhs, rhs),
2449 Some(TK::StarStarEqual) => mk_eq(Starstar, lhs, rhs),
2450 Some(TK::SlashEqual) => mk_eq(Slash, lhs, rhs),
2451 Some(TK::DotEqual) => mk_eq(Dot, lhs, rhs),
2452 Some(TK::PercentEqual) => mk_eq(Percent, lhs, rhs),
2453 Some(TK::CaratEqual) => mk_eq(Xor, lhs, rhs),
2454 Some(TK::AmpersandEqual) => mk_eq(Amp, lhs, rhs),
2455 Some(TK::BarBar) => mk(Barbar, lhs, rhs),
2456 Some(TK::AmpersandAmpersand) => mk(Ampamp, lhs, rhs),
2457 Some(TK::LessThanLessThan) => mk(Ltlt, lhs, rhs),
2458 Some(TK::GreaterThanGreaterThan) => mk(Gtgt, lhs, rhs),
2459 Some(TK::EqualEqualEqual) => mk(Eqeqeq, lhs, rhs),
2460 Some(TK::LessThanLessThanEqual) => mk_eq(Ltlt, lhs, rhs),
2461 Some(TK::GreaterThanGreaterThanEqual) => mk_eq(Gtgt, lhs, rhs),
2462 Some(TK::ExclamationEqualEqual) => mk(Diff2, lhs, rhs),
2463 Some(TK::LessThanEqualGreaterThan) => mk(Cmp, lhs, rhs),
2464 Some(TK::QuestionQuestion) => mk(QuestionQuestion, lhs, rhs),
2465 Some(TK::QuestionQuestionEqual) => mk_eq(QuestionQuestion, lhs, rhs),
2466 /* The ugly duckling; In the FFP, `|>` is parsed as a
2467 * `BinaryOperator`, whereas the typed AST has separate constructors for
2468 * Pipe and Binop. This is why we don't just project onto a
2469 * `bop`, but a `expr -> expr -> expr_`.
2471 Some(TK::BarGreaterThan) => {
2472 let lid = aast::Lid::from_counter(
2474 env.next_local_id(),
2475 special_idents::DOLLAR_DOLLAR,
2477 Ok(E_::mk_pipe(lid, lhs, rhs))
2479 Some(TK::QuestionColon) => Ok(E_::mk_eif(lhs, None, rhs)),
2480 _ => Self::missing_syntax(None, "binary operator", node, env),
2484 fn is_noop(stmt: &aast!(Stmt<,>)) -> bool {
2485 if let aast::Stmt_::Noop = stmt.1 {
2494 mut nodes: Iter<&Syntax<T, V>>,
2496 ) -> ret!(Vec<aast!(Stmt<,>)>) {
2499 match nodes.next() {
2500 Some(n) => match &n.syntax {
2501 UsingStatementFunctionScoped(c) => {
2502 let body = Self::p_stmt_list_(pos, nodes, env)?;
2503 let f = |e: &mut Env| {
2506 aast::Stmt_::mk_using(aast::UsingStmt {
2507 is_block_scoped: false,
2508 has_await: !c.using_function_await_keyword.is_missing(),
2509 expr: Self::p_expr_l_with_loc(
2510 ExprLocation::UsingStatement,
2511 &c.using_function_expression,
2518 let using = Self::lift_awaits_in_statement_(f, Either::Right(pos), env)?;
2523 r.push(Self::p_stmt(n, env)?);
2531 // TODO: rename to p_stmt_list
2532 fn handle_loop_body(pos: Pos, node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Stmt<,>) {
2533 let list = Self::as_list(node);
2534 let blk: Vec<_> = Self::p_stmt_list_(&pos, list.iter(), env)?
2536 .filter(|stmt| !Self::is_noop(stmt))
2538 let body = if blk.len() == 0 {
2539 vec![Self::mk_noop(env)]
2543 Ok(aast::Stmt::new(pos, aast::Stmt_::mk_block(body)))
2546 fn is_simple_assignment_await_expression(node: &Syntax<T, V>) -> bool {
2547 match &node.syntax {
2548 BinaryExpression(c) => {
2549 Self::token_kind(&c.binary_operator) == Some(TK::Equal)
2550 && Self::is_simple_await_expression(&c.binary_right_operand)
2556 fn is_simple_await_expression(node: &Syntax<T, V>) -> bool {
2557 match &node.syntax {
2558 PrefixUnaryExpression(c) => {
2559 Self::token_kind(&c.prefix_unary_operator) == Some(TK::Await)
2565 fn with_new_nonconcurrent_scrope<F, R>(f: F, env: &mut Env) -> R
2567 F: FnOnce(&mut Env) -> R,
2569 let saved_lifted_awaits = env.lifted_awaits.take();
2570 let result = f(env);
2571 env.lifted_awaits = saved_lifted_awaits;
2575 fn with_new_concurrent_scrope<F, R>(f: F, env: &mut Env) -> ret!((LiftedAwaitExprs, R))
2577 F: FnOnce(&mut Env) -> ret!(R),
2579 let saved_lifted_awaits = env.lifted_awaits.replace(LiftedAwaits {
2581 lift_kind: LiftedAwaitKind::LiftedFromConcurrent,
2583 let result = f(env);
2584 let lifted_awaits = mem::replace(&mut env.lifted_awaits, saved_lifted_awaits);
2585 let result = result?;
2586 let awaits = match lifted_awaits {
2587 Some(la) => Self::process_lifted_awaits(la, env)?,
2588 None => Self::failwith("lifted awaits should not be None")?,
2590 Ok((awaits, result))
2593 fn process_lifted_awaits(mut awaits: LiftedAwaits, env: &Env) -> ret!(LiftedAwaitExprs) {
2594 for await_ in awaits.awaits.iter() {
2595 if (await_.1).0.is_none() {
2596 return Self::failwith("none pos in lifted awaits");
2601 .sort_unstable_by(|a1, a2| Pos::compare(&(a1.1).0, &(a2.1).0));
2605 fn clear_statement_scope<F, R>(f: F, env: &mut Env) -> R
2607 F: FnOnce(&mut Env) -> R,
2609 use LiftedAwaitKind::*;
2610 match &env.lifted_awaits {
2611 Some(LiftedAwaits { lift_kind, .. }) if *lift_kind == LiftedFromStatement => {
2612 let saved_lifted_awaits = env.lifted_awaits.take();
2613 let result = f(env);
2614 env.lifted_awaits = saved_lifted_awaits;
2621 fn lift_awaits_in_statement<F>(f: F, node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Stmt<,>)
2623 F: FnOnce(&mut Env) -> ret_aast!(Stmt<,>),
2625 Self::lift_awaits_in_statement_(f, Either::Left(node), env)
2628 fn lift_awaits_in_statement_<F>(
2630 pos: Either<&Syntax<T, V>, &Pos>,
2632 ) -> ret_aast!(Stmt<,>)
2634 F: FnOnce(&mut Env) -> ret_aast!(Stmt<,>),
2636 use LiftedAwaitKind::*;
2637 let (lifted_awaits, result) = match env.lifted_awaits {
2638 Some(LiftedAwaits { lift_kind, .. }) if lift_kind == LiftedFromConcurrent => {
2642 let saved = env.lifted_awaits.replace(LiftedAwaits {
2644 lift_kind: LiftedFromStatement,
2646 let result = f(env);
2647 let lifted_awaits = mem::replace(&mut env.lifted_awaits, saved);
2648 let result = result?;
2649 (lifted_awaits, result)
2652 if let Some(lifted_awaits) = lifted_awaits {
2653 if !lifted_awaits.awaits.is_empty() {
2654 let awaits = Self::process_lifted_awaits(lifted_awaits, env)?;
2655 let pos = match pos {
2656 Either::Left(n) => Self::p_pos(n, env),
2657 Either::Right(p) => p.clone(),
2659 return Ok(aast::Stmt::new(
2661 aast::Stmt_::mk_awaitall(awaits, vec![result]),
2670 expr: aast!(Expr<,>),
2672 location: ExprLocation,
2673 ) -> ret_aast!(Expr_<,>) {
2674 use ExprLocation::*;
2675 match (&env.lifted_awaits, location) {
2676 (_, UsingStatement) | (_, RightOfAssignmentInUsingStatement) | (None, _) => {
2677 Ok(E_::mk_await(expr))
2680 if location != AsStatement {
2681 let name = env.make_tmp_var_name();
2682 let lid = aast::Lid::new(parent_pos, name.clone());
2683 let await_lid = aast::Lid::new(expr.0.clone(), name);
2684 let await_ = (Some(await_lid), expr);
2685 env.lifted_awaits.as_mut().map(|aw| aw.awaits.push(await_));
2686 Ok(E_::mk_lvar(lid))
2690 .map(|aw| aw.awaits.push((None, expr)));
2697 fn p_stmt(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Stmt<,>) {
2698 Self::clear_statement_scope(
2700 let docblock = Self::extract_docblock(node, e);
2701 e.push_docblock(docblock);
2702 let result = Self::p_stmt_(node, e);
2710 fn p_stmt_(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Stmt<,>) {
2711 let pos = Self::p_pos(node, env);
2712 use aast::{Stmt as S, Stmt_ as S_};
2713 match &node.syntax {
2714 SwitchStatement(c) => {
2715 let p_label = |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(Case<,>) {
2717 CaseLabel(c) => Ok(aast::Case::Case(
2718 Self::p_expr(&c.case_expression, e)?,
2721 DefaultLabel(_) => Ok(aast::Case::Default(Self::p_pos(n, e), vec![])),
2722 _ => Self::missing_syntax(None, "switch label", n, e),
2725 let p_section = |n: &Syntax<T, V>, e: &mut Env| -> ret!(Vec<aast!(Case<,>)>) {
2727 SwitchSection(c) => {
2729 Self::could_map(Self::p_stmt, &c.switch_section_statements, e)?;
2730 if !c.switch_section_fallthrough.is_missing() {
2731 blk.push(S::new(e.mk_none_pos(), S_::Fallthrough));
2733 let mut labels = Self::could_map(p_label, &c.switch_section_labels, e)?;
2734 match labels.last_mut() {
2735 Some(aast::Case::Default(_, b)) => *b = blk,
2736 Some(aast::Case::Case(_, b)) => *b = blk,
2737 _ => Self::raise_parsing_error(n, e, "Malformed block result"),
2741 _ => Self::missing_syntax(None, "switch section", n, e),
2744 let f = |env: &mut Env| -> ret_aast!(Stmt<,>) {
2748 Self::p_expr(&c.switch_expression, env)?,
2749 itertools::concat(Self::could_map(p_section, &c.switch_sections, env)?),
2753 Self::lift_awaits_in_statement(f, node, env)
2757 |n: &Syntax<T, V>, e: &mut Env| -> ret!((aast!(Expr<,>), aast!(Block<,>))) {
2759 ElseifClause(c) => Ok((
2760 Self::p_expr(&c.elseif_condition, e)?,
2761 Self::p_block(true, &c.elseif_statement, e)?,
2763 _ => Self::missing_syntax(None, "elseif clause", n, e),
2766 let f = |env: &mut Env| -> ret_aast!(Stmt<,>) {
2767 let condition = Self::p_expr(&c.if_condition, env)?;
2769 Self::p_block(true /* remove noop */, &c.if_statement, env)?;
2770 let else_ = match &c.if_else_clause.syntax {
2771 ElseClause(c) => Self::p_block(true, &c.else_statement, env)?,
2772 Missing => vec![Self::mk_noop(env)],
2773 _ => Self::missing_syntax(None, "else clause", &c.if_else_clause, env)?,
2775 let else_ifs = Self::could_map(p_else_if, &c.if_elseif_clauses, env)?;
2776 let else_if = else_ifs
2779 .fold(else_, |child, (cond, stmts)| {
2780 vec![S::new(pos.clone(), S_::mk_if(cond, stmts, child))]
2782 Ok(S::new(pos, S_::mk_if(condition, statement, else_if)))
2784 Self::lift_awaits_in_statement(f, node, env)
2786 ExpressionStatement(c) => {
2787 let expr = &c.expression_statement_expression;
2788 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2789 if expr.is_missing() {
2790 Ok(S::new(pos, S_::Noop))
2794 S_::mk_expr(Self::p_expr_with_loc(ExprLocation::AsStatement, expr, e)?),
2798 if Self::is_simple_assignment_await_expression(expr)
2799 || Self::is_simple_await_expression(expr)
2803 Self::lift_awaits_in_statement(f, node, env)
2806 CompoundStatement(c) => Self::handle_loop_body(pos, &c.compound_statements, env),
2807 SyntaxList(_) => Self::handle_loop_body(pos, node, env),
2808 ThrowStatement(c) => Self::lift_awaits_in_statement(
2809 |e: &mut Env| -> ret_aast!(Stmt<,>) {
2812 S_::mk_throw(Self::p_expr(&c.throw_expression, e)?),
2818 DoStatement(c) => Ok(S::new(
2821 Self::p_block(false /* remove noop */, &c.do_body, env)?,
2822 Self::p_expr(&c.do_condition, env)?,
2825 WhileStatement(c) => Ok(S::new(
2828 Self::p_expr(&c.while_condition, env)?,
2829 Self::p_block(true, &c.while_body, env)?,
2832 UsingStatementBlockScoped(c) => {
2833 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2836 S_::mk_using(aast::UsingStmt {
2837 is_block_scoped: true,
2838 has_await: !&c.using_block_await_keyword.is_missing(),
2839 expr: Self::p_expr_l_with_loc(
2840 ExprLocation::UsingStatement,
2841 &c.using_block_expressions,
2844 block: Self::p_block(false, &c.using_block_body, e)?,
2848 Self::lift_awaits_in_statement(f, node, env)
2850 UsingStatementFunctionScoped(c) => {
2851 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2854 S_::mk_using(aast::UsingStmt {
2855 is_block_scoped: false,
2856 has_await: !&c.using_function_await_keyword.is_missing(),
2857 expr: Self::p_expr_l_with_loc(
2858 ExprLocation::UsingStatement,
2859 &c.using_function_expression,
2862 block: vec![Self::mk_noop(e)],
2866 Self::lift_awaits_in_statement(f, node, env)
2868 LetStatement(c) => {
2869 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2870 let id = Self::lid_from_pos_name(pos.clone(), &c.let_statement_name, e)?;
2871 let ty = Self::mp_optional(Self::p_hint, &c.let_statement_type, e)?;
2872 let expr = Self::p_simple_initializer(&c.let_statement_initializer, e)?;
2873 Ok(S::new(pos, S_::mk_let(id, ty, expr)))
2875 Self::lift_awaits_in_statement(f, node, env)
2877 ForStatement(c) => {
2878 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2879 let ini = Self::p_expr_l(&c.for_initializer, e)?;
2880 let ctr = Self::p_expr_l(&c.for_control, e)?;
2881 let eol = Self::p_expr_l(&c.for_end_of_loop, e)?;
2882 let blk = Self::p_block(true, &c.for_body, e)?;
2883 Ok(S::new(pos, S_::mk_for(ini, ctr, eol, blk)))
2885 Self::lift_awaits_in_statement(f, node, env)
2887 ForeachStatement(c) => {
2888 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2889 let col = Self::p_expr(&c.foreach_collection, e)?;
2890 let akw = match Self::token_kind(&c.foreach_await_keyword) {
2891 Some(TK::Await) => Some(Self::p_pos(&c.foreach_await_keyword, e)),
2894 let value = Self::p_expr(&c.foreach_value, e)?;
2895 let akv = match (akw, &c.foreach_key.syntax) {
2896 (Some(p), Missing) => aast::AsExpr::AwaitAsV(p, value),
2897 (None, Missing) => aast::AsExpr::AsV(value),
2899 aast::AsExpr::AwaitAsKv(p, Self::p_expr(&c.foreach_key, e)?, value)
2901 (None, _) => aast::AsExpr::AsKv(Self::p_expr(&c.foreach_key, e)?, value),
2903 let blk = Self::p_block(true, &c.foreach_body, e)?;
2904 Ok(S::new(pos, S_::mk_foreach(col, akv, blk)))
2906 Self::lift_awaits_in_statement(f, node, env)
2908 TryStatement(c) => Ok(S::new(
2911 Self::p_block(false, &c.try_compound_statement, env)?,
2913 |n: &Syntax<T, V>, e| match &n.syntax {
2914 CatchClause(c) => Ok(aast::Catch(
2915 Self::pos_name(&c.catch_type, e)?,
2916 Self::lid_from_name(&c.catch_variable, e)?,
2917 Self::p_block(true, &c.catch_body, e)?,
2919 _ => Self::missing_syntax(None, "catch clause", n, e),
2921 &c.try_catch_clauses,
2924 match &c.try_finally_clause.syntax {
2925 FinallyClause(c) => Self::p_block(false, &c.finally_body, env)?,
2930 ReturnStatement(c) => {
2931 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2932 let expr = match &c.return_expression.syntax {
2934 _ => Some(Self::p_expr_with_loc(
2935 ExprLocation::RightOfReturn,
2936 &c.return_expression,
2940 Ok(aast::Stmt::new(pos, aast::Stmt_::mk_return(expr)))
2942 if Self::is_simple_await_expression(&c.return_expression) {
2945 Self::lift_awaits_in_statement(f, node, env)
2949 if env.is_typechecker() && !env.parser_options.po_allow_goto {
2950 Self::raise_parsing_error(node, env, &syntax_error::goto_label);
2955 Self::p_pos(&c.goto_label_name, env),
2956 Self::text(&c.goto_label_name, env),
2960 GotoStatement(c) => {
2961 if env.is_typechecker() && !env.parser_options.po_allow_goto {
2962 Self::raise_parsing_error(node, env, &syntax_error::goto_label);
2966 S_::mk_goto(Self::p_pstring(&c.goto_statement_label_name, env)?),
2969 EchoStatement(c) => {
2970 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2971 let echo = match &c.echo_keyword.syntax {
2972 QualifiedName(_) | SimpleTypeSpecifier(_) | Token(_) => {
2973 let name = Self::pos_name(&c.echo_keyword, e)?;
2974 aast::Expr::new(name.0.clone(), E_::mk_id(name))
2976 _ => Self::missing_syntax(None, "id", &c.echo_keyword, e)?,
2978 let args = Self::could_map(Self::p_expr, &c.echo_expressions, e)?;
2981 S_::mk_expr(aast::Expr::new(
2983 E_::mk_call(aast::CallType::Cnormal, echo, vec![], args, vec![]),
2987 Self::lift_awaits_in_statement(f, node, env)
2989 UnsetStatement(c) => {
2990 let f = |e: &mut Env| -> ret_aast!(Stmt<,>) {
2991 let args = Self::could_map(Self::p_expr, &c.unset_variables, e)?;
2992 if e.parser_options.po_disable_unset_class_const {
2994 .for_each(|arg| Self::check_mutate_class_const(arg, node, e))
2996 let unset = match &c.unset_keyword.syntax {
2997 QualifiedName(_) | SimpleTypeSpecifier(_) | Token(_) => {
2998 let name = Self::pos_name(&c.unset_keyword, e)?;
2999 aast::Expr::new(name.0.clone(), E_::mk_id(name))
3001 _ => Self::missing_syntax(None, "id", &c.unset_keyword, e)?,
3005 S_::mk_expr(aast::Expr::new(
3007 E_::mk_call(aast::CallType::Cnormal, unset, vec![], args, vec![]),
3011 Self::lift_awaits_in_statement(f, node, env)
3013 BreakStatement(_) => Ok(S::new(pos, S_::Break)),
3014 ContinueStatement(_) => Ok(S::new(pos, S_::Continue)),
3015 ConcurrentStatement(c) => {
3016 let (lifted_awaits, S(stmt_pos, stmt)) = Self::with_new_concurrent_scrope(
3017 |e: &mut Env| Self::p_stmt(&c.concurrent_statement, e),
3020 let stmt = match stmt {
3021 S_::Block(stmts) => {
3022 use aast::Expr as E;
3023 use ast_defs::Bop::Eq;
3024 /* Reuse tmp vars from lifted_awaits, this is safe because there will
3025 * always be more awaits with tmp vars than statements with assignments */
3026 let mut tmp_vars = lifted_awaits
3028 .filter_map(|lifted_await| lifted_await.0.as_ref().map(|x| &x.1));
3029 let mut body_stmts = vec![];
3030 let mut assign_stmts = vec![];
3031 for n in stmts.into_iter() {
3032 if !n.is_assign_expr() {
3037 if let Some(tv) = tmp_vars.next() {
3038 if let S(p1, S_::Expr(expr)) = n {
3039 if let E(p2, E_::Binop(bop)) = *expr {
3040 if let (Eq(op), e1, e2) = *bop {
3041 let tmp_n = E::mk_lvar(&e2.0, &(tv.1));
3042 if tmp_n.lvar_name() != e2.lvar_name() {
3054 body_stmts.push(new_n);
3056 let assign_stmt = S::new(
3060 E_::mk_binop(Eq(op), e1, tmp_n),
3063 assign_stmts.push(assign_stmt);
3069 Self::failwith("Expect assignment stmt")?;
3071 Self::raise_parsing_error_pos(
3074 &syntax_error::statement_without_await_in_concurrent_block,
3079 body_stmts.append(&mut assign_stmts);
3080 S::new(stmt_pos, S_::mk_block(body_stmts))
3082 _ => Self::failwith("Unexpected concurrent stmt structure")?,
3084 Ok(S::new(pos, S_::mk_awaitall(lifted_awaits, vec![stmt])))
3086 MarkupSection(_) => Self::p_markup(node, env),
3087 _ => Self::missing_syntax(
3088 Some(S::new(env.mk_none_pos(), S_::Noop)),
3096 fn check_mutate_class_const(e: &aast!(Expr<,>), node: &Syntax<T, V>, env: &mut Env) {
3098 E_::ArrayGet(c) if c.1.is_some() => Self::check_mutate_class_const(&c.0, node, env),
3099 E_::ClassConst(_) => {
3100 Self::raise_parsing_error(node, env, &syntax_error::const_mutation)
3106 fn is_hashbang(node: &Syntax<T, V>, env: &Env) -> bool {
3107 let text = Self::text_str(node, env);
3109 static ref RE: regex::Regex = regex::Regex::new("^#!.*\n").unwrap();
3111 text.lines().nth(1).is_none() && // only one line
3115 fn p_markup(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Stmt<,>) {
3116 match &node.syntax {
3117 MarkupSection(c) => {
3118 let markup_prefix = &c.markup_prefix;
3119 let markup_text = &c.markup_text;
3120 let markup_expression = &c.markup_expression;
3121 let pos = Self::p_pos(node, env);
3122 let has_dot_hack_extension = pos.filename().has_extension("hack");
3123 if has_dot_hack_extension {
3124 Self::raise_parsing_error(node, env, &syntax_error::error1060);
3125 } else if markup_prefix.value.is_missing()
3126 && markup_text.width() > 0
3127 && !Self::is_hashbang(&markup_text, env)
3129 Self::raise_parsing_error(node, env, &syntax_error::error1001);
3131 let expr = match &markup_expression.syntax {
3133 ExpressionStatement(e) => {
3134 Some(Self::p_expr(&e.expression_statement_expression, env)?)
3136 _ => Self::failwith("expression expected")?,
3139 aast::Stmt_::mk_markup((pos.clone(), Self::text(&markup_text, env)), expr);
3140 Ok(aast::Stmt::new(pos, stmt_))
3142 _ => Self::failwith("invalid node"),
3146 fn p_modifiers<F: Fn(R, modifier::Kind) -> R, R>(
3149 node: &Syntax<T, V>,
3151 ) -> ret!((modifier::KindSet, R)) {
3152 let nodes = Self::as_list(node);
3153 let mut kind_set = modifier::KindSet::new();
3154 for n in nodes.iter() {
3155 let token_kind = Self::token_kind(n).map_or(None, modifier::from_token_kind);
3159 init = on_kind(init, kind);
3161 _ => Self::missing_syntax(None, "kind", n, env)?,
3164 Ok((kind_set, init))
3167 fn p_kinds(node: &Syntax<T, V>, env: &mut Env) -> ret!(modifier::KindSet) {
3168 Self::p_modifiers(|_, _| {}, (), node, env).map(|r| r.0)
3171 // TODO: change name to map_flatten after porting
3173 fn could_map<R, F>(f: F, node: &Syntax<T, V>, env: &mut Env) -> ret!(Vec<R>)
3175 F: Fn(&Syntax<T, V>, &mut Env) -> ret!(R),
3177 Self::map_flatten_(f, node, env, vec![])
3181 fn map_flatten_<R, F>(f: F, node: &Syntax<T, V>, env: &mut Env, acc: Vec<R>) -> ret!(Vec<R>)
3183 F: Fn(&Syntax<T, V>, &mut Env) -> ret!(R),
3185 let op = |mut v: Vec<R>, a| {
3189 Self::map_fold(&f, &op, node, env, acc)
3192 fn map_fold<A, R, F, O>(f: &F, op: &O, node: &Syntax<T, V>, env: &mut Env, acc: A) -> ret!(A)
3194 F: Fn(&Syntax<T, V>, &mut Env) -> ret!(R),
3197 match &node.syntax {
3201 for x in xs.iter() {
3202 a = Self::map_fold(f, op, &x, env, a)?;
3206 ListItem(x) => Ok(op(acc, f(&x.list_item, env)?)),
3207 _ => Ok(op(acc, f(node, env)?)),
3211 fn p_visibility(node: &Syntax<T, V>, env: &mut Env) -> ret!(Option<aast!(Visibility)>) {
3213 |r: Option<aast!(Visibility)>, kind| r.or_else(|| modifier::to_visibility(kind));
3214 Self::p_modifiers(first_vis, None, node, env).map(|r| r.1)
3218 node: &Syntax<T, V>,
3220 default: aast!(Visibility),
3221 ) -> ret_aast!(Visibility) {
3222 Self::p_visibility(node, env).map(|v| v.unwrap_or(default))
3225 fn p_visibility_last_win(
3226 node: &Syntax<T, V>,
3228 ) -> ret!(Option<aast!(Visibility)>) {
3229 let last_vis = |r, kind| modifier::to_visibility(kind).or(r);
3230 Self::p_modifiers(last_vis, None, node, env).map(|r| r.1)
3233 fn p_visibility_last_win_or(
3234 node: &Syntax<T, V>,
3236 default: aast!(Visibility),
3237 ) -> ret_aast!(Visibility) {
3238 Self::p_visibility_last_win(node, env).map(|v| v.unwrap_or(default))
3241 fn has_soft(attrs: &[aast!(UserAttribute<,>)]) -> bool {
3242 attrs.iter().any(|attr| attr.name.1 == "__Soft")
3245 fn soften_hint(attrs: &[aast!(UserAttribute<,>)], hint: aast!(Hint)) -> aast!(Hint) {
3246 if Self::has_soft(attrs) {
3247 aast::Hint::new(hint.0.clone(), aast::Hint_::Hsoft(hint))
3253 fn p_fun_param_default_value(
3254 node: &Syntax<T, V>,
3256 ) -> ret!(Option<aast!(Expr<,>)>) {
3257 match &node.syntax {
3258 SimpleInitializer(c) => {
3259 Self::mp_optional(Self::p_expr, &c.simple_initializer_value, env)
3265 fn p_param_kind(node: &Syntax<T, V>, env: &mut Env) -> ret!(ast_defs::ParamKind) {
3266 match Self::token_kind(node) {
3267 Some(TK::Inout) => Ok(ast_defs::ParamKind::Pinout),
3268 _ => Self::missing_syntax(None, "param kind", node, env),
3272 fn param_template(node: &Syntax<T, V>, env: &Env) -> aast!(FunParam<,>) {
3273 let pos = Self::p_pos(node, env);
3275 annotation: pos.clone(),
3276 type_hint: aast::TypeHint((), None),
3277 is_reference: false,
3280 name: Self::text(node, env),
3283 user_attributes: vec![],
3288 fn p_fun_param(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(FunParam<,>) {
3289 match &node.syntax {
3290 ParameterDeclaration(c) => {
3291 let parameter_attribute = &c.parameter_attribute;
3292 let parameter_visibility = &c.parameter_visibility;
3293 let parameter_call_convention = &c.parameter_call_convention;
3294 let parameter_type = &c.parameter_type;
3295 let parameter_name = &c.parameter_name;
3296 let parameter_default_value = &c.parameter_default_value;
3297 let (is_reference, is_variadic, name) = match ¶meter_name.syntax {
3298 DecoratedExpression(c) => {
3299 let decorated_expression_decorator = &c.decorated_expression_decorator;
3300 let decorated_expression_expression = &c.decorated_expression_expression;
3301 let decorator = Self::text_str(decorated_expression_decorator, env);
3302 match &decorated_expression_expression.syntax {
3303 DecoratedExpression(c) => {
3304 let nested_expression = &c.decorated_expression_expression;
3305 let nested_decorator =
3306 Self::text_str(&c.decorated_expression_decorator, env);
3308 decorator == "&" || nested_decorator == "&",
3309 decorator == "..." || nested_decorator == "...",
3316 decorated_expression_expression,
3320 _ => (false, false, parameter_name),
3322 let user_attributes = Self::p_user_attributes(¶meter_attribute, env)?;
3323 let hint = Self::mp_optional(Self::p_hint, parameter_type, env)?
3324 .map(|h| Self::soften_hint(&user_attributes, h));
3325 if is_variadic && !user_attributes.is_empty() {
3326 Self::raise_parsing_error(
3329 &syntax_error::no_attributes_on_variadic_parameter,
3332 let pos = Self::p_pos(name, env);
3334 annotation: pos.clone(),
3335 type_hint: aast::TypeHint((), hint),
3340 name: Self::text(name, env),
3341 expr: Self::p_fun_param_default_value(parameter_default_value, env)?,
3342 callconv: Self::mp_optional(
3344 parameter_call_convention,
3347 /* implicit field via constructor parameter.
3348 * This is always None except for constructors and the modifier
3349 * can be only Public or Protected or Private.
3351 visibility: Self::p_visibility(parameter_visibility, env)?,
3354 VariadicParameter(_) => {
3355 let mut param = Self::param_template(node, env);
3356 param.is_variadic = true;
3359 Token(_) if Self::text_str(node, env) == "..." => {
3360 let mut param = Self::param_template(node, env);
3361 param.is_variadic = true;
3364 _ => Self::missing_syntax(None, "function parameter", node, env),
3368 fn p_tconstraint_ty(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Hint) {
3369 match &node.syntax {
3370 TypeConstraint(c) => Self::p_hint(&c.constraint_type, env),
3371 _ => Self::missing_syntax(None, "type constraint", node, env),
3376 node: &Syntax<T, V>,
3378 ) -> ret!((ast_defs::ConstraintKind, aast!(Hint))) {
3379 match &node.syntax {
3380 TypeConstraint(c) => Ok((
3381 match Self::token_kind(&c.constraint_keyword) {
3382 Some(TK::As) => ast_defs::ConstraintKind::ConstraintAs,
3383 Some(TK::Super) => ast_defs::ConstraintKind::ConstraintSuper,
3384 Some(TK::Equal) => ast_defs::ConstraintKind::ConstraintEq,
3385 _ => Self::missing_syntax(
3387 "constraint operator",
3388 &c.constraint_keyword,
3392 Self::p_hint(&c.constraint_type, env)?,
3394 _ => Self::missing_syntax(None, "type constraint", node, env),
3398 fn p_tparam(is_class: bool, node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Tparam<,>) {
3399 match &node.syntax {
3400 TypeParameter(c) => {
3401 let user_attributes = Self::p_user_attributes(&c.type_attribute_spec, env)?;
3402 let is_reified = !&c.type_reified.is_missing();
3403 if is_class && is_reified {
3404 let type_name = Self::text(&c.type_name, env);
3405 env.cls_reified_generics().insert(type_name);
3407 let variance = match Self::token_kind(&c.type_variance) {
3408 Some(TK::Plus) => ast_defs::Variance::Covariant,
3409 Some(TK::Minus) => ast_defs::Variance::Contravariant,
3410 _ => ast_defs::Variance::Invariant,
3412 if is_reified && variance != ast_defs::Variance::Invariant {
3413 Self::raise_parsing_error(
3416 &syntax_error::non_invariant_reified_generic,
3419 let reified = match (is_reified, Self::has_soft(&user_attributes)) {
3420 (true, true) => aast::ReifyKind::SoftReified,
3421 (true, false) => aast::ReifyKind::Reified,
3422 _ => aast::ReifyKind::Erased,
3426 name: Self::pos_name(&c.type_name, env)?,
3427 constraints: Self::could_map(Self::p_tconstraint, &c.type_constraints, env)?,
3432 _ => Self::missing_syntax(None, "type parameter", node, env),
3438 node: &Syntax<T, V>,
3440 ) -> ret!(Vec<aast!(Tparam<,>)>) {
3441 match &node.syntax {
3442 Missing => Ok(vec![]),
3443 TypeParameters(c) => Self::could_map(
3444 |n, e| Self::p_tparam(is_class, n, e),
3445 &c.type_parameters_parameters,
3448 _ => Self::missing_syntax(None, "type parameter", node, env),
3452 fn p_fun_hdr(node: &Syntax<T, V>, env: &mut Env) -> ret!(FunHdr) {
3453 match &node.syntax {
3454 FunctionDeclarationHeader(c) => {
3455 let function_modifiers = &c.function_modifiers;
3456 let function_name = &c.function_name;
3457 let function_where_clause = &c.function_where_clause;
3458 let function_type_parameter_list = &c.function_type_parameter_list;
3459 let function_parameter_list = &c.function_parameter_list;
3460 let function_type = &c.function_type;
3461 let is_autoload = Self::text_str(function_name, env)
3462 .eq_ignore_ascii_case(special_functions::AUTOLOAD);
3463 if function_name.value.is_missing() {
3464 Self::raise_parsing_error(function_name, env, &syntax_error::empty_method_name);
3466 let num_params = Self::syntax_to_list(false, function_parameter_list).len();
3467 if is_autoload && num_params > 1 {
3468 Self::raise_parsing_error(
3471 &syntax_error::autoload_takes_one_argument,
3474 let kinds = Self::p_kinds(function_modifiers, env)?;
3475 let has_async = kinds.has(modifier::ASYNC);
3476 let has_coroutine = kinds.has(modifier::COROUTINE);
3477 let parameters = Self::could_map(Self::p_fun_param, function_parameter_list, env)?;
3478 let return_type = Self::mp_optional(Self::p_hint, function_type, env)?;
3479 let suspension_kind =
3480 Self::mk_suspension_kind_(node, env, has_async, has_coroutine);
3481 let name = Self::pos_name(function_name, env)?;
3482 let constrs = Self::p_where_constraint(false, node, function_where_clause, env)?;
3483 let type_parameters = Self::p_tparam_l(false, function_type_parameter_list, env)?;
3493 LambdaSignature(c) => {
3494 let mut header = FunHdr::make_empty(env);
3495 header.parameters = Self::could_map(Self::p_fun_param, &c.lambda_parameters, env)?;
3496 header.return_type = Self::mp_optional(Self::p_hint, &c.lambda_type, env)?;
3499 Token(_) => Ok(FunHdr::make_empty(env)),
3500 _ => Self::missing_syntax(None, "function header", node, env),
3504 fn determine_variadicity(params: &[aast!(FunParam<,>)]) -> aast!(FunVariadicity<,>) {
3505 use aast::FunVariadicity::*;
3506 if let Some(x) = params.last() {
3507 match (x.is_variadic, &x.name) {
3508 (false, _) => FVnonVariadic,
3509 (true, name) if name == "..." => FVellipsis(x.pos.clone()),
3510 (true, _) => FVvariadicArg(x.clone()),
3517 // TODO: change name to p_fun_pos after porting.
3518 fn p_function(node: &Syntax<T, V>, env: &Env) -> Pos {
3519 let get_pos = |n: &Syntax<T, V>, p: Pos| -> Pos {
3520 if let FunctionDeclarationHeader(c1) = &n.syntax {
3521 if !c1.function_keyword.value.is_missing() {
3522 return Pos::btw_nocheck(Self::p_pos(n, env), p);
3527 let p = Self::p_pos(node, env);
3528 match &node.syntax {
3529 FunctionDeclaration(c) if env.codegen() => get_pos(&c.function_declaration_header, p),
3530 MethodishDeclaration(c) if env.codegen() => {
3531 get_pos(&c.methodish_function_decl_header, p)
3537 fn p_block(remove_noop: bool, node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Block<,>) {
3538 let aast::Stmt(p, stmt_) = Self::p_stmt(node, env)?;
3539 if let aast::Stmt_::Block(blk) = stmt_ {
3540 if remove_noop && blk.len() == 1 {
3541 if let aast::Stmt_::Noop = blk[0].1 {
3547 Ok(vec![aast::Stmt(p, stmt_)])
3551 fn mk_noop(env: &Env) -> aast!(Stmt<,>) {
3552 aast::Stmt::noop(env.mk_none_pos())
3555 fn p_function_body(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Block<,>) {
3556 let mk_noop_result = |e: &Env| Ok(vec![Self::mk_noop(e)]);
3557 let f = |e: &mut Env| -> ret_aast!(Block<,>) {
3558 match &node.syntax {
3559 Missing => Ok(vec![]),
3560 CompoundStatement(c) => {
3561 let compound_statements = &c.compound_statements.syntax;
3562 let compound_right_brace = &c.compound_right_brace.syntax;
3563 match (compound_statements, compound_right_brace) {
3564 (Missing, Token(_)) => mk_noop_result(e),
3565 (SyntaxList(t), _) if t.len() == 1 && t[0].is_yield() => {
3570 if !e.top_level_statements
3571 && ((e.file_mode() == file_info::Mode::Mdecl && !e.codegen())
3576 Self::p_block(false /*remove noop*/, node, e)
3582 let f = |e: &mut Env| {
3583 let expr = Self::p_expr(node, e)?;
3586 aast::Stmt_::mk_return(Some(expr)),
3589 Ok(vec![Self::lift_awaits_in_statement(f, node, e)?])
3593 Self::with_new_nonconcurrent_scrope(f, env)
3596 fn mk_suspension_kind(
3597 node: &Syntax<T, V>,
3599 async_keyword: &Syntax<T, V>,
3600 coroutine_keyword: &Syntax<T, V>,
3601 ) -> SuspensionKind {
3602 Self::mk_suspension_kind_(
3605 !async_keyword.is_missing(),
3606 !coroutine_keyword.is_missing(),
3610 fn mk_suspension_kind_(
3611 node: &Syntax<T, V>,
3614 has_coroutine: bool,
3615 ) -> SuspensionKind {
3616 use SuspensionKind::*;
3617 match (has_async, has_coroutine) {
3618 (false, false) => SKSync,
3619 (true, false) => SKAsync,
3620 (false, true) => SKCoroutine,
3622 Self::raise_parsing_error(node, env, "Coroutine functions may not be async");
3628 fn mk_fun_kind(suspension_kind: SuspensionKind, yield_: bool) -> ast_defs::FunKind {
3629 use ast_defs::FunKind::*;
3630 use SuspensionKind::*;
3631 match (suspension_kind, yield_) {
3632 (SKSync, true) => FGenerator,
3633 (SKAsync, true) => FAsyncGenerator,
3634 (SKSync, false) => FSync,
3635 (SKAsync, false) => FAsync,
3636 (SKCoroutine, _) => FCoroutine,
3640 fn process_attribute_constructor_call(
3641 node: &Syntax<T, V>,
3642 constructor_call_argument_list: &Syntax<T, V>,
3643 constructor_call_type: &Syntax<T, V>,
3645 ) -> ret_aast!(UserAttribute<,>) {
3646 let name = Self::pos_name(constructor_call_type, env)?;
3647 if name.1.eq_ignore_ascii_case("__reified")
3648 || name.1.eq_ignore_ascii_case("__hasreifiedparent")
3650 Self::raise_parsing_error(node, env, &syntax_error::reified_attribute);
3651 } else if name.1.eq_ignore_ascii_case("__soft")
3652 && Self::as_list(constructor_call_argument_list).len() > 0
3654 Self::raise_parsing_error(node, env, &syntax_error::soft_no_arguments);
3656 let params = Self::could_map(
3657 |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(Expr<,>) {
3658 if let ScopeResolutionExpression(c) = &n.syntax {
3659 if let Some(TK::Name) = Self::token_kind(&c.scope_resolution_name) {
3660 Self::raise_parsing_error(
3663 &syntax_error::constants_as_attribute_arguments,
3666 } else if let Some(TK::Name) = Self::token_kind(n) {
3667 Self::raise_parsing_error(
3670 &syntax_error::constants_as_attribute_arguments,
3675 constructor_call_argument_list,
3678 Ok(aast::UserAttribute { name, params })
3681 fn p_user_attribute(node: &Syntax<T, V>, env: &mut Env) -> ret!(Vec<aast!(UserAttribute<,>)>) {
3682 let p_attr = |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(UserAttribute<,>) {
3684 ConstructorCall(c) => Self::process_attribute_constructor_call(
3686 &c.constructor_call_argument_list,
3687 &c.constructor_call_type,
3690 _ => Self::missing_syntax(None, "attribute", node, e),
3693 match &node.syntax {
3694 FileAttributeSpecification(c) => {
3695 Self::could_map(p_attr, &c.file_attribute_specification_attributes, env)
3697 OldAttributeSpecification(c) => {
3698 Self::could_map(p_attr, &c.old_attribute_specification_attributes, env)
3700 AttributeSpecification(c) => Self::could_map(
3701 |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(UserAttribute<,>) {
3703 Attribute(c) => p_attr(&c.attribute_attribute_name, e),
3704 _ => Self::missing_syntax(None, "attribute", node, e),
3707 &c.attribute_specification_attributes,
3710 _ => Self::missing_syntax(None, "attribute specification", node, env),
3714 fn p_user_attributes(node: &Syntax<T, V>, env: &mut Env) -> ret!(Vec<aast!(UserAttribute<,>)>) {
3716 &Self::p_user_attribute,
3717 &|mut acc: Vec<aast!(UserAttribute<,>)>, mut x: Vec<aast!(UserAttribute<,>)>| {
3727 fn mp_yielding<F, R>(p: F, node: &Syntax<T, V>, env: &mut Env) -> ret!((R, bool))
3729 F: FnOnce(&Syntax<T, V>, &mut Env) -> ret!(R),
3731 let outer_saw_yield = env.saw_yield;
3732 env.saw_yield = false;
3733 let r = p(node, env);
3734 let saw_yield = env.saw_yield;
3735 env.saw_yield = outer_saw_yield;
3739 fn mk_empty_ns_env(env: &Env) -> RcOc<NamespaceEnv> {
3740 RcOc::clone(&env.empty_ns_env)
3743 fn extract_docblock(node: &Syntax<T, V>, env: &Env) -> Option<DocComment> {
3744 #[derive(Copy, Clone, Eq, PartialEq)]
3757 // `parse` mixes loop and recursion to use less stack space.
3758 fn parse(str: &str, start: usize, state: ScanState, idx: usize) -> Option<String> {
3759 let is_whitespace = |c| c == ' ' || c == '\t' || c == '\n' || c == '\r';
3760 let mut s = (start, state, idx);
3761 let chars = str.as_bytes();
3763 if s.2 == str.len() {
3768 match (s.1, chars[s.2] as char) {
3769 (LineCmt, '\n') => s = (next, Free, next),
3770 (EndEmbedded, '/') => s = (next, Free, next),
3772 let r = parse(str, next, Free, next);
3774 d @ Some(_) => break d,
3775 None => break Some(String::from(&str[s.0..s.2 + 1])),
3778 /* PHP has line comments delimited by a # */
3779 (Free, '#') => s = (next, LineCmt, next),
3780 /* All other comment delimiters start with a / */
3781 (Free, '/') => s = (s.2, SawSlash, next),
3782 /* After a / in trivia, we must see either another / or a * */
3783 (SawSlash, '/') => s = (next, LineCmt, next),
3784 (SawSlash, '*') => s = (s.0, MaybeDoc, next),
3785 (MaybeDoc, '*') => s = (s.0, MaybeDoc2, next),
3786 (MaybeDoc, _) => s = (s.0, EmbeddedCmt, next),
3787 (MaybeDoc2, '/') => s = (next, Free, next),
3788 /* Doc comments have a space after the second star */
3789 (MaybeDoc2, c) if is_whitespace(c) => s = (s.0, DocComment, s.2),
3790 (MaybeDoc2, _) => s = (s.0, EmbeddedCmt, next),
3791 (DocComment, '*') => s = (s.0, EndDoc, next),
3792 (DocComment, _) => s = (s.0, DocComment, next),
3793 (EndDoc, _) => s = (s.0, DocComment, next),
3794 /* A * without a / does not end an embedded comment */
3795 (EmbeddedCmt, '*') => s = (s.0, EndEmbedded, next),
3796 (EndEmbedded, '*') => s = (s.0, EndEmbedded, next),
3797 (EndEmbedded, _) => s = (s.0, EmbeddedCmt, next),
3798 /* Whitespace skips everywhere else */
3799 (_, c) if is_whitespace(c) => s = (s.0, s.1, next),
3800 /* When scanning comments, anything else is accepted */
3801 (LineCmt, _) => s = (s.0, s.1, next),
3802 (EmbeddedCmt, _) => s = (s.0, s.1, next),
3807 let str = node.leading_text(env.indexed_source_text.source_text());
3808 parse(str, 0, Free, 0).map(Rc::new)
3811 fn p_xhp_child(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(XhpChild) {
3812 use aast::XhpChild::*;
3813 use aast::XhpChildOp::*;
3814 match &node.syntax {
3815 Token(_) => Self::pos_name(node, env).map(ChildName),
3816 PostfixUnaryExpression(c) => {
3817 let operand = Self::p_xhp_child(&c.postfix_unary_operand, env)?;
3818 let operator = match Self::token_kind(&c.postfix_unary_operator) {
3819 Some(TK::Question) => ChildQuestion,
3820 Some(TK::Plus) => ChildPlus,
3821 Some(TK::Star) => ChildStar,
3822 _ => Self::missing_syntax(None, "xhp children operator", node, env)?,
3824 Ok(ChildUnary(Box::new(operand), operator))
3826 BinaryExpression(c) => {
3827 let left = Self::p_xhp_child(&c.binary_left_operand, env)?;
3828 let right = Self::p_xhp_child(&c.binary_right_operand, env)?;
3829 Ok(ChildBinary(Box::new(left), Box::new(right)))
3831 XHPChildrenParenthesizedList(c) => {
3832 let children = Self::as_list(&c.xhp_children_list_xhp_children);
3833 let children: std::result::Result<Vec<_>, _> =
3834 children.iter().map(|c| Self::p_xhp_child(c, env)).collect();
3835 Ok(ChildList(children?))
3837 _ => Self::missing_syntax(None, "xhp children", node, env),
3841 fn p_class_elt_(class: &mut aast!(Class_<,>), node: &Syntax<T, V>, env: &mut Env) -> ret!(()) {
3842 let doc_comment_opt = Self::extract_docblock(node, env);
3843 let has_fun_header = |m: &MethodishDeclarationChildren<T, V>| {
3844 if let FunctionDeclarationHeader(_) = m.methodish_function_decl_header.syntax {
3849 let has_fun_header_mtr = |m: &MethodishTraitResolutionChildren<T, V>| {
3850 if let FunctionDeclarationHeader(_) = m.methodish_trait_function_decl_header.syntax {
3855 let p_method_vis = |node: &Syntax<T, V>, env: &mut Env| -> ret_aast!(Visibility) {
3856 match Self::p_visibility_last_win(node, env)? {
3858 Self::raise_nast_error("method_needs_visiblity");
3859 Ok(aast::Visibility::Public)
3864 match &node.syntax {
3865 ConstDeclaration(c) => {
3866 // TODO: make wrap `type_` `doc_comment` by `Rc` in ClassConst to avoid clone
3867 let type_ = Self::mp_optional(Self::p_hint, &c.const_type_specifier, env)?;
3868 // using map_fold can save one Vec allocation, but ocaml's behavior is that
3869 // if anything throw, it will discard all lowered elements. So adding to class
3870 // must be at the last.
3871 let mut class_consts = Self::could_map(
3872 |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(ClassConst<,>) {
3874 ConstantDeclarator(c) => {
3875 let id = Self::pos_name(&c.constant_declarator_name, e)?;
3876 let expr = if n.is_abstract() {
3880 Self::p_simple_initializer,
3881 &c.constant_declarator_initializer,
3885 Ok(aast::ClassConst {
3886 type_: type_.clone(),
3889 doc_comment: doc_comment_opt.clone(),
3892 _ => Self::missing_syntax(None, "constant declarator", n, e),
3895 &c.const_declarators,
3898 Ok(class.consts.append(&mut class_consts))
3900 TypeConstDeclaration(c) => {
3901 if !c.type_const_type_parameters.is_missing() {
3902 Self::raise_parsing_error(node, env, &syntax_error::tparams_in_tconst);
3904 let user_attributes = Self::p_user_attributes(&c.type_const_attribute_spec, env)?;
3905 let type__ = Self::mp_optional(Self::p_hint, &c.type_const_type_specifier, env)?
3906 .map(|hint| Self::soften_hint(&user_attributes, hint));
3907 let kinds = Self::p_kinds(&c.type_const_modifiers, env)?;
3908 let name = Self::pos_name(&c.type_const_name, env)?;
3910 Self::mp_optional(Self::p_tconstraint_ty, &c.type_const_type_constraint, env)?;
3911 let span = Self::p_pos(node, env);
3912 let has_abstract = kinds.has(modifier::ABSTRACT);
3913 let (type_, abstract_kind) = match (has_abstract, &constraint, &type__) {
3914 (false, _, None) => {
3915 Self::raise_nast_error("not_abstract_without_typeconst");
3916 (constraint.clone(), aast::TypeconstAbstractKind::TCConcrete)
3918 (false, None, Some(_)) => (type__, aast::TypeconstAbstractKind::TCConcrete),
3919 (false, Some(_), Some(_)) => {
3920 (type__, aast::TypeconstAbstractKind::TCPartiallyAbstract)
3922 (true, _, None) => (
3924 aast::TypeconstAbstractKind::TCAbstract(type__),
3926 (true, _, Some(_)) => (None, aast::TypeconstAbstractKind::TCAbstract(type__)),
3928 Ok(class.typeconsts.push(aast::ClassTypeconst {
3929 abstract_: abstract_kind,
3935 doc_comment: doc_comment_opt,
3938 PropertyDeclaration(c) => {
3939 let user_attributes = Self::p_user_attributes(&c.property_attribute_spec, env)?;
3940 let type_ = Self::mp_optional(Self::p_hint, &c.property_type, env)?
3941 .map(|t| Self::soften_hint(&user_attributes, t));
3942 let kinds = Self::p_kinds(&c.property_modifiers, env)?;
3943 let vis = Self::p_visibility_last_win_or(
3944 &c.property_modifiers,
3946 aast::Visibility::Public,
3948 let doc_comment = if env.quick_mode {
3953 let name_exprs = Self::could_map(
3954 |n, e| -> ret!((Pos, aast!(Sid), Option<aast!(Expr<,>)>)) {
3956 PropertyDeclarator(c) => {
3957 let name = Self::pos_name_(&c.property_name, e, Some('$'))?;
3958 let pos = Self::p_pos(n, e);
3959 let expr = Self::mp_optional(
3960 Self::p_simple_initializer,
3961 &c.property_initializer,
3964 Ok((pos, name, expr))
3966 _ => Self::missing_syntax(None, "property declarator", n, e),
3969 &c.property_declarators,
3974 for name_expr in name_exprs.into_iter() {
3975 class.vars.push(aast::ClassVar {
3976 final_: kinds.has(modifier::FINAL),
3978 abstract_: kinds.has(modifier::ABSTRACT),
3980 type_: type_.clone(),
3983 user_attributes: user_attributes.clone(),
3984 doc_comment: if i == 0 { doc_comment.clone() } else { None },
3985 is_promoted_variadic: false,
3986 is_static: kinds.has(modifier::STATIC),
3993 MethodishDeclaration(c) if has_fun_header(c) => {
3995 |param: &aast!(FunParam<,>)| -> (aast!(Stmt<,>), aast!(ClassVar<,>)) {
3996 let cvname = Self::drop_prefix(¶m.name, '$');
3998 let span = match ¶m.expr {
3999 Some(aast::Expr(pos_end, _)) => {
4000 Pos::btw(p, pos_end).unwrap_or_else(|_| p.clone())
4004 let e = |expr_: aast!(Expr_<,>)| -> aast!(Expr<,>) {
4005 aast::Expr::new(p.clone(), expr_)
4008 |s: &str| -> aast!(Lid) { aast::Lid(p.clone(), (0, s.to_string())) };
4012 aast::Stmt_::mk_expr(e(E_::mk_binop(
4013 ast_defs::Bop::Eq(None),
4015 e(E_::mk_lvar(lid("$this"))),
4016 e(E_::mk_id(ast_defs::Id(p.clone(), cvname.to_string()))),
4017 aast::OgNullFlavor::OGNullthrows,
4019 e(E_::mk_lvar(lid(¶m.name))),
4026 visibility: param.visibility.unwrap(),
4027 type_: param.type_hint.1.clone(),
4028 id: ast_defs::Id(p.clone(), cvname.to_string()),
4030 user_attributes: param.user_attributes.clone(),
4032 is_promoted_variadic: param.is_variadic,
4038 let header = &c.methodish_function_decl_header;
4039 let h = match &header.syntax {
4040 FunctionDeclarationHeader(h) => h,
4043 let hdr = Self::p_fun_hdr(header, env)?;
4044 if hdr.name.1 == "__construct" && !hdr.type_parameters.is_empty() {
4045 Self::raise_parsing_error(
4048 &syntax_error::no_generics_on_constructors,
4051 let (mut member_init, mut member_def): (
4052 Vec<aast!(Stmt<,>)>,
4053 Vec<aast!(ClassVar<,>)>,
4057 .filter_map(|p| p.visibility.map(|_| classvar_init(p)))
4060 let kinds = Self::p_kinds(&h.function_modifiers, env)?;
4061 let visibility = p_method_vis(&h.function_modifiers, env)?;
4062 let is_static = kinds.has(modifier::STATIC);
4063 *env.in_static_method() = is_static;
4064 let (mut body, body_has_yield) =
4065 Self::mp_yielding(Self::p_function_body, &c.methodish_function_body, env)?;
4067 member_init.reverse();
4069 member_init.append(&mut body);
4070 let body = member_init;
4071 *env.in_static_method() = false;
4072 let is_abstract = kinds.has(modifier::ABSTRACT);
4073 let is_external = !is_abstract && c.methodish_function_body.is_external();
4074 let user_attributes = Self::p_user_attributes(&c.methodish_attribute, env)?;
4075 let method = aast::Method_ {
4076 span: Self::p_function(node, env),
4078 final_: kinds.has(modifier::FINAL),
4079 abstract_: is_abstract,
4083 tparams: hdr.type_parameters,
4084 where_constraints: hdr.constrs,
4085 variadic: Self::determine_variadicity(&hdr.parameters),
4086 params: hdr.parameters,
4087 body: aast::FuncBody {
4091 fun_kind: Self::mk_fun_kind(hdr.suspension_kind, body_has_yield),
4093 ret: aast::TypeHint((), hdr.return_type),
4094 external: is_external,
4095 doc_comment: doc_comment_opt,
4097 class.vars.append(&mut member_def);
4098 Ok(class.methods.push(method))
4100 MethodishTraitResolution(c) if has_fun_header_mtr(c) => {
4101 let header = &c.methodish_trait_function_decl_header;
4102 let h = match &header.syntax {
4103 FunctionDeclarationHeader(h) => h,
4106 let hdr = Self::p_fun_hdr(header, env)?;
4107 let kind = Self::p_kinds(&h.function_modifiers, env)?;
4108 let (qualifier, name) = match &c.methodish_trait_name.syntax {
4109 ScopeResolutionExpression(c) => (
4110 Self::p_hint(&c.scope_resolution_qualifier, env)?,
4111 Self::p_pstring(&c.scope_resolution_name, env)?,
4113 _ => Self::missing_syntax(None, "trait method redeclaration", node, env)?,
4115 let user_attributes = Self::p_user_attributes(&c.methodish_trait_attribute, env)?;
4116 let visibility = p_method_vis(&h.function_modifiers, env)?;
4117 let mtr = aast::MethodRedeclaration {
4118 final_: kind.has(modifier::FINAL),
4119 abstract_: kind.has(modifier::ABSTRACT),
4120 static_: kind.has(modifier::STATIC),
4123 tparams: hdr.type_parameters,
4124 where_constraints: hdr.constrs,
4125 variadic: Self::determine_variadicity(&hdr.parameters),
4126 params: hdr.parameters,
4127 fun_kind: Self::mk_fun_kind(hdr.suspension_kind, false),
4128 ret: aast::TypeHint((), hdr.return_type),
4133 class.method_redeclarations.push(mtr);
4136 TraitUseConflictResolution(c) => {
4137 type Ret = ret!(Either<aast!(InsteadofAlias), aast!(UseAsAlias)>);
4138 let p_item = |n: &Syntax<T, V>, e: &mut Env| -> Ret {
4140 TraitUsePrecedenceItem(c) => {
4141 let removed_names = &c.trait_use_precedence_item_removed_names;
4142 let (qualifier, name) = match &c.trait_use_precedence_item_name.syntax {
4143 ScopeResolutionExpression(c) => (
4144 Self::pos_name(&c.scope_resolution_qualifier, e)?,
4145 Self::p_pstring(&c.scope_resolution_name, e)?,
4147 _ => Self::missing_syntax(None, "trait use precedence item", n, e)?,
4149 let removed_names = Self::could_map(Self::pos_name, removed_names, e)?;
4150 Self::raise_nast_error("unsupported_instead_of");
4151 Ok(Either::Left(aast::InsteadofAlias(
4157 TraitUseAliasItem(c) => {
4158 let aliasing_name = &c.trait_use_alias_item_aliasing_name;
4159 let modifiers = &c.trait_use_alias_item_modifiers;
4160 let aliased_name = &c.trait_use_alias_item_aliased_name;
4161 let (qualifier, name) = match &aliasing_name.syntax {
4162 ScopeResolutionExpression(c) => (
4163 Some(Self::pos_name(&c.scope_resolution_qualifier, e)?),
4164 Self::p_pstring(&c.scope_resolution_name, e)?,
4166 _ => (None, Self::p_pstring(aliasing_name, e)?),
4168 let (kinds, mut vis_raw) = Self::p_modifiers(
4169 |mut acc, kind| -> Vec<aast_defs::UseAsVisibility> {
4170 if let Some(v) = modifier::to_use_as_visibility(kind) {
4179 let vis = if kinds.is_empty() || kinds.has_any(modifier::VISIBILITIES) {
4182 let mut v = vec![aast::UseAsVisibility::UseAsPublic];
4183 v.append(&mut vis_raw);
4186 let aliased_name = if !aliased_name.is_missing() {
4187 Some(Self::pos_name(aliased_name, e)?)
4191 Self::raise_nast_error("unsupported_trait_use_as");
4192 Ok(Either::Right(aast::UseAsAlias(
4199 _ => Self::missing_syntax(None, "trait use conflict resolution item", n, e),
4203 Self::could_map(Self::p_hint, &c.trait_use_conflict_resolution_names, env)?;
4204 let elts = Self::could_map(p_item, &c.trait_use_conflict_resolution_clauses, env)?;
4205 class.uses.append(&mut uses);
4206 for elt in elts.into_iter() {
4208 Either::Left(l) => class.insteadof_alias.push(l),
4209 Either::Right(r) => class.use_as_alias.push(r),
4215 let mut uses = Self::could_map(Self::p_hint, &c.trait_use_names, env)?;
4216 Ok(class.uses.append(&mut uses))
4218 RequireClause(c) => {
4219 let hint = Self::p_hint(&c.require_name, env)?;
4220 let is_extends = match Self::token_kind(&c.require_kind) {
4221 Some(TK::Implements) => false,
4222 Some(TK::Extends) => true,
4223 _ => Self::missing_syntax(None, "trait require kind", &c.require_kind, env)?,
4225 Ok(class.reqs.push((hint, is_extends)))
4227 XHPClassAttributeDeclaration(c) => {
4228 type Ret = ret!(Either<aast!(XhpAttr<,>), aast!(Hint)>);
4229 let p_attr = |node: &Syntax<T, V>, env: &mut Env| -> Ret {
4230 let mut mk_attr_use = |n: &Syntax<T, V>| {
4231 Ok(Either::Right(aast::Hint(
4232 Self::p_pos(n, env),
4233 Box::new(aast::Hint_::Happly(Self::pos_name(n, env)?, vec![])),
4236 match &node.syntax {
4237 XHPClassAttribute(c) => {
4238 let ty = &c.xhp_attribute_decl_type;
4239 let init = &c.xhp_attribute_decl_initializer;
4240 let ast_defs::Id(p, name) =
4241 Self::pos_name(&c.xhp_attribute_decl_name, env)?;
4243 TypeConstant(_) if env.is_typechecker() => {
4244 Self::raise_parsing_error(
4247 &syntax_error::xhp_class_attribute_type_constant,
4252 let req = match &c.xhp_attribute_decl_required.syntax {
4253 XHPRequired(_) => Some(aast::XhpAttrTag::Required),
4254 XHPLateinit(_) => Some(aast::XhpAttrTag::LateInit),
4257 let pos = if init.is_missing() {
4260 Pos::btw(&p, &Self::p_pos(init, env)).map_err(Error::Failwith)?
4262 let (hint, enum_) = match &ty.syntax {
4264 let p = Self::p_pos(ty, env);
4265 let opt = !(&c.xhp_enum_optional.is_missing());
4267 Self::could_map(Self::p_expr, &c.xhp_enum_values, env)?;
4268 (None, Some((p, opt, vals)))
4270 _ => (Some(Self::p_hint(ty, env)?), None),
4273 Self::mp_optional(Self::p_simple_initializer, init, env)?;
4274 let xhp_attr = aast::XhpAttr(
4278 xhp_attr: Some(aast::XhpAttrInfo { xai_tag: req }),
4280 visibility: aast::Visibility::Public,
4282 id: ast_defs::Id(p, String::from(":") + &name),
4284 user_attributes: vec![],
4286 is_promoted_variadic: false,
4293 Ok(Either::Left(xhp_attr))
4295 XHPSimpleClassAttribute(c) => {
4296 mk_attr_use(&c.xhp_simple_class_attribute_type)
4298 Token(_) => mk_attr_use(node),
4299 _ => Self::missing_syntax(None, "XHP attribute", node, env),
4302 let attrs = Self::could_map(p_attr, &c.xhp_attribute_attributes, env)?;
4303 for attr in attrs.into_iter() {
4305 Either::Left(attr) => class.xhp_attrs.push(attr),
4306 Either::Right(xhp_attr_use) => class.xhp_attr_uses.push(xhp_attr_use),
4311 XHPChildrenDeclaration(c) => {
4312 let p = Self::p_pos(node, env);
4315 .push((p, Self::p_xhp_child(&c.xhp_children_expression, env)?)))
4317 XHPCategoryDeclaration(c) => {
4318 let p = Self::p_pos(node, env);
4319 let categories = Self::could_map(
4320 |n, e| Self::p_pstring_(n, e, Some('%')),
4321 &c.xhp_category_categories,
4324 if let Some((_, cs)) = &class.xhp_category {
4326 Self::raise_nast_error("multiple_xhp_category")
4329 Ok(class.xhp_category = Some((p, categories)))
4331 PocketEnumDeclaration(c) => {
4332 let is_final = Self::p_kinds(&c.pocket_enum_modifiers, env)?.has(modifier::FINAL);
4333 let id = Self::pos_name(&c.pocket_enum_name, env)?;
4334 let flds = Self::as_list(&c.pocket_enum_fields);
4335 let mut case_types = vec![];
4336 let mut case_values = vec![];
4337 let mut members = vec![];
4338 for fld in flds.iter() {
4340 PocketAtomMappingDeclaration(c) => {
4341 let id = Self::pos_name(&c.pocket_atom_mapping_name, env)?;
4342 let maps = Self::as_list(&c.pocket_atom_mapping_mappings);
4343 let mut types = vec![];
4344 let mut exprs = vec![];
4345 for map in maps.iter() {
4347 PocketMappingIdDeclaration(c) => {
4348 let id = Self::pos_name(&c.pocket_mapping_id_name, env)?;
4349 let expr = Self::p_simple_initializer(
4350 &c.pocket_mapping_id_initializer,
4353 exprs.push((id, expr));
4355 PocketMappingTypeDeclaration(c) => {
4356 let id = Self::pos_name(&c.pocket_mapping_type_name, env)?;
4357 let hint = Self::p_hint(&c.pocket_mapping_type_type, env)?;
4358 types.push((id, hint));
4361 Self::missing_syntax(None, "pumapping", map, env)?;
4365 members.push(aast::PuMember {
4371 PocketFieldTypeExprDeclaration(c) => {
4372 let typ = Self::p_hint(&c.pocket_field_type_expr_type, env)?;
4373 let id = Self::pos_name(&c.pocket_field_type_expr_name, env)?;
4374 case_values.push((id, typ));
4376 PocketFieldTypeDeclaration(c) => {
4377 let id = Self::pos_name(&c.pocket_field_type_name, env)?;
4378 case_types.push(id);
4381 Self::missing_syntax(None, "pufield", fld, env)?;
4385 Ok(class.pu_enums.push(aast::PuEnum {
4393 _ => Self::missing_syntax(None, "class element", node, env),
4397 fn p_class_elt(class: &mut aast!(Class_<,>), node: &Syntax<T, V>, env: &mut Env) -> ret!(()) {
4398 let r = Self::p_class_elt_(class, node, env);
4400 // match ocaml behavior, don't throw if missing syntax when fail_open is true
4401 Err(Error::APIMissingSyntax { .. }) if env.fail_open => Ok(()),
4406 fn contains_class_body(c: &ClassishDeclarationChildren<T, V>) -> bool {
4407 match &c.classish_body.syntax {
4408 ClassishBody(_) => true,
4413 fn p_where_constraint(
4415 parent: &Syntax<T, V>,
4416 node: &Syntax<T, V>,
4418 ) -> ret!(Vec<aast!(WhereConstraint)>) {
4419 match &node.syntax {
4420 Missing => Ok(vec![]),
4422 if is_class && !env.parser_options.po_enable_class_level_where_clauses {
4423 Self::raise_parsing_error(
4426 "Class-level where clauses are disabled",
4429 let f = |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(WhereConstraint) {
4431 WhereConstraint(c) => {
4432 use ast_defs::ConstraintKind::*;
4433 let l = Self::p_hint(&c.where_constraint_left_type, e)?;
4434 let o = &c.where_constraint_operator;
4435 let o = match Self::token_kind(o) {
4436 Some(TK::Equal) => ConstraintEq,
4437 Some(TK::As) => ConstraintAs,
4438 Some(TK::Super) => ConstraintSuper,
4439 _ => Self::missing_syntax(None, "constraint operator", o, e)?,
4441 let r = Self::p_hint(&c.where_constraint_right_type, e)?;
4442 Ok(aast::WhereConstraint(l, o, r))
4444 _ => Self::missing_syntax(None, "where constraint", n, e),
4447 Self::as_list(&c.where_clause_constraints)
4454 Self::missing_syntax(None, "classish declaration constraints", parent, env)
4456 Self::missing_syntax(None, "function header constraints", parent, env)
4462 fn p_namespace_use_kind(kind: &Syntax<T, V>, env: &mut Env) -> ret_aast!(NsKind) {
4463 use aast::NsKind::*;
4464 match &kind.syntax {
4465 Missing => Ok(NSClassAndNamespace),
4466 _ => match Self::token_kind(kind) {
4467 Some(TK::Namespace) => Ok(NSNamespace),
4468 Some(TK::Type) => Ok(NSClass),
4469 Some(TK::Function) => Ok(NSFun),
4470 Some(TK::Const) => Ok(NSConst),
4471 _ => Self::missing_syntax(None, "namespace use kind", kind, env),
4476 fn p_namespace_use_clause(
4477 prefix: Option<&Syntax<T, V>>,
4478 kind: ret_aast!(NsKind),
4479 node: &Syntax<T, V>,
4481 ) -> ret!((aast!(NsKind), aast!(Sid), aast!(Sid))) {
4483 static ref NAMESPACE_USE: regex::Regex = regex::Regex::new("[^\\\\]*$").unwrap();
4486 match &node.syntax {
4487 NamespaceUseClause(c) => {
4488 let clause_kind = &c.namespace_use_clause_kind;
4489 let alias = &c.namespace_use_alias;
4490 let name = &c.namespace_use_name;
4491 let ast_defs::Id(p, n) = match (prefix, Self::pos_name(name, env)?) {
4493 (Some(prefix), ast_defs::Id(p, n)) => {
4494 ast_defs::Id(p, Self::pos_name(prefix, env)?.1 + &n)
4497 let alias = if alias.is_missing() {
4498 let x = NAMESPACE_USE.find(&n).unwrap().as_str();
4499 ast_defs::Id(p.clone(), x.to_string())
4501 Self::pos_name(alias, env)?
4503 let kind = if clause_kind.is_missing() {
4506 Self::p_namespace_use_kind(clause_kind, env)
4512 if n.len() > 0 && n.chars().nth(0) == Some('\\') {
4515 String::from("\\") + &n
4521 _ => Self::missing_syntax(None, "namespace use clause", node, env),
4525 fn p_def(node: &Syntax<T, V>, env: &mut Env) -> ret!(Vec<aast!(Def<,>)>) {
4526 let doc_comment_opt = Self::extract_docblock(node, env);
4527 match &node.syntax {
4528 FunctionDeclaration(c) => {
4529 let function_attribute_spec = &c.function_attribute_spec;
4530 let function_declaration_header = &c.function_declaration_header;
4531 let function_body = &c.function_body;
4532 let mut env = Env::clone_and_unset_toplevel_if_toplevel(env);
4533 let env = env.as_mut();
4534 let hdr = Self::p_fun_hdr(function_declaration_header, env)?;
4535 let is_external = function_body.is_external();
4536 let (block, yield_) = if is_external {
4539 Self::mp_yielding(&Self::p_function_body, function_body, env)?
4541 let user_attributes = Self::p_user_attributes(function_attribute_spec, env)?;
4542 let variadic = Self::determine_variadicity(&hdr.parameters);
4543 let ret = aast::TypeHint((), hdr.return_type);
4544 Ok(vec![aast::Def::mk_fun(aast::Fun_ {
4545 span: Self::p_function(node, env),
4547 mode: Self::mode_annotation(env.file_mode()),
4550 tparams: hdr.type_parameters,
4551 where_constraints: hdr.constrs,
4552 params: hdr.parameters,
4553 body: aast::FuncBody {
4557 fun_kind: Self::mk_fun_kind(hdr.suspension_kind, yield_),
4560 file_attributes: vec![],
4561 external: is_external,
4562 namespace: Self::mk_empty_ns_env(env),
4563 doc_comment: doc_comment_opt,
4567 ClassishDeclaration(c) if Self::contains_class_body(c) => {
4568 let mut env = Env::clone_and_unset_toplevel_if_toplevel(env);
4569 let env = env.as_mut();
4570 let mode = Self::mode_annotation(env.file_mode());
4571 let user_attributes = Self::p_user_attributes(&c.classish_attribute, env)?;
4572 let kinds = Self::p_kinds(&c.classish_modifiers, env)?;
4573 let final_ = kinds.has(modifier::FINAL);
4574 let is_xhp = match Self::token_kind(&c.classish_name) {
4575 Some(TK::XHPElementName) => true,
4576 Some(TK::XHPClassName) => true,
4579 let name = Self::pos_name(&c.classish_name, env)?;
4580 *env.cls_reified_generics() = HashSet::new();
4581 let tparams = aast::ClassTparams {
4582 list: Self::p_tparam_l(true, &c.classish_type_parameters, env)?,
4583 constraints: s_map::SMap::new(),
4585 let extends = Self::could_map(Self::p_hint, &c.classish_extends_list, env)?;
4586 *env.parent_maybe_reified() = match extends.first().map(|h| h.1.as_ref()) {
4587 Some(aast::Hint_::Happly(_, hl)) => !hl.is_empty(),
4590 let implements = Self::could_map(Self::p_hint, &c.classish_implements_list, env)?;
4591 let where_constraints =
4592 Self::p_where_constraint(true, node, &c.classish_where_clause, env)?;
4593 let namespace = Self::mk_empty_ns_env(env);
4594 let span = Self::p_pos(node, env);
4595 let class_kind = match Self::token_kind(&c.classish_keyword) {
4596 Some(TK::Class) if kinds.has(modifier::ABSTRACT) => {
4597 ast_defs::ClassKind::Cabstract
4599 Some(TK::Class) => ast_defs::ClassKind::Cnormal,
4600 Some(TK::Interface) => ast_defs::ClassKind::Cinterface,
4601 Some(TK::Trait) => ast_defs::ClassKind::Ctrait,
4602 Some(TK::Enum) => ast_defs::ClassKind::Cenum,
4603 _ => Self::missing_syntax(None, "class kind", &c.classish_keyword, env)?,
4605 let mut class_ = aast::Class_ {
4616 use_as_alias: vec![],
4617 insteadof_alias: vec![],
4618 method_redeclarations: vec![],
4619 xhp_attr_uses: vec![],
4628 // TODO: what is this attbiute? check ast_to_aast
4630 xhp_children: vec![],
4634 file_attributes: vec![],
4637 doc_comment: doc_comment_opt,
4639 match &c.classish_body.syntax {
4640 ClassishBody(c1) => {
4641 for elt in Self::as_list(&c1.classish_body_elements).iter() {
4642 Self::p_class_elt(&mut class_, elt, env)?;
4645 _ => Self::missing_syntax(None, "classish body", &c.classish_body, env)?,
4647 Ok(vec![aast::Def::mk_class(class_)])
4649 ConstDeclaration(c) => {
4650 let ty = &c.const_type_specifier;
4651 let decls = Self::as_list(&c.const_declarators);
4652 let mut defs = vec![];
4653 for decl in decls.iter() {
4654 let def = match &decl.syntax {
4655 ConstantDeclarator(c) => {
4656 let name = &c.constant_declarator_name;
4657 let init = &c.constant_declarator_initializer;
4658 let gconst = aast::Gconst {
4660 mode: Self::mode_annotation(env.file_mode()),
4661 name: Self::pos_name(name, env)?,
4662 type_: Self::mp_optional(Self::p_hint, ty, env)?,
4663 value: Self::p_simple_initializer(init, env)?,
4664 namespace: Self::mk_empty_ns_env(env),
4665 span: Self::p_pos(node, env),
4667 aast::Def::mk_constant(gconst)
4669 _ => Self::missing_syntax(None, "constant declaration", decl, env)?,
4675 AliasDeclaration(c) => {
4676 let tparams = Self::p_tparam_l(false, &c.alias_generic_parameter, env)?;
4677 for tparam in tparams.iter() {
4678 if tparam.reified != aast::ReifyKind::Erased {
4679 Self::raise_parsing_error(node, env, &syntax_error::invalid_reified)
4682 Ok(vec![aast::Def::mk_typedef(aast::Typedef {
4684 name: Self::pos_name(&c.alias_name, env)?,
4686 constraint: Self::mp_optional(Self::p_tconstraint, &c.alias_constraint, env)?
4688 user_attributes: itertools::concat(
4689 Self::as_list(&c.alias_attribute_spec)
4691 .map(|attr| Self::p_user_attribute(attr, env))
4692 .collect::<std::result::Result<Vec<Vec<_>>, _>>()?,
4694 namespace: Self::mk_empty_ns_env(env),
4695 mode: Self::mode_annotation(env.file_mode()),
4696 vis: match Self::token_kind(&c.alias_keyword) {
4697 Some(TK::Type) => aast::TypedefVisibility::Transparent,
4698 Some(TK::Newtype) => aast::TypedefVisibility::Opaque,
4699 _ => Self::missing_syntax(None, "kind", &c.alias_keyword, env)?,
4701 kind: Self::p_hint(&c.alias_type, env)?,
4704 EnumDeclaration(c) => {
4705 let p_enumerator = |n: &Syntax<T, V>, e: &mut Env| -> ret_aast!(ClassConst<,>) {
4707 Enumerator(c) => Ok(aast::ClassConst {
4709 id: Self::pos_name(&c.enumerator_name, e)?,
4710 expr: Some(Self::p_expr(&c.enumerator_value, e)?),
4713 _ => Self::missing_syntax(None, "enumerator", n, e),
4716 Ok(vec![aast::Def::mk_class(aast::Class_ {
4718 mode: Self::mode_annotation(env.file_mode()),
4719 user_attributes: Self::p_user_attributes(&c.enum_attribute_spec, env)?,
4720 file_attributes: vec![],
4722 kind: ast_defs::ClassKind::Cenum,
4724 name: Self::pos_name(&c.enum_name, env)?,
4725 tparams: aast::ClassTparams {
4727 constraints: s_map::SMap::new(),
4731 where_constraints: vec![],
4732 consts: Self::could_map(p_enumerator, &c.enum_enumerators, env)?,
4733 namespace: Self::mk_empty_ns_env(env),
4734 span: Self::p_pos(node, env),
4735 enum_: Some(aast::Enum_ {
4736 base: Self::p_hint(&c.enum_base, env)?,
4737 constraint: Self::mp_optional(Self::p_tconstraint_ty, &c.enum_type, env)?,
4740 doc_comment: doc_comment_opt,
4742 use_as_alias: vec![],
4743 insteadof_alias: vec![],
4744 method_redeclarations: vec![],
4745 xhp_attr_uses: vec![],
4752 xhp_children: vec![],
4757 RecordDeclaration(c) => {
4758 let p_field = |n: &Syntax<T, V>, e: &mut Env| match &n.syntax {
4759 RecordField(c) => Ok((
4760 Self::pos_name(&c.record_field_name, e)?,
4761 Self::p_hint(&c.record_field_type, e)?,
4762 Self::mp_optional(Self::p_simple_initializer, &c.record_field_init, e)?,
4764 _ => Self::missing_syntax(None, "record_field", n, e),
4766 Ok(vec![aast::Def::mk_record_def(aast::RecordDef {
4768 name: Self::pos_name(&c.record_name, env)?,
4769 extends: Self::could_map(Self::p_hint, &c.record_extends_list, env)?
4772 abstract_: Self::token_kind(&c.record_modifier) == Some(TK::Abstract),
4773 user_attributes: Self::p_user_attributes(&c.record_attribute_spec, env)?,
4774 fields: Self::could_map(p_field, &c.record_fields, env)?,
4775 namespace: Self::mk_empty_ns_env(env),
4776 span: Self::p_pos(node, env),
4777 doc_comment: doc_comment_opt,
4780 InclusionDirective(c)
4781 if env.file_mode() != file_info::Mode::Mdecl
4782 && env.file_mode() != file_info::Mode::Mphp
4785 let expr = Self::p_expr(&c.inclusion_expression, env)?;
4786 Ok(vec![aast::Def::mk_stmt(aast::Stmt::new(
4787 Self::p_pos(node, env),
4788 aast::Stmt_::mk_expr(expr),
4791 NamespaceDeclaration(c) => {
4792 let name = &c.namespace_name;
4793 let defs = match &c.namespace_body.syntax {
4794 NamespaceBody(c) => {
4795 let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
4796 let env1 = env1.as_mut();
4798 Self::as_list(&c.namespace_declarations)
4800 .map(|n| Self::p_def(n, env1))
4801 .collect::<std::result::Result<Vec<Vec<_>>, _>>()?,
4806 Ok(vec![aast::Def::mk_namespace(
4807 Self::pos_name(name, env)?,
4811 NamespaceGroupUseDeclaration(c) => {
4812 let uses: std::result::Result<Vec<_>, _> =
4813 Self::as_list(&c.namespace_group_use_clauses)
4816 Self::p_namespace_use_clause(
4817 Some(&c.namespace_group_use_prefix),
4818 Self::p_namespace_use_kind(&c.namespace_group_use_kind, env),
4824 Ok(vec![aast::Def::mk_namespace_use(uses?)])
4826 NamespaceUseDeclaration(c) => {
4827 let uses: std::result::Result<Vec<_>, _> = Self::as_list(&c.namespace_use_clauses)
4830 Self::p_namespace_use_clause(
4832 Self::p_namespace_use_kind(&c.namespace_use_kind, env),
4838 Ok(vec![aast::Def::mk_namespace_use(uses?)])
4840 FileAttributeSpecification(_) => {
4841 Ok(vec![aast::Def::mk_file_attributes(aast::FileAttribute {
4842 user_attributes: Self::p_user_attribute(node, env)?,
4843 namespace: Self::mk_empty_ns_env(env),
4846 _ if env.file_mode() == file_info::Mode::Mdecl
4847 || env.file_mode() == file_info::Mode::Mphp && !env.codegen =>
4851 _ => Ok(vec![aast::Def::mk_stmt(Self::p_stmt(node, env)?)]),
4855 fn partial_should_check_error(mode: file_info::Mode, code: usize) -> bool {
4856 use file_info::Mode::*;
4858 Mexperimental | Mstrict => true,
4859 Mdecl | Mphp => false,
4860 Mpartial => false, // TODO: Error.is_strict_code code
4864 fn post_process(env: &mut Env, program: aast!(Program<,>), acc: &mut aast!(Program<,>)) {
4865 use aast::{Def, Def::*, Stmt_::*};
4866 let mut saw_ns: Option<(aast!(Sid), aast!(Program<,>))> = None;
4867 for def in program.into_iter() {
4868 if let Namespace(_) = &def {
4869 if let Some((n, ns_acc)) = saw_ns {
4870 acc.push(Def::mk_namespace(n, ns_acc));
4875 if let Namespace(ns) = def {
4876 let (n, defs) = *ns;
4877 if defs.is_empty() {
4878 saw_ns = Some((n, vec![]));
4880 let mut acc_ = vec![];
4881 Self::post_process(env, defs, &mut acc_);
4882 acc.push(Def::mk_namespace(n, acc_));
4888 if let Stmt(s) = &def {
4889 if Self::is_noop(&s) {
4892 let raise_error = match &s.1 {
4895 if expr.as_ref().is_import()
4896 && !env.parser_options.po_disallow_toplevel_requires =>
4902 && env.is_typechecker()
4903 && Self::partial_should_check_error(env.file_mode(), 1002)
4907 Self::raise_parsing_error_pos(&s.0, env, &syntax_error::toplevel_statements);
4911 if let Some((_, ns_acc)) = &mut saw_ns {
4917 if let Some((n, defs)) = saw_ns {
4918 acc.push(Def::mk_namespace(n, defs));
4922 fn p_program(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Program<,>) {
4923 let is_halt = |syntax: &SyntaxVariant<T, V>| -> bool {
4925 ExpressionStatement(c) => match &c.expression_statement_expression.syntax {
4926 HaltCompilerExpression(_) => true,
4932 let nodes = Self::as_list(node);
4933 let mut acc = vec![];
4934 for i in 0..nodes.len() {
4935 match &nodes[i].syntax {
4936 EndOfFile(_) => break,
4937 n if is_halt(n) => {
4938 let pos = Self::p_pos(nodes[i], env);
4939 *env.saw_compiler_halt_offset() = Some(pos.end_cnum());
4941 _ => match Self::p_def(nodes[i], env) {
4942 Err(Error::APIMissingSyntax { .. }) if env.fail_open => {}
4943 e @ Err(_) => return e,
4944 Ok(mut def) => acc.append(&mut def),
4948 let mut program = vec![];
4949 Self::post_process(env, acc, &mut program);
4953 fn p_script(node: &Syntax<T, V>, env: &mut Env) -> ret_aast!(Program<,>) {
4954 match &node.syntax {
4955 Script(children) => Self::p_program(&children.script_declarations, env),
4956 _ => Self::missing_syntax(None, "script", node, env),
4960 fn elaborate_halt_compiler(ast: aast!(Program<,>), env: &mut Env) -> aast!(Program<,>) {
4961 match *env.saw_compiler_halt_offset() {
4962 Some(_) => unimplemented!(),
4967 fn lower(env: &mut Env<'a>, script: &Syntax<T, V>) -> std::result::Result<Result, String> {
4968 let aast_result = Self::p_script(script, env);
4969 let aast = match aast_result {
4971 Err(err) => match err {
4972 Error::APIMissingSyntax {
4978 "missing case in {:?}.\n - pos: {:?}\n - unexpected: '{:?}'\n - kind: {:?}\n",
4979 expecting.to_string(),
4981 node_name.to_string(),
4984 _ => Err(format!("Lowerer Error: {:?}", err))?,
4988 let aast = Self::elaborate_halt_compiler(aast, env);