pub fn desugar<TF>(hint: &aast::Hint, e: Expr, env: &Env<TF>) -> Result<Expr, (Pos, String)> {
    let visitor_name = hint_name(hint)?;
    let et_literal_pos = e.1.clone();

    let mut temps = Temporaries {
        splices: vec![],
        global_function_pointers: vec![],
        static_method_pointers: vec![],
    };
    let (virtual_expr, desugar_expr) = rewrite_expr(&mut temps, e, &visitor_name)?;

    let splice_count = temps.splices.len();
    let function_count = temps.global_function_pointers.len();
    let static_method_count = temps.static_method_pointers.len();

    let metadata = maketree_metadata(
        &et_literal_pos,
        &temps.splices,
        &temps.global_function_pointers,
        &temps.static_method_pointers,
    );

    // Make anonymous function of smart constructor calls
    let visitor_expr = wrap_return(desugar_expr, &et_literal_pos);
    let visitor_body = ast::FuncBody {
        fb_ast: vec![visitor_expr],
    };
    let param = ast::FunParam {
        annotation: (),
        type_hint: ast::TypeHint((), Some(hint.clone())),
        is_variadic: false,
        pos: hint.0.clone(),
        name: visitor_variable(),
        expr: None,
        callconv: None,
        readonly: None,
        user_attributes: vec![],
        visibility: None,
    };
    let visitor_fun_ = wrap_fun_(visitor_body, vec![param], et_literal_pos.clone());
    let visitor_lambda = Expr::new(
        (),
        et_literal_pos.clone(),
        Expr_::mk_lfun(visitor_fun_, vec![]),
    );

    // Wrap this in an Efun with appropriate variables for typing.
    // This enables us to report unbound variables correctly.
    let virtualized_expr = {
        let typing_fun_body = ast::FuncBody {
            fb_ast: vec![wrap_return(virtual_expr, &et_literal_pos)],
        };
        let typing_fun_ = wrap_fun_(typing_fun_body, vec![], et_literal_pos.clone());
        let mut spliced_vars: Vec<ast::Lid> = (0..splice_count)
            .into_iter()
            .map(|i| ast::Lid(et_literal_pos.clone(), (0, temp_splice_lvar_string(i))))
            .collect();
        let function_pointer_vars: Vec<ast::Lid> = (0..function_count)
            .into_iter()
            .map(|i| {
                ast::Lid(
                    et_literal_pos.clone(),
                    (0, temp_function_pointer_lvar_string(i)),
                )
            })
            .collect();
        let static_method_vars: Vec<ast::Lid> = (0..static_method_count)
            .into_iter()
            .map(|i| {
                ast::Lid(
                    et_literal_pos.clone(),
                    (0, temp_static_method_lvar_string(i)),
                )
            })
            .collect();
        spliced_vars.extend(function_pointer_vars);
        spliced_vars.extend(static_method_vars);
        Expr::new(
            (),
            et_literal_pos.clone(),
            Expr_::Call(Box::new((
                Expr::new(
                    (),
                    et_literal_pos.clone(),
                    Expr_::mk_efun(typing_fun_, spliced_vars),
                ),
                vec![],
                vec![],
                None,
            ))),
        )
    };

    // Create assignment of the extracted expressions to temporary variables
    // `$0splice0 = spliced_expr0;`
    let splice_assignments: Vec<Stmt> = create_temp_statements(temps.splices, temp_splice_lvar);
    // `$0fp0 = foo<>;`
    let function_pointer_assignments: Vec<Stmt> =
        create_temp_statements(temps.global_function_pointers, temp_function_pointer_lvar);
    // `$0sm0 = Foo::bar<>;`
    let static_method_assignments: Vec<Stmt> =
        create_temp_statements(temps.static_method_pointers, temp_static_method_lvar);

    let mut function_pointers = vec![];
    function_pointers.extend(function_pointer_assignments);
    function_pointers.extend(static_method_assignments);

    let make_tree = static_meth_call(
        &visitor_name,
        et::MAKE_TREE,
        vec![exprpos(&et_literal_pos), metadata, visitor_lambda],
        &et_literal_pos.clone(),
    );

    let runtime_expr = if splice_assignments.is_empty() && function_pointers.is_empty() {
        make_tree
    } else {
        let body = if env.codegen {
            let mut b = splice_assignments.clone();
            b.extend(function_pointers.clone());
            b.push(wrap_return(make_tree, &et_literal_pos));
            b
        } else {
            vec![wrap_return(make_tree, &et_literal_pos)]
        };
        immediately_invoked_lambda(&et_literal_pos, body)
    };

    Ok(Expr::new(
        (),
        et_literal_pos,
        Expr_::mk_expression_tree(ast::ExpressionTree {
            hint: hint.clone(),
            splices: splice_assignments,
            function_pointers,
            virtualized_expr,
            runtime_expr,
        }),
    ))
}
/// Rewrite the contents of an expression tree literal into an
/// expression on a visitor class.
///
/// Given the following expression tree:
/// ```
/// MyDsl`foo(1) + ${ $x }`;
/// ```
///
/// First, the splices are extracted and assigned to temporary variables:
/// ```
/// { $0splice0 = $x; }
/// ```
///
/// Then the expression is virtualized as virtualized_expr
/// ```
/// MyDsl::symbolType(foo<>)(MyDsl::intType())->__plus( ${ $0splice0 } )
/// ```
/// Where virtualized_expr is used in helping type Expression Trees
///
/// Finally, the expression is desugared as runtime_expr
/// ```
/// MyDsl::makeTree(
///   // At runtime, expression tree visitors know the position of the literal.
///   shape('path' => 'whatever.php', 'start_line' => 123, ...),
///
///   // We provide metadata of values used inside the visitor, so users can access
///   // spliced or called values without having to re-run the visit method.
///   shape(
///     'splices' => dict['$0splice0' => $0splice0],
///     'functions' => vec[foo<>],
///     'static_methods' => vec[],
///   )
///
///   (MyDsl $0v) ==> {
///     $0v->visitBinop(
///       // (ignoring ExprPos arguments for brevity)
///       $0v->visitCall(
///         $0v->visitGlobalFunction(foo<>),
///         vec[$0v->visitInt(1)],
///       ),
///       '__plus',
///       $0v->splice('$0splice0', $0splice0),
///     )
///   },
/// )
/// ```
/// Which is the runtime representation of the Expression Tree
Rewrite the contents of an expression tree literal into an
expression on a visitor class.







Finally, the expression is desugared as runtime_expr
```
MyDsl::makeTree(
At runtime, expression tree visitors know the position of the literal.

We provide metadata of values used inside the visitor, so users can access
spliced or called values without having to re-run the visit method.


Rewrite the contents of an expression tree literal into an expression on a visitor class . Finally the expression is desugared as runtime_expr ` ` ` MyDsl :: makeTree ( At runtime expression tree visitors know the position of the literal . We provide metadata of values used inside the visitor so users can access spliced or called values without having to re - run the visit method .
pub fn desugar<TF>(hint: &aast::Hint, e: Expr, env: &Env<TF>) -> Result<Expr, (Pos, String)> {
    let visitor_name = hint_name(hint)?;
    let et_literal_pos = e.1.clone();
    let mut temps = Temporaries {
        splices: vec![],
        global_function_pointers: vec![],
        static_method_pointers: vec![],
    };
    let (virtual_expr, desugar_expr) = rewrite_expr(&mut temps, e, &visitor_name)?;
    let splice_count = temps.splices.len();
    let function_count = temps.global_function_pointers.len();
    let static_method_count = temps.static_method_pointers.len();
    let metadata = maketree_metadata(
        &et_literal_pos,
        &temps.splices,
        &temps.global_function_pointers,
        &temps.static_method_pointers,
    );
    // Make anonymous function of smart constructor calls
    let visitor_expr = wrap_return(desugar_expr, &et_literal_pos);
    let visitor_body = ast::FuncBody {
        fb_ast: vec![visitor_expr],
    };
    let param = ast::FunParam {
        annotation: (),
        type_hint: ast::TypeHint((), Some(hint.clone())),
        is_variadic: false,
        pos: hint.0.clone(),
        name: visitor_variable(),
        expr: None,
        callconv: None,
        readonly: None,
        user_attributes: vec![],
        visibility: None,
    };
    let visitor_fun_ = wrap_fun_(visitor_body, vec![param], et_literal_pos.clone());
    let visitor_lambda = Expr::new(
        (),
        et_literal_pos.clone(),
        Expr_::mk_lfun(visitor_fun_, vec![]),
    );
    // Wrap this in an Efun with appropriate variables for typing.
    // This enables us to report unbound variables correctly.
    let virtualized_expr = {
        let typing_fun_body = ast::FuncBody {
            fb_ast: vec![wrap_return(virtual_expr, &et_literal_pos)],
        };
        let typing_fun_ = wrap_fun_(typing_fun_body, vec![], et_literal_pos.clone());
        let mut spliced_vars: Vec<ast::Lid> = (0..splice_count)
            .into_iter()
            .map(|i| ast::Lid(et_literal_pos.clone(), (0, temp_splice_lvar_string(i))))
            .collect();
        let function_pointer_vars: Vec<ast::Lid> = (0..function_count)
            .into_iter()
            .map(|i| {
                ast::Lid(
                    et_literal_pos.clone(),
                    (0, temp_function_pointer_lvar_string(i)),
                )
            })
            .collect();
        let static_method_vars: Vec<ast::Lid> = (0..static_method_count)
            .into_iter()
            .map(|i| {
                ast::Lid(
                    et_literal_pos.clone(),
                    (0, temp_static_method_lvar_string(i)),
                )
            })
            .collect();
        spliced_vars.extend(function_pointer_vars);
        spliced_vars.extend(static_method_vars);
        Expr::new(
            (),
            et_literal_pos.clone(),
            Expr_::Call(Box::new((
                Expr::new(
                    (),
                    et_literal_pos.clone(),
                    Expr_::mk_efun(typing_fun_, spliced_vars),
                ),
                vec![],
                vec![],
                None,
            ))),
        )
    };
    // Create assignment of the extracted expressions to temporary variables
    // `$0splice0 = spliced_expr0;`
    let splice_assignments: Vec<Stmt> = create_temp_statements(temps.splices, temp_splice_lvar);
    // `$0fp0 = foo<>;`
    let function_pointer_assignments: Vec<Stmt> =
        create_temp_statements(temps.global_function_pointers, temp_function_pointer_lvar);
    // `$0sm0 = Foo::bar<>;`
    let static_method_assignments: Vec<Stmt> =
        create_temp_statements(temps.static_method_pointers, temp_static_method_lvar);
    let mut function_pointers = vec![];
    function_pointers.extend(function_pointer_assignments);
    function_pointers.extend(static_method_assignments);
    let make_tree = static_meth_call(
        &visitor_name,
        et::MAKE_TREE,
        vec![exprpos(&et_literal_pos), metadata, visitor_lambda],
        &et_literal_pos.clone(),
    );
    let runtime_expr = if splice_assignments.is_empty() && function_pointers.is_empty() {
        make_tree
    } else {
        let body = if env.codegen {
            let mut b = splice_assignments.clone();
            b.extend(function_pointers.clone());
            b.push(wrap_return(make_tree, &et_literal_pos));
            b
        } else {
            vec![wrap_return(make_tree, &et_literal_pos)]
        };
        immediately_invoked_lambda(&et_literal_pos, body)
    };
    Ok(Expr::new(
        (),
        et_literal_pos,
        Expr_::mk_expression_tree(ast::ExpressionTree {
            hint: hint.clone(),
            splices: splice_assignments,
            function_pointers,
            virtualized_expr,
            runtime_expr,
        }),
    ))
}
pub fn desugar < TF > ( hint : & aast :: Hint , e : Expr , env : & Env < TF > ) -> Result < Expr , ( Pos , String ) > { let visitor_name = hint_name ( hint ) ? ; let et_literal_pos = e . 1 . clone ( ) ; let mut temps = Temporaries { splices : vec ! [ ] , global_function_pointers : vec ! [ ] , static_method_pointers : vec ! [ ] , } ; let ( virtual_expr , desugar_expr ) = rewrite_expr ( & mut temps , e , & visitor_name ) ? ; let splice_count = temps . splices . len ( ) ; let function_count = temps . global_function_pointers . len ( ) ; let static_method_count = temps . static_method_pointers . len ( ) ; let metadata = maketree_metadata ( & et_literal_pos , & temps . splices , & temps . global_function_pointers , & temps . static_method_pointers , ) ; // Make anonymous function of smart constructor calls let visitor_expr = wrap_return ( desugar_expr , & et_literal_pos ) ; let visitor_body = ast :: FuncBody { fb_ast : vec ! [ visitor_expr ] , } ; let param = ast :: FunParam { annotation : ( ) , type_hint : ast :: TypeHint ( ( ) , Some ( hint . clone ( ) ) ) , is_variadic : false , pos : hint . 0 . clone ( ) , name : visitor_variable ( ) , expr : None , callconv : None , readonly : None , user_attributes : vec ! [ ] , visibility : None , } ; let visitor_fun_ = wrap_fun_ ( visitor_body , vec ! [ param ] , et_literal_pos . clone ( ) ) ; let visitor_lambda = Expr :: new ( ( ) , et_literal_pos . clone ( ) , Expr_ :: mk_lfun ( visitor_fun_ , vec ! [ ] ) , ) ; // Wrap this in an Efun with appropriate variables for typing. // This enables us to report unbound variables correctly. let virtualized_expr = { let typing_fun_body = ast :: FuncBody { fb_ast : vec ! [ wrap_return ( virtual_expr et_literal_pos ) ] , } ; let typing_fun_ = wrap_fun_ ( typing_fun_body , vec ! [ ] , et_literal_pos . clone ( ) ) ; let mut spliced_vars : Vec < ast :: Lid > = ( 0 .. splice_count ) . into_iter ( ) . map ( | i | ast :: Lid ( et_literal_pos . clone ( ) , ( 0 , temp_splice_lvar_string ( i ) ) ) ) . collect ( ) ; let function_pointer_vars : Vec < ast :: Lid > = ( 0 .. function_count ) . into_iter ( ) . map ( | i | { ast :: Lid ( et_literal_pos . clone ( ) , ( 0 , temp_function_pointer_lvar_string ( i ) ) , ) } ) . collect ( ) ; let static_method_vars : Vec < ast :: Lid > = ( 0 .. static_method_count ) . into_iter ( ) . map ( | i | { ast :: Lid ( et_literal_pos . clone ( ) , ( 0 , temp_static_method_lvar_string ( i ) ) , ) } ) . collect ( ) ; spliced_vars . extend ( function_pointer_vars ) ; spliced_vars . extend ( static_method_vars ) ; Expr :: new ( ( ) , et_literal_pos . clone ( ) , Expr_ :: Call ( Box :: new ( ( Expr :: new ( ( ) , et_literal_pos . clone ( ) , Expr_ :: mk_efun ( typing_fun_ , spliced_vars ) , ) , vec ! [ ] , vec ! [ ] , None , ) ) ) , ) } ; // Create assignment of the extracted expressions to temporary variables // `$0splice0 = spliced_expr0;` let splice_assignments : Vec < Stmt > = create_temp_statements ( temps . splices , temp_splice_lvar ) ; // `$0fp0 = foo<>;` let function_pointer_assignments : Vec < Stmt > = create_temp_statements ( temps . global_function_pointers , temp_function_pointer_lvar ) ; // `$0sm0 = Foo::bar<>;` let static_method_assignments : Vec < Stmt > = create_temp_statements ( temps . static_method_pointers , temp_static_method_lvar ) ; let mut function_pointers = vec ! [ ] ; function_pointers . extend ( function_pointer_assignments ) ; function_pointers . extend ( static_method_assignments ) ; let make_tree = static_meth_call ( & visitor_name , et :: MAKE_TREE , vec ! [ exprpos ( et_literal_pos ) metadata visitor_lambda ] , & et_literal_pos . clone ( ) , ) ; let runtime_expr = if splice_assignments . is_empty ( ) && function_pointers . is_empty ( ) { make_tree } else { let body = if env . codegen { let mut b = splice_assignments . clone ( ) ; b . extend ( function_pointers . clone ( ) ) ; b . push ( wrap_return ( make_tree , & et_literal_pos ) ) ; b } else { vec ! [ wrap_return ( make_tree et_literal_pos ) ] } ; immediately_invoked_lambda ( & et_literal_pos , body ) } ; Ok ( Expr :: new ( ( ) , et_literal_pos , Expr_ :: mk_expression_tree ( ast :: ExpressionTree { hint : hint . clone ( ) , splices : splice_assignments , function_pointers , virtualized_expr , runtime_expr , } ) , ) ) }
Rewrite the contents of an expression tree literal into an
expression on a visitor class.
Rewrite the contents of an expression tree literal into an expression on a visitor class .
hint
&aast::Hint
e
Expr
env
&Env<TF>
hint
&aast::Hint
e
Expr
env
&Env<TF>