/**
  * Optimize a given node
  *
  * @param   xp.compiler.ast.Node in
  * @param   xp.compiler.types.Scope scope
  * @param   xp.compiler.optimize.Optimizations optimizations
  * @param   xp.compiler.ast.Node optimized
  */
 public function optimize(\xp\compiler\ast\Node $in, \xp\compiler\types\Scope $scope, Optimizations $optimizations)
 {
     $assign = cast($in, 'xp.compiler.ast.AssignmentNode');
     $assign->expression = $optimizations->optimize($assign->expression, $scope);
     // Optimize "<var>= <var>+ <expr>" to "<var>+= <expr>"
     if ($assign->expression instanceof BinaryOpNode && isset(self::$optimizable[$assign->expression->op]) && $assign->variable->equals($assign->expression->lhs)) {
         $assign = new AssignmentNode(['variable' => $assign->variable, 'expression' => $assign->expression->rhs, 'op' => self::$optimizable[$assign->expression->op]]);
     }
     // Optimize "<var>-= -<expr>" to "<var>+= <expr>"
     // Optimize "<var>+= -<expr>" to "<var>-= <expr>"
     if ($assign->expression instanceof UnaryOpNode && '-' === $assign->expression->op && isset(self::$switch[$assign->op])) {
         $assign = new AssignmentNode(['variable' => $assign->variable, 'expression' => $assign->expression->expression, 'op' => self::$switch[$assign->op]]);
     }
     // Not optimizable
     return $assign;
 }
 /**
  * Optimize a given node
  *
  * @param   xp.compiler.ast.Node in
  * @param   xp.compiler.types.Scope scope
  * @param   xp.compiler.optimize.Optimizations optimizations
  * @param   xp.compiler.ast.Node optimized
  */
 public function optimize(\xp\compiler\ast\Node $in, \xp\compiler\types\Scope $scope, Optimizations $optimizations)
 {
     if (!isset(self::$optimizable[$in->op])) {
         return $in;
     }
     $in->lhs = $optimizations->optimize($this->unwrap($in->lhs), $scope);
     $in->rhs = $optimizations->optimize($this->unwrap($in->rhs), $scope);
     // Optimize "a + -b" to "a - b" and "a - -b" to "a + b"
     if ($in->rhs instanceof UnaryOpNode && '-' === $in->rhs->op && isset(self::$switch[$in->op])) {
         $in = new BinaryOpNode(['lhs' => $in->lhs, 'rhs' => $in->rhs->expression, 'op' => self::$switch[$in->op]]);
     }
     // Constant folding
     if ($in->lhs instanceof Resolveable && $in->rhs instanceof Resolveable) {
         $r = call_user_func_array([$this, 'eval' . self::$optimizable[$in->op]], [$in->lhs, $in->rhs]);
         if (null !== $r) {
             $in = $r;
         }
     }
     return $in;
 }