pub fn emit_lval_op_list(
    e: &mut Emitter,
    env: &Env,
    outer_pos: &Pos,
    local: Option<&local::Type>,
    indices: &[isize],
    expr: &tast::Expr,
    last_usage: bool,
) -> Result<(InstrSeq, InstrSeq)> {
    use options::Php7Flags;
    use tast::Expr_ as E_;
    let is_ltr = e.options().php7_flags.contains(Php7Flags::LTR_ASSIGN);
    match &expr.1 {
        E_::List(exprs) => {
            let last_non_omitted = if last_usage {
                // last usage of the local will happen when processing last non-omitted
                // element in the list - find it
                if is_ltr {
                    exprs.iter().rposition(|v| !v.1.is_omitted())
                } else {
                    // in right-to-left case result list will be reversed
                    // so we need to find first non-omitted expression
                    exprs.iter().rev().rposition(|v| !v.1.is_omitted())
                }
            } else {
                None
            };
            let (lhs_instrs, set_instrs): (Vec<InstrSeq>, Vec<InstrSeq>) = exprs
                .iter()
                .enumerate()
                .map(|(i, expr)| {
                    let mut new_indices = vec![i as isize];
                    new_indices.extend_from_slice(indices);
                    emit_lval_op_list(
                        e,
                        env,
                        outer_pos,
                        local,
                        &new_indices[..],
                        expr,
                        last_non_omitted.map_or(false, |j| j == i),
                    )
                })
                .collect::<Result<Vec<_>>>()?
                .into_iter()
                .unzip();
            Ok((
                InstrSeq::gather(lhs_instrs),
                InstrSeq::gather(if !is_ltr {
                    set_instrs.into_iter().rev().collect()
                } else {
                    set_instrs
                }),
            ))
        }
        E_::Omitted => Ok((instr::empty(), instr::empty())),
        _ => {
            // Generate code to access the element from the array
            let access_instrs = match (local, indices) {
                (Some(loc), [_, ..]) => emit_array_get_fixed(last_usage, loc.to_owned(), indices),
                (Some(loc), []) => {
                    if last_usage {
                        instr::pushl(loc.to_owned())
                    } else {
                        instr::cgetl(loc.to_owned())
                    }
                }
                (None, _) => instr::null(),
            };
            // Generate code to assign to the lvalue *)
            // Return pair: side effects to initialize lhs + assignment
            let (lhs_instrs, rhs_instrs, set_op) = emit_lval_op_nonlist_steps(
                e,
                env,
                outer_pos,
                LValOp::Set,
                expr,
                access_instrs,
                1,
                false,
            )?;
            Ok(if is_ltr {
                (
                    instr::empty(),
                    InstrSeq::gather(vec![lhs_instrs, rhs_instrs, set_op, instr::popc()]),
                )
            } else {
                (
                    lhs_instrs,
                    InstrSeq::gather(vec![instr::empty(), rhs_instrs, set_op, instr::popc()]),
                )
            })
        }
    }
}
// Generate code for each lvalue assignment in a list destructuring expression.
// Lvalues are assigned right-to-left, regardless of the nesting structure. So
//      list($a, list($b, $c)) = $d
//  and list(list($a, $b), $c) = $d
//  will both assign to $c, $b and $a in that order.
//  Returns a pair of instructions:
//  1. initialization part of the left hand side
//  2. assignment
//  this is necessary to handle cases like:
//  list($a[$f()]) = b();
//  here f() should be invoked before b()
Generate code for each lvalue assignment in a list destructuring expression.
Lvalues are assigned right-to-left, regardless of the nesting structure.
Generate code for each lvalue assignment in a list destructuring expression . Lvalues are assigned right - to - left regardless of the nesting structure .
pub fn emit_lval_op_list(
    e: &mut Emitter,
    env: &Env,
    outer_pos: &Pos,
    local: Option<&local::Type>,
    indices: &[isize],
    expr: &tast::Expr,
    last_usage: bool,
) -> Result<(InstrSeq, InstrSeq)> {
    use options::Php7Flags;
    use tast::Expr_ as E_;
    let is_ltr = e.options().php7_flags.contains(Php7Flags::LTR_ASSIGN);
    match &expr.1 {
        E_::List(exprs) => {
            let last_non_omitted = if last_usage {
                // last usage of the local will happen when processing last non-omitted
                // element in the list - find it
                if is_ltr {
                    exprs.iter().rposition(|v| !v.1.is_omitted())
                } else {
                    // in right-to-left case result list will be reversed
                    // so we need to find first non-omitted expression
                    exprs.iter().rev().rposition(|v| !v.1.is_omitted())
                }
            } else {
                None
            };
            let (lhs_instrs, set_instrs): (Vec<InstrSeq>, Vec<InstrSeq>) = exprs
                .iter()
                .enumerate()
                .map(|(i, expr)| {
                    let mut new_indices = vec![i as isize];
                    new_indices.extend_from_slice(indices);
                    emit_lval_op_list(
                        e,
                        env,
                        outer_pos,
                        local,
                        &new_indices[..],
                        expr,
                        last_non_omitted.map_or(false, |j| j == i),
                    )
                })
                .collect::<Result<Vec<_>>>()?
                .into_iter()
                .unzip();
            Ok((
                InstrSeq::gather(lhs_instrs),
                InstrSeq::gather(if !is_ltr {
                    set_instrs.into_iter().rev().collect()
                } else {
                    set_instrs
                }),
            ))
        }
        E_::Omitted => Ok((instr::empty(), instr::empty())),
        _ => {
            // Generate code to access the element from the array
            let access_instrs = match (local, indices) {
                (Some(loc), [_, ..]) => emit_array_get_fixed(last_usage, loc.to_owned(), indices),
                (Some(loc), []) => {
                    if last_usage {
                        instr::pushl(loc.to_owned())
                    } else {
                        instr::cgetl(loc.to_owned())
                    }
                }
                (None, _) => instr::null(),
            };
            // Generate code to assign to the lvalue *)
            // Return pair: side effects to initialize lhs + assignment
            let (lhs_instrs, rhs_instrs, set_op) = emit_lval_op_nonlist_steps(
                e,
                env,
                outer_pos,
                LValOp::Set,
                expr,
                access_instrs,
                1,
                false,
            )?;
            Ok(if is_ltr {
                (
                    instr::empty(),
                    InstrSeq::gather(vec![lhs_instrs, rhs_instrs, set_op, instr::popc()]),
                )
            } else {
                (
                    lhs_instrs,
                    InstrSeq::gather(vec![instr::empty(), rhs_instrs, set_op, instr::popc()]),
                )
            })
        }
    }
}
pub fn emit_lval_op_list ( e : & mut Emitter , env : & Env , outer_pos : & Pos , local : Option < & local :: Type > , indices : & [ isize ] , expr : & tast :: Expr , last_usage : bool , ) -> Result < ( InstrSeq , InstrSeq ) > { use options :: Php7Flags ; use tast :: Expr_ as E_ ; let is_ltr = e . options ( ) . php7_flags . contains ( Php7Flags :: LTR_ASSIGN ) ; match & expr . 1 { E_ :: List ( exprs ) => { let last_non_omitted = if last_usage { // last usage of the local will happen when processing last non-omitted // element in the list - find it if is_ltr { exprs . iter ( ) . rposition ( | v | ! v . 1 . is_omitted ( ) ) } else { // in right-to-left case result list will be reversed // so we need to find first non-omitted expression exprs . iter ( ) . rev ( ) . rposition ( | v | ! v . 1 . is_omitted ( ) ) } } else { None } ; let ( lhs_instrs , set_instrs ) : ( Vec < InstrSeq > , Vec < InstrSeq > ) = exprs . iter ( ) . enumerate ( ) . map ( | ( i , expr ) | { let mut new_indices = vec ! [ i as isize ] ; new_indices . extend_from_slice ( indices ) ; emit_lval_op_list ( e , env , outer_pos , local , & new_indices [ .. ] , expr , last_non_omitted . map_or ( false , | j | j == i ) , ) } ) . collect :: < Result < Vec < _ > > > ( ) ? . into_iter ( ) . unzip ( ) ; Ok ( ( InstrSeq :: gather ( lhs_instrs ) , InstrSeq :: gather ( if ! is_ltr { set_instrs . into_iter ( ) . rev ( ) . collect ( ) } else { set_instrs } ) , ) ) } E_ :: Omitted => Ok ( ( instr :: empty ( ) , instr :: empty ( ) ) ) , _ => { // Generate code to access the element from the array let access_instrs = match ( local , indices ) { ( Some ( loc ) , [ _ , .. ] ) => emit_array_get_fixed ( last_usage , loc . to_owned ( ) , indices ) , ( Some ( loc ) , [ ] ) => { if last_usage { instr :: pushl ( loc . to_owned ( ) ) } else { instr :: cgetl ( loc . to_owned ( ) ) } } ( None , _ ) => instr :: null ( ) , } ; // Generate code to assign to the lvalue *) // Return pair: side effects to initialize lhs + assignment let ( lhs_instrs , rhs_instrs , set_op ) = emit_lval_op_nonlist_steps ( e , env , outer_pos , LValOp :: Set , expr , access_instrs , 1 , false , ) ? ; Ok ( if is_ltr { ( instr :: empty ( ) , InstrSeq :: gather ( vec ! [ lhs_instrs rhs_instrs set_op instr popc ( ) ] ) , ) } else { ( lhs_instrs , InstrSeq :: gather ( vec ! [ instr empty ( ) rhs_instrs set_op instr popc ( ) ] ) , ) } ) } } }
Generate code for each lvalue assignment in a list destructuring expression.
Generate code for each lvalue assignment in a list destructuring expression .
e
&mut Emitter
env
&Env
outer_pos
&Pos
local
Option<&local::Type>
indices
&[isize]
expr
&tast::Expr
last_usage
bool