fn gen_pu_accessor(
    fun_name: String,
    pos: ast_defs::Pos,
    is_final: bool,
    extends: bool,
    uses: &[&str],
    infos: Vec<(String, Tast::Expr)>,
    error: String,
) -> Tast::Method_ {
    let var_name = "$atom".to_string();
    let var_atom = lvar(pos.clone(), &var_name);
    let do_case = |entry, init| {
        let entry = str_(pos.clone(), entry);
        let ret = return_(pos.clone(), init);
        Tast::Case::Case(entry.into(), vec![ret])
    };
    let mut cases = vec![];
    for info in infos.into_iter() {
        let (atom_name, value) = info;
        cases.push(do_case(atom_name, value.clone()));
    }
    let extends =
    /* returns a stmt_, to be used in the default branch */
    if extends {
        let parent_call = class_const(pos.clone(), "parent", &fun_name);
        let call = call(pos.clone(), parent_call, vec![var_atom.clone()]);
        return_(pos.clone(), call)
    } else {
        let msg_ = Tast::Expr_::mk_binop(
            ast_defs::Bop::Dot,
            str_(pos.clone(), error),
            var_atom.clone(),
        );
        let msg = Tast::Expr(pos.clone(), msg_);
        let new_exn = new_(pos.clone(), "\\Exception", vec![msg]);
        let throw = Tast::Stmt_::mk_throw(new_exn);
        Tast::Stmt(pos.clone(), throw)
    };
    let default = if uses.is_empty() {
        Tast::Case::Default(pos.clone(), vec![extends])
    } else {
        let uses_list: Vec<Tast::Afield> = uses
            .iter()
            .map(|x| {
                Tast::Afield::AFvalue(str_(pos.clone(), string_utils::strip_ns(x).to_string()))
            })
            .collect();
        let default_block = vec![
            /* $trait_classes = vec[MyTraitA::class, MyTraitB::class]; */
            assign_lvar(
                pos.clone(),
                "$trait_classes",
                Tast::Expr(
                    pos.clone(),
                    Tast::Expr_::mk_collection(
                        ast_defs::Id(pos.clone(), "vec".to_string()),
                        None,
                        uses_list,
                    ),
                ),
            ),
            /* foreach ($trait_classes as $trait_class) */
            Tast::Stmt(
                pos.clone(),
                Tast::Stmt_::mk_foreach(
                    lvar(pos.clone(), "$trait_classes"),
                    Tast::AsExpr::AsV(lvar(pos.clone(), "$trait_class")),
                    /* try */
                    vec![Tast::Stmt(
                        pos.clone(),
                        Tast::Stmt_::mk_try(
                            vec![
                                /* $class = new ReflectionClass($trait_class); */
                                assign_lvar(
                                    pos.clone(),
                                    "$class",
                                    new_(
                                        pos.clone(),
                                        "ReflectionClass",
                                        vec![lvar(pos.clone(), "$trait_class")],
                                    ),
                                ),
                                /*  $method = $class->getMethod('pu$E$value'); */
                                assign_lvar(
                                    pos.clone(),
                                    "$method",
                                    call(
                                        pos.clone(),
                                        obj_get(pos.clone(), "$class", "getMethod"),
                                        vec![str_(pos.clone(), fun_name.clone())],
                                    ),
                                ),
                                /* return $method->invoke(null,$atom); */
                                return_(
                                    pos.clone(),
                                    call(
                                        pos.clone(),
                                        obj_get(pos.clone(), "$method", "invoke"),
                                        vec![
                                            Tast::Expr(pos.clone(), Tast::Expr_::Null),
                                            var_atom.clone(),
                                        ],
                                    ),
                                ),
                            ],
                            /* catch (Exception $_) {} */
                            vec![Tast::Catch(
                                ast_defs::Id(pos.clone(), "Exception".to_string()),
                                aast::Lid(pos.clone(), local_id::make_unscoped("$_".to_string())),
                                vec![],
                            )],
                            vec![],
                        ),
                    )],
                ),
            ),
            /* parent::pu$E$value($atom), or raise an exception */
            extends,
        ];
        Tast::Case::Default(pos.clone(), default_block)
    };
    cases.push(default);
    let body = {
        let switch = Tast::Stmt_::mk_switch(var_atom, cases);
        Tast::FuncBody {
            ast: vec![Tast::Stmt(pos.clone(), switch)],
            annotation: (),
        }
    };
    Tast::Method_ {
        span: pos.clone(),
        annotation: (),
        final_: is_final,
        abstract_: false,
        static_: true,
        visibility: aast_defs::Visibility::Public,
        name: ast_defs::Id(pos.clone(), fun_name),
        tparams: vec![],
        where_constraints: vec![],
        variadic: Tast::FunVariadicity::FVnonVariadic,
        params: vec![Tast::FunParam {
            annotation: pos.clone(),
            type_hint: create_string_type_hint(pos.clone()),
            is_variadic: false,
            pos: pos.clone(),
            name: var_name,
            expr: None,
            callconv: None,
            user_attributes: vec![],
            visibility: None,
        }],
        cap: create_mixed_type_hint(pos.clone()),
        unsafe_cap: create_mixed_type_hint(pos.clone()),
        body,
        fun_kind: ast_defs::FunKind::FSync,
        user_attributes: vec![memoize(pos.clone())],
        ret: create_mixed_type_hint(pos),
        external: false,
        doc_comment: None,
    }
}
/* Generate a static accessor function from the pumapping information, eg:

   <<__Memoize>>
   static function pu$Field_name$Expr_name(string $atom) : mixed {
     switch ($atom) {
       case "A":
        return valA;
       case "B":
        return valB;
       ...
       default:
           raise \Exception "illegal..."
     }
    }

   If the class uses traits T1, .., Tn, then the default case calls the
   pu$Field_name$Expr_name method on traits T1, .., Tn, catching method
   not found errors via reflection (as explained below for the Members function).
   Given the semantics of trait method override, it is necessary to perform
   manually the search on the used traits.

   If the class extends a superclass, the raise statement is replaced with
   a call to parent::pu$Field_name$Expr_name.

   Remark: at compile time we cannot reliably detect if, whenever a class D
   extends a class C, a PU defined in the subclass D extends a PU defined in C
   or is self-contained.  In this case the accessor functions include the
   default call to parent.  Type checking ensures that the default case is
   not reachable if the PU was not inherited from the super-class.

*/


If the class uses traits T1, .., Tn, then the default case calls the
pu$Field_name$Expr_name method on traits T1, .., Tn, catching method
not found errors via reflection (as explained below for the Members function).
Given the semantics of trait method override, it is necessary to perform
manually the search on the used traits.

If the class extends a superclass, the raise statement is replaced with
a call to parent::pu$Field_name$Expr_name.

at compile time we cannot reliably detect if, whenever a class D
extends a class C, a PU defined in the subclass D extends a PU defined in C
or is self-contained.  In this case the accessor functions include the
default call to parent.  Type checking ensures that the default case is
not reachable if the PU was not inherited from the super-class.
If the class uses traits T1 .. Tn then the default case calls the pu$Field_name$Expr_name method on traits T1 .. Tn catching method not found errors via reflection ( as explained below for the Members function ) . Given the semantics of trait method override it is necessary to perform manually the search on the used traits . If the class extends a superclass the raise statement is replaced with a call to parent :: pu$Field_name$Expr_name . at compile time we cannot reliably detect if whenever a class D extends a class C a PU defined in the subclass D extends a PU defined in C or is self - contained . In this case the accessor functions include the default call to parent . Type checking ensures that the default case is not reachable if the PU was not inherited from the super - class .
fn gen_pu_accessor(
    fun_name: String,
    pos: ast_defs::Pos,
    is_final: bool,
    extends: bool,
    uses: &[&str],
    infos: Vec<(String, Tast::Expr)>,
    error: String,
) -> Tast::Method_ {
    let var_name = "$atom".to_string();
    let var_atom = lvar(pos.clone(), &var_name);
    let do_case = |entry, init| {
        let entry = str_(pos.clone(), entry);
        let ret = return_(pos.clone(), init);
        Tast::Case::Case(entry.into(), vec![ret])
    };
    let mut cases = vec![];
    for info in infos.into_iter() {
        let (atom_name, value) = info;
        cases.push(do_case(atom_name, value.clone()));
    }
    let extends =
    /* returns a stmt_, to be used in the default branch */
    if extends {
        let parent_call = class_const(pos.clone(), "parent", &fun_name);
        let call = call(pos.clone(), parent_call, vec![var_atom.clone()]);
        return_(pos.clone(), call)
    } else {
        let msg_ = Tast::Expr_::mk_binop(
            ast_defs::Bop::Dot,
            str_(pos.clone(), error),
            var_atom.clone(),
        );
        let msg = Tast::Expr(pos.clone(), msg_);
        let new_exn = new_(pos.clone(), "\\Exception", vec![msg]);
        let throw = Tast::Stmt_::mk_throw(new_exn);
        Tast::Stmt(pos.clone(), throw)
    };
    let default = if uses.is_empty() {
        Tast::Case::Default(pos.clone(), vec![extends])
    } else {
        let uses_list: Vec<Tast::Afield> = uses
            .iter()
            .map(|x| {
                Tast::Afield::AFvalue(str_(pos.clone(), string_utils::strip_ns(x).to_string()))
            })
            .collect();
        let default_block = vec![
            /* $trait_classes = vec[MyTraitA::class, MyTraitB::class]; */
            assign_lvar(
                pos.clone(),
                "$trait_classes",
                Tast::Expr(
                    pos.clone(),
                    Tast::Expr_::mk_collection(
                        ast_defs::Id(pos.clone(), "vec".to_string()),
                        None,
                        uses_list,
                    ),
                ),
            ),
            /* foreach ($trait_classes as $trait_class) */
            Tast::Stmt(
                pos.clone(),
                Tast::Stmt_::mk_foreach(
                    lvar(pos.clone(), "$trait_classes"),
                    Tast::AsExpr::AsV(lvar(pos.clone(), "$trait_class")),
                    /* try */
                    vec![Tast::Stmt(
                        pos.clone(),
                        Tast::Stmt_::mk_try(
                            vec![
                                /* $class = new ReflectionClass($trait_class); */
                                assign_lvar(
                                    pos.clone(),
                                    "$class",
                                    new_(
                                        pos.clone(),
                                        "ReflectionClass",
                                        vec![lvar(pos.clone(), "$trait_class")],
                                    ),
                                ),
                                /*  $method = $class->getMethod('pu$E$value'); */
                                assign_lvar(
                                    pos.clone(),
                                    "$method",
                                    call(
                                        pos.clone(),
                                        obj_get(pos.clone(), "$class", "getMethod"),
                                        vec![str_(pos.clone(), fun_name.clone())],
                                    ),
                                ),
                                /* return $method->invoke(null,$atom); */
                                return_(
                                    pos.clone(),
                                    call(
                                        pos.clone(),
                                        obj_get(pos.clone(), "$method", "invoke"),
                                        vec![
                                            Tast::Expr(pos.clone(), Tast::Expr_::Null),
                                            var_atom.clone(),
                                        ],
                                    ),
                                ),
                            ],
                            /* catch (Exception $_) {} */
                            vec![Tast::Catch(
                                ast_defs::Id(pos.clone(), "Exception".to_string()),
                                aast::Lid(pos.clone(), local_id::make_unscoped("$_".to_string())),
                                vec![],
                            )],
                            vec![],
                        ),
                    )],
                ),
            ),
            /* parent::pu$E$value($atom), or raise an exception */
            extends,
        ];
        Tast::Case::Default(pos.clone(), default_block)
    };
    cases.push(default);
    let body = {
        let switch = Tast::Stmt_::mk_switch(var_atom, cases);
        Tast::FuncBody {
            ast: vec![Tast::Stmt(pos.clone(), switch)],
            annotation: (),
        }
    };
    Tast::Method_ {
        span: pos.clone(),
        annotation: (),
        final_: is_final,
        abstract_: false,
        static_: true,
        visibility: aast_defs::Visibility::Public,
        name: ast_defs::Id(pos.clone(), fun_name),
        tparams: vec![],
        where_constraints: vec![],
        variadic: Tast::FunVariadicity::FVnonVariadic,
        params: vec![Tast::FunParam {
            annotation: pos.clone(),
            type_hint: create_string_type_hint(pos.clone()),
            is_variadic: false,
            pos: pos.clone(),
            name: var_name,
            expr: None,
            callconv: None,
            user_attributes: vec![],
            visibility: None,
        }],
        cap: create_mixed_type_hint(pos.clone()),
        unsafe_cap: create_mixed_type_hint(pos.clone()),
        body,
        fun_kind: ast_defs::FunKind::FSync,
        user_attributes: vec![memoize(pos.clone())],
        ret: create_mixed_type_hint(pos),
        external: false,
        doc_comment: None,
    }
}
fn gen_pu_accessor ( fun_name : String , pos : ast_defs :: Pos , is_final : bool , extends : bool , uses : & [ & str ] , infos : Vec < ( String , Tast :: Expr ) > , error : String , ) -> Tast :: Method_ { let var_name = " " . to_string ( ) ; let var_atom = lvar ( pos . clone ( ) , & var_name ) ; let do_case = | entry , init | { let entry = str_ ( pos . clone ( ) , entry ) ; let ret = return_ ( pos . clone ( ) , init ) ; Tast :: Case :: Case ( entry . into ( ) , vec ! [ ret ] ) } ; let mut cases = vec ! [ ] ; for info in infos . into_iter ( ) { let ( atom_name , value ) = info ; cases . push ( do_case ( atom_name , value . clone ( ) ) ) ; } let extends = /* returns a stmt_, to be used in the default branch */ if extends { let parent_call = class_const ( pos . clone ( ) , " " , & fun_name ) ; let call = call ( pos . clone ( ) , parent_call , vec ! [ var_atom clone ( ) ] ) ; return_ ( pos . clone ( ) , call ) } else { let msg_ = Tast :: Expr_ :: mk_binop ( ast_defs :: Bop :: Dot , str_ ( pos . clone ( ) , error ) , var_atom . clone ( ) , ) ; let msg = Tast :: Expr ( pos . clone ( ) , msg_ ) ; let new_exn = new_ ( pos . clone ( ) , " \\ " , vec ! [ msg ] ) ; let throw = Tast :: Stmt_ :: mk_throw ( new_exn ) ; Tast :: Stmt ( pos . clone ( ) , throw ) } ; let default = if uses . is_empty ( ) { Tast :: Case :: Default ( pos . clone ( ) , vec ! [ extends ] ) } else { let uses_list : Vec < Tast :: Afield > = uses . iter ( ) . map ( | x | { Tast :: Afield :: AFvalue ( str_ ( pos . clone ( ) , string_utils :: strip_ns ( x ) . to_string ( ) ) ) } ) . collect ( ) ; let default_block = vec ! [ /* $trait_classes = vec[MyTraitA::class, MyTraitB::class]; */ assign_lvar ( pos clone ( ) " " Tast Expr ( pos clone ( ) Tast Expr_ mk_collection ( ast_defs Id ( pos clone ( ) " " to_string ( ) ) None uses_list ) ) ) /* foreach ($trait_classes as $trait_class) */ Tast Stmt ( pos clone ( ) Tast Stmt_ mk_foreach ( lvar ( pos clone ( ) " " ) Tast AsExpr AsV ( lvar ( pos clone ( ) " " ) ) /* try */ vec [ Tast Stmt ( pos clone ( ) Tast Stmt_ mk_try ( vec [ /* $class = new ReflectionClass($trait_class); */ assign_lvar ( pos clone ( ) " " new_ ( pos clone ( ) " " vec [ lvar ( pos clone ( ) " " ) ] ) ) /*  $method = $class->getMethod('pu$E$value'); */ assign_lvar ( pos clone ( ) " " call ( pos clone ( ) obj_get ( pos clone ( ) " " " " ) vec [ str_ ( pos clone ( ) fun_name clone ( ) ) ] ) ) /* return $method->invoke(null,$atom); */ return_ ( pos clone ( ) call ( pos clone ( ) obj_get ( pos clone ( ) " " " " ) vec [ Tast Expr ( pos clone ( ) Tast Expr_ Null ) var_atom clone ( ) ] ) ) ] /* catch (Exception $_) {} */ vec [ Tast Catch ( ast_defs Id ( pos clone ( ) " " to_string ( ) ) aast Lid ( pos clone ( ) local_id make_unscoped ( " " to_string ( ) ) ) vec [ ] ) ] vec [ ] ) ) ] ) ) /* parent::pu$E$value($atom), or raise an exception */ extends ] ; Tast :: Case :: Default ( pos . clone ( ) , default_block ) } ; cases . push ( default ) ; let body = { let switch = Tast :: Stmt_ :: mk_switch ( var_atom , cases ) ; Tast :: FuncBody { ast : vec ! [ Tast Stmt ( pos clone ( ) switch ) ] , annotation : ( ) , } } ; Tast :: Method_ { span : pos . clone ( ) , annotation : ( ) , final_ : is_final , abstract_ : false , static_ : true , visibility : aast_defs :: Visibility :: Public , name : ast_defs :: Id ( pos . clone ( ) , fun_name ) , tparams : vec ! [ ] , where_constraints : vec ! [ ] , variadic : Tast :: FunVariadicity :: FVnonVariadic , params : vec ! [ Tast FunParam { annotation pos clone ( ) type_hint create_string_type_hint ( pos clone ( ) ) is_variadic false pos pos clone ( ) name var_name expr None callconv None user_attributes vec [ ] visibility None } ] , cap : create_mixed_type_hint ( pos . clone ( ) ) , unsafe_cap : create_mixed_type_hint ( pos . clone ( ) ) , body , fun_kind : ast_defs :: FunKind :: FSync , user_attributes : vec ! [ memoize ( pos clone ( ) ) ] , ret : create_mixed_type_hint ( pos ) , external : false , doc_comment : None , } }
Generate a static accessor function from the pumapping information, eg:
<<__Memoize>>
static function pu$Field_name$Expr_name(string $atom) : mixed {
switch ($atom) {
case "A":
return valA;
case "B":
return valB;
...
default:
raise \Exception "illegal..."
}
}
Generate a static accessor function from the pumapping information eg : <<__Memoize >> static function pu$Field_name$Expr_name ( string $atom ) : mixed { switch ( $atom ) { case " A " : return valA ; case " B " : return valB ; ... default : raise \ Exception " illegal ... " } }
fun_name
String
pos
ast_defs::Pos
is_final
bool
extends
bool
uses
&[&str]
infos
Vec<(String, Tast::Expr)>
error
String