Index: /trunk/Decompiler.class.php
===================================================================
--- /trunk/Decompiler.class.php	(revision 810)
+++ /trunk/Decompiler.class.php	(revision 811)
@@ -559,8 +559,8 @@
 	}
 	// }}}
-	function outputPhp(&$EX, $range, $indent) // {{{
+	function outputPhp(&$EX, $range) // {{{
 	{
 		$needBlankline = isset($EX['lastBlock']);
-		$origindent = $indent;
+		$indent = $EX['indent'];
 		$curticks = 0;
 		for ($i = $range[0]; $i <= $range[1]; $i ++) {
@@ -579,10 +579,10 @@
 					$curticks = $toticks;
 					if (!$curticks) {
-						echo $origindent, "}\n\n";
-						$indent = $origindent;
+						echo $EX['indent'], "}\n\n";
+						$indent = $EX['indent'];
 					}
 					else {
 						if ($oldticks) {
-							echo $origindent, "}\n\n";
+							echo $EX['indent'], "}\n\n";
 						}
 						else if (!$oldticks) {
@@ -593,5 +593,5 @@
 							echo PHP_EOL;
 						}
-						echo $origindent, "declare (ticks=$curticks) {\n";
+						echo $EX['indent'], "declare (ticks=$curticks) {\n";
 					}
 				}
@@ -605,5 +605,5 @@
 		}
 		if ($curticks) {
-			echo $origindent, "}\n";
+			echo $EX['indent'], "}\n";
 		}
 	}
@@ -700,11 +700,11 @@
 	}
 	// }}}
-	function decompileBasicBlock(&$EX, $range, $indent, $unhandled = false) // {{{
+	function decompileBasicBlock(&$EX, $range, $unhandled = false) // {{{
 	{
 		$this->dasmBasicBlock($EX, $range);
 		if ($unhandled) {
-			$this->dumpRange($EX, $range, $indent);
-		}
-		$this->outputPhp($EX, $range, $indent);
+			$this->dumpRange($EX, $range);
+		}
+		$this->outputPhp($EX, $range);
 	}
 	// }}}
@@ -731,4 +731,18 @@
 	}
 	// }}}
+	function beginScope(&$EX, $doIndent = true) // {{{
+	{
+		array_push($EX['scopeStack'], array($EX['lastBlock'], $EX['indent']));
+		if ($doIndent) {
+			$EX['indent'] .= INDENT;
+		}
+		$EX['lastBlock'] = null;
+	}
+	// }}}
+	function endScope(&$EX) // {{{
+	{
+		list($EX['lastBlock'], $EX['indent']) = array_pop($EX['scopeStack']);
+	}
+	// }}}
 	function beginComplexBlock(&$EX) // {{{
 	{
@@ -744,8 +758,9 @@
 	}
 	// }}}
-	function decompileComplexBlock(&$EX, $range, $indent) // {{{
+	function decompileComplexBlock(&$EX, $range) // {{{
 	{
 		$T = &$EX['Ts'];
 		$opcodes = &$EX['opcodes'];
+		$indent = $EX['indent'];
 
 		$firstOp = &$opcodes[$range[0]];
@@ -760,8 +775,8 @@
 			$this->removeJmpInfo($EX, $range[0]);
 
-			$this->recognizeAndDecompileClosedBlocks($EX, array($range[0], $range[0]), $indent . INDENT);
+			$this->recognizeAndDecompileClosedBlocks($EX, array($range[0], $range[0]));
 			$op1 = $this->getOpVal($firstOp['result'], $EX, true);
 
-			$this->recognizeAndDecompileClosedBlocks($EX, array($range[0] + 1, $range[1]), $indent . INDENT);
+			$this->recognizeAndDecompileClosedBlocks($EX, array($range[0] + 1, $range[1]));
 			$op2 = $this->getOpVal($lastOp['result'], $EX, true);
 
@@ -782,7 +797,7 @@
 
 			$condition = $this->getOpVal($firstOp['op1'], $EX);
-			$this->recognizeAndDecompileClosedBlocks($EX, $trueRange, $indent . INDENT);
+			$this->recognizeAndDecompileClosedBlocks($EX, $trueRange);
 			$trueValue = $this->getOpVal($opcodes[$trueRange[1]]['result'], $EX, true);
-			$this->recognizeAndDecompileClosedBlocks($EX, $falseRange, $indent . INDENT);
+			$this->recognizeAndDecompileClosedBlocks($EX, $falseRange);
 			$falseValue = $this->getOpVal($opcodes[$falseRange[1]]['result'], $EX, true);
 			$T[$opcodes[$trueRange[1]]['result']['var']] = new Decompiler_TriOp($condition, $trueValue, $falseValue);
@@ -798,5 +813,5 @@
 			$opcodes[$target]['gofrom'][] = $range[0];
 
-			$this->recognizeAndDecompileClosedBlocks($EX, $range, $indent);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
 			return false;
 		}
@@ -814,5 +829,6 @@
 
 			$initial = '';
-			$this->dasmBasicBlock($EX, $conditionRange, $indent . INDENT);
+			$this->beginScope($EX);
+			$this->dasmBasicBlock($EX, $conditionRange);
 			$conditionCodes = array();
 			for ($i = $conditionRange[0]; $i <= $conditionRange[1]; ++$i) {
@@ -825,6 +841,8 @@
 				$conditionCodes = array();
 			}
-
-			$this->dasmBasicBlock($EX, $nextRange, $indent . INDENT);
+			$this->endScope($EX);
+
+			$this->beginScope($EX);
+			$this->dasmBasicBlock($EX, $nextRange);
 			$nextCodes = array();
 			for ($i = $nextRange[0]; $i <= $nextRange[1]; ++$i) {
@@ -833,7 +851,11 @@
 				}
 			}
+			$this->endScope($EX);
+
 			$this->beginComplexBlock($EX);
 			echo $indent, 'for (', str($initial, $EX), '; ', implode(', ', $conditionCodes), '; ', implode(', ', $nextCodes), ') ', '{', PHP_EOL;
-			$this->recognizeAndDecompileClosedBlocks($EX, $bodyRange, $indent . INDENT);
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $bodyRange);
+			$this->endScope($EX);
 			echo $indent, '}', PHP_EOL;
 			$this->endComplexBlock($EX);
@@ -852,5 +874,7 @@
 
 				echo $indent, $isElseIf ? 'else if' : 'if', ' (', str($condition, $EX), ') ', '{', PHP_EOL;
-				$this->recognizeAndDecompileClosedBlocks($EX, $ifRange, $indent . INDENT);
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, $ifRange);
+				$this->endScope($EX);
 				$EX['lastBlock'] = null;
 				echo $indent, '}', PHP_EOL;
@@ -873,5 +897,7 @@
 				$elseRange = array($ifRange[1], $range[1]);
 				echo $indent, 'else ', '{', PHP_EOL;
-				$this->recognizeAndDecompileClosedBlocks($EX, $elseRange, $indent . INDENT);
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, $elseRange);
+				$this->endScope($EX);
 				$EX['lastBlock'] = null;
 				echo $indent, '}', PHP_EOL;
@@ -916,10 +942,12 @@
 			$this->beginComplexBlock($EX);
 			echo $indent, "try {", PHP_EOL;
-			$this->recognizeAndDecompileClosedBlocks($EX, $tryRange, $indent . INDENT);
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $tryRange);
+			$this->endScope($EX);
 			echo $indent, '}', PHP_EOL;
 			foreach ($catchBlocks as $catchFirst => $catchInfo) {
 				list($catchOpLine, $catchBodyLast) = $catchInfo;
 				$catchBodyFirst = $catchOpLine + 1;
-				$this->recognizeAndDecompileClosedBlocks($EX, array($catchFirst, $catchOpLine), $indent);
+				$this->dasmBasicBlock($EX, array($catchFirst, $catchOpLine));
 				$catchOp = &$opcodes[$catchOpLine];
 				echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ") {", PHP_EOL;
@@ -927,5 +955,7 @@
 
 				$EX['lastBlock'] = null;
-				$this->recognizeAndDecompileClosedBlocks($EX, array($catchBodyFirst, $catchBodyLast), $indent . INDENT);
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, array($catchBodyFirst, $catchBodyLast));
+				$this->endScope($EX);
 				echo $indent, '}', PHP_EOL;
 			}
@@ -982,8 +1012,7 @@
 			$caseIsOut = false;
 			foreach ($cases as $caseFirst => $caseLast) {
-				if ($caseIsOut && !empty($EX['lastBlock']) && empty($lastCaseFall)) {
+				if ($caseIsOut && empty($lastCaseFall)) {
 					echo PHP_EOL;
 				}
-				unset($EX['lastBlock']);
 
 				$caseOp = $opcodes[$caseFirst];
@@ -1025,5 +1054,7 @@
 				}
 
-				$this->recognizeAndDecompileClosedBlocks($EX, array($caseFirst, $caseLast), $indent . INDENT);
+				$this->beginScope($EX);
+				$this->recognizeAndDecompileClosedBlocks($EX, array($caseFirst, $caseLast));
+				$this->endScope($EX);
 				$caseIsOut = true;
 			}
@@ -1041,5 +1072,7 @@
 
 			echo $indent, "do {", PHP_EOL;
-			$this->recognizeAndDecompileClosedBlocks($EX, $range, $indent . INDENT);
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			$this->endScope($EX);
 			echo $indent, "} while (", str($this->getOpVal($lastOp['op1'], $EX)), ');', PHP_EOL;
 
@@ -1072,5 +1105,7 @@
 
 			ob_start();
-			$this->recognizeAndDecompileClosedBlocks($EX, $range, $indent . INDENT);
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			$this->endScope($EX);
 			$body = ob_get_clean();
 
@@ -1094,5 +1129,7 @@
 
 			ob_start();
-			$this->recognizeAndDecompileClosedBlocks($EX, $range, $indent . INDENT);
+			$this->beginScope($EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $range);
+			$this->endScope($EX);
 			$body = ob_get_clean();
 
@@ -1114,8 +1151,8 @@
 		// }}}
 
-		$this->decompileBasicBlock($EX, $range, $indent, true);
-	}
-	// }}}
-	function recognizeAndDecompileClosedBlocks(&$EX, $range, $indent) // {{{ decompile in a tree way
+		$this->decompileBasicBlock($EX, $range, true);
+	}
+	// }}}
+	function recognizeAndDecompileClosedBlocks(&$EX, $range) // {{{ decompile in a tree way
 	{
 		$opcodes = &$EX['opcodes'];
@@ -1148,7 +1185,7 @@
 				if ($blockLast >= $blockFirst) {
 					if ($blockFirst > $starti) {
-						$this->decompileBasicBlock($EX, array($starti, $blockFirst - 1), $indent);
-					}
-					if ($this->decompileComplexBlock($EX, array($blockFirst, $blockLast), $indent) === false) {
+						$this->decompileBasicBlock($EX, array($starti, $blockFirst - 1));
+					}
+					if ($this->decompileComplexBlock($EX, array($blockFirst, $blockLast)) === false) {
 						if ($EX['lastBlock'] == 'complex') {
 							echo PHP_EOL;
@@ -1168,5 +1205,5 @@
 		}
 		if ($starti <= $range[1]) {
-			$this->decompileBasicBlock($EX, array($starti, $range[1]), $indent);
+			$this->decompileBasicBlock($EX, array($starti, $range[1]));
 		}
 	}
@@ -1289,4 +1326,5 @@
 		$EX['argstack'] = array();
 		$EX['arg_types_stack'] = array();
+		$EX['scopeStack'] = array();
 		$EX['silence'] = 0;
 		$EX['recvs'] = array();
@@ -1304,122 +1342,4 @@
 		$this->recognizeAndDecompileClosedBlocks($EX, $EX['range'], $EX['indent']);
 		return $EX;
-	}
-	// }}}
-	function outputCode(&$EX, $range, $indent, $loop = false) // {{{
-	{
-		$op = &$EX['opcodes'][$range[0]];
-		$next = $EX['nextbbs'][$range[0]];
-
-		$end = $next - 1;
-		if ($end > $range[1]) {
-			$end = $range[1];
-		}
-
-		if (isset($op['jmpins'])) {
-			echo "\nline", $op['line'], ":\n";
-		}
-		else {
-			// echo ";;;\n";
-		}
-		$this->dasmBasicBlock($EX, array($opline, $end));
-		$this->outputPhp($EX, array($opline, $end), $indent);
-		// jmpout op
-		$op = &$EX['opcodes'][$end];
-		$op1 = $op['op1'];
-		$op2 = $op['op2'];
-		$ext = $op['extended_value'];
-		$line = $op['line'];
-
-		if (isset($EX['opcodes'][$next])) {
-			if (isset($range[1]) && $next > $range[1]) {
-				$next = null;
-			}
-		}
-		else {
-			$next = null;
-		}
-		/*
-		if ($op['opcode'] == XC_JMPZ) {
-			$target = $op2['opline_num'];
-			if ($line + 1) {
-				$nextblock = $EX['nextbbs'][$next];
-				$jmpop = end($nextblock);
-				if ($jmpop['opcode'] == XC_JMP) {
-					$ifendline = $op2['opline_num'];
-					if ($ifendline >= $line) {
-						$cond = $op['cond'];
-						echo "{$indent}if ($cond) {\n";
-						$this->outputCode($EX, $next, $range[1], INDENT . $indent);
-						echo "$indent}\n";
-						$this->outputCode($EX, $target, $range[1], $indent);
-						return;
-					}
-				}
-			}
-		}
-		*/
-		if (!isset($next)) {
-			return;
-		}
-		if (isset($op['jmpouts']) && isset($op['isjmp'])) {
-			if (isset($op['cond'])) {
-				echo "{$indent}check (" . str($op["cond"]) . ") {\n";
-				echo INDENT;
-			}
-			switch ($op['opcode']) {
-			case XC_CONT:
-			case XC_BRK:
-				break;
-
-			default:
-				echo $indent;
-				echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
-				if (isset($op['jmpouts'][1])) {
-					echo ', line', $op['jmpouts'][1];
-				}
-				echo ";";
-				// echo ' // <- line', $op['line'];
-				echo "\n";
-			}
-			if (isset($op['cond'])) echo "$indent}\n";
-		}
-
-		// proces JMPZ_EX/JMPNZ_EX for AND,OR
-		$op = &$EX['opcodes'][$next];
-		/*
-		if (isset($op['jmpins'])) {
-			foreach (array_reverse($op['jmpins']) as $fromline) {
-				$fromop = $EX['opcodes'][$fromline];
-				switch ($fromop['opcode']) {
-				case XC_JMPZ_EX: $opstr = 'and'; break;
-				case XC_JMPNZ_EX: $opstr = 'or'; break;
-				case XC_JMPZNZ: var_dump($fromop); exit;
-				default: continue 2;
-				}
-
-				$var = $fromop['result']['var'];
-				var_dump($EX['Ts'][$var]);
-				$EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
-			}
-			#$this->outputCode($EX, $next, $range[1], $indent);
-			#return;
-		}
-		*/
-		if (isset($op['cond_false'])) {
-			// $this->dumpop($op, $EX);
-			// any true comes here, so it's a "or"
-			$cond = implode(' and ', str($op['cond_false']));
-			// var_dump($op['cond'] = $cond);
-			/*
-			$rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
-			unset($op['cond_true']);
-			*/
-		}
-
-		$nextRange = array($next, $range[1]);
-		if ($loop) {
-			return $nextRange;
-		}
-		$this->outputCode($EX, $nextRange, $indent);
 	}
 	// }}}
@@ -1921,5 +1841,5 @@
 					$i += 2;
 				}
-				$this->dclass($class);
+				$this->dclass($class, $EX['indent']);
 				echo "\n";
 				unset($class);
@@ -2070,28 +1990,8 @@
 			case XC_JMPZNZ: // for
 			case XC_JMPZ: // {{{
-				if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
-					$rvalue = $EX['object'];
-				}
-				else {
-					$rvalue = $this->getOpVal($op1, $EX);
-				}
-
-				if (isset($op['cond_true'])) {
-					// any true comes here, so it's a "or"
-					$rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
-					unset($op['cond_true']);
-				}
-				if (isset($op['cond_false'])) {
-					echo "TODO(cond_false):\n";
-					var_dump($op);// exit;
-				}
-				$op['cond'] = $rvalue; 
-				$op['isjmp'] = true;
 				break;
 				// }}}
 			case XC_CONT:
 			case XC_BRK:
-				$op['cond'] = null;
-				$op['isjmp'] = true;
 				$resvar = $opc == XC_CONT ? 'continue' : 'break';
 				$count = str($this->getOpVal($op2, $EX));
@@ -2106,6 +2006,4 @@
 
 			case XC_JMP: // {{{
-				$op['cond'] = null;
-				$op['isjmp'] = true;
 				break;
 				// }}}
@@ -2342,13 +2240,13 @@
 	}
 	// }}}
-	function dumpRange(&$EX, $range, $indent = '') // {{{
+	function dumpRange(&$EX, $range) // {{{
 	{
 		for ($i = $range[0]; $i <= $range[1]; ++$i) {
-			echo $indent, $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
-		}
-		echo $indent, "==", PHP_EOL;
-	}
-	// }}}
-	function dargs(&$EX, $indent) // {{{
+			echo $EX['indent'], $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
+		}
+		echo $EX['indent'], "==", PHP_EOL;
+	}
+	// }}}
+	function dargs(&$EX) // {{{
 	{
 		$op_array = &$EX['op_array'];
@@ -2410,13 +2308,13 @@
 					}
 				}
-				echo str($arg[0], $indent);
+				echo str($arg[0], $EX);
 			}
 			if (isset($arg[1])) {
-				echo ' = ', str($arg[1], $indent);
-			}
-		}
-	}
-	// }}}
-	function duses(&$EX, $indent) // {{{
+				echo ' = ', str($arg[1], $EX);
+			}
+		}
+	}
+	// }}}
+	function duses(&$EX) // {{{
 	{
 		if ($EX['uses']) {
@@ -2425,5 +2323,5 @@
 	}
 	// }}}
-	function dfunction($func, $indent = '', $nobody = false) // {{{
+	function dfunction($func, $indent = '', $decorations = array(), $nobody = false) // {{{
 	{
 		$this->detectNamespace($func['op_array']['function_name']);
@@ -2437,22 +2335,27 @@
 		else {
 			ob_start();
-			$newindent = INDENT . $indent;
-			$EX = &$this->dop_array($func['op_array'], $newindent);
+			$EX = &$this->dop_array($func['op_array'], $indent . INDENT);
 			$body = ob_get_clean();
 		}
 
 		$functionName = $this->stripNamespace($func['op_array']['function_name']);
+		$isExpression = false;
 		if ($functionName == '{closure}') {
 			$functionName = '';
+			$isExpression = true;
+		}
+		echo $isExpression ? '' : $indent;
+		if ($decorations) {
+			echo implode(' ', $decorations), ' ';
 		}
 		echo 'function', $functionName ? ' ' . $functionName : '', '(';
-		$this->dargs($EX, $indent);
+		$this->dargs($EX);
 		echo ")";
-		$this->duses($EX, $indent);
+		$this->duses($EX);
 		if ($nobody) {
 			echo ";\n";
 		}
 		else {
-			if ($functionName !== '') {
+			if (!$isExpression) {
 				echo "\n";
 				echo $indent, "{\n";
@@ -2464,5 +2367,5 @@
 			echo $body;
 			echo "$indent}";
-			if ($functionName !== '') {
+			if (!$isExpression) {
 				echo "\n";
 			}
@@ -2480,19 +2383,25 @@
 			echo "\n";
 		}
-		$isinterface = false;
+		$isInterface = false;
+		$decorations = array();
 		if (!empty($class['ce_flags'])) {
 			if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
-				$isinterface = true;
+				$isInterface = true;
 			}
 			else {
 				if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
-					echo "abstract ";
+					$decorations[] = "abstract";
 				}
 				if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
-					echo "final ";
-				}
-			}
-		}
-		echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
+					$decorations[] = "final";
+				}
+			}
+		}
+
+		echo $indent;
+		if ($decorations) {
+			echo implode(' ', $decorations), ' ';
+		}
+		echo $isInterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
 		if ($class['parent']) {
 			echo ' extends ', $class['parent'];
@@ -2608,34 +2517,34 @@
 						echo "\n";
 					}
-					echo $newindent;
 					$isAbstractMethod = false;
+					$decorations = array();
 					if (isset($opa['fn_flags'])) {
-						if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
-							echo "abstract ";
+						if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isInterface) {
+							$decorations[] = "abstract";
 							$isAbstractMethod = true;
 						}
 						if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
-							echo "final ";
+							$decorations[] = "final";
 						}
 						if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
-							echo "static ";
+							$decorations[] = "static";
 						}
 
 						switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
 							case ZEND_ACC_PUBLIC:
-								echo "public ";
+								$decorations[] = "public";
 								break;
 							case ZEND_ACC_PRIVATE:
-								echo "private ";
+								$decorations[] = "private";
 								break;
 							case ZEND_ACC_PROTECTED:
-								echo "protected ";
+								$decorations[] = "protected";
 								break;
 							default:
-								echo "<visibility error> ";
+								$decorations[] = "<visibility error>";
 								break;
 						}
 					}
-					$this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
+					$this->dfunction($func, $newindent, $decorations, $isInterface || $isAbstractMethod);
 					if ($opa['function_name'] == 'Decompiler') {
 						//exit;
Index: /trunk/decompilesample.php
===================================================================
--- /trunk/decompilesample.php	(revision 810)
+++ /trunk/decompilesample.php	(revision 811)
@@ -65,6 +65,6 @@
 	/** doc */
 	protected function protectedMethod(ClassName $a, $b = array(
-		array('array')
-		))
+			array('array')
+			))
 	{
 		$runtimeArray = array('1');
@@ -155,11 +155,15 @@
 
 if ($late) {
-class LateBindingClass
-{}
-
-function lateBindingFunction($arg)
-{
-	echo 'lateFunction';
-}
+	class LateBindingClass
+	{
+		public function __construct()
+		{
+		}
+	}
+
+	function lateBindingFunction($arg)
+	{
+		echo 'lateFunction';
+	}
 }
 
@@ -277,4 +281,5 @@
 if (if_()) {
 	echo 'if';
+
 	if (innerIf_()) {
 		echo 'if innerIf';
@@ -283,4 +288,5 @@
 else if (elseif_()) {
 	echo 'else if';
+
 	if (innerIf_()) {
 		echo 'if innerIf';
@@ -291,4 +297,5 @@
 		echo 'if innerIf';
 	}
+
 	echo 'else';
 }
